]> rtime.felk.cvut.cz Git - frescor/frsh.git/blob - frsh_api/frsh_contract.c
607fa38ebf50101d0768576e17c3716659c264ed
[frescor/frsh.git] / frsh_api / frsh_contract.c
1 /**************************************************************************/
2 /* ---------------------------------------------------------------------- */
3 /* Copyright (C) 2006 - 2008 FRESCOR consortium partners:                 */
4 /*                                                                        */
5 /*   Universidad de Cantabria,              SPAIN                         */
6 /*   University of York,                    UK                            */
7 /*   Scuola Superiore Sant'Anna,            ITALY                         */
8 /*   Kaiserslautern University,             GERMANY                       */
9 /*   Univ. Politécnica  Valencia,           SPAIN                        */
10 /*   Czech Technical University in Prague,  CZECH REPUBLIC                */
11 /*   ENEA                                   SWEDEN                        */
12 /*   Thales Communication S.A.              FRANCE                        */
13 /*   Visual Tools S.A.                      SPAIN                         */
14 /*   Rapita Systems Ltd                     UK                            */
15 /*   Evidence                               ITALY                         */
16 /*                                                                        */
17 /*   See http://www.frescor.org for a link to partners' websites          */
18 /*                                                                        */
19 /*          FRESCOR project (FP6/2005/IST/5-034026) is funded             */
20 /*       in part by the European Union Sixth Framework Programme          */
21 /*       The European Union is not liable of any use that may be          */
22 /*       made of this code.                                               */
23 /*                                                                        */
24 /*                                                                        */
25 /*  This file is part of FRSH (FRescor ScHeduler)                         */
26 /*                                                                        */
27 /* FRSH is free software; you can redistribute it and/or modify it        */
28 /* under terms of the GNU General Public License as published by the      */
29 /* Free Software Foundation; either version 2, or (at your option) any    */
30 /* later version.  FRSH is distributed in the hope that it will be        */
31 /* useful, but WITHOUT ANY WARRANTY; without even the implied warranty    */
32 /* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU    */
33 /* General Public License for more details. You should have received a    */
34 /* copy of the GNU General Public License along with FRSH; see file       */
35 /* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave,  */
36 /* Cambridge, MA 02139, USA.                                              */
37 /*                                                                        */
38 /* As a special exception, including FRSH header files in a file,         */
39 /* instantiating FRSH generics or templates, or linking other files       */
40 /* with FRSH objects to produce an executable application, does not       */
41 /* by itself cause the resulting executable application to be covered     */
42 /* by the GNU General Public License. This exception does not             */
43 /* however invalidate any other reasons why the executable file might be  */
44 /* covered by the GNU Public License.                                     */
45 /**************************************************************************/
46
47 /**
48  * @file   frsh_contract.c
49  * @author Michal Sojka <sojkam1@fel.cvut.cz>
50  *         Dario Faggioli <faggioli@gandalf.sssup.it>
51  * 
52  * @brief  Implementation of FRSH contract API on top of FRES contracts.
53  * 
54  * 
55  */
56 #include <fres_contract.h>
57 #include <fres_contract_idl.h>
58 #include <frsh_core.h>
59 #include <frsh_error.h>
60 #include <fres_blocks.h>
61 #include <string.h>
62 #include <fcb.h>
63 #include "frsh_forb.h"
64 #include <fra_generic.h>
65 #include <frsh_energy_management.h>
66
67 /**********************************/
68 /* -----===== FRSH API =====----- */
69 /**********************************/
70
71 int
72 frsh_contract_init(frsh_contract_t *contract)
73 {
74         frsh_rel_time_t zero_msec = fosa_msec_to_rel_time(0);
75         if (!contract) return FRSH_ERR_BAD_ARGUMENT;
76         
77         *contract = fres_contract_new();
78         if (!(*contract)) goto err;
79
80         /* Set default parameters */
81         frsh_contract_set_resource_and_label(contract,
82                                              FRSH_RT_PROCESSOR,
83                                              0,
84                                              NULL);
85         frsh_contract_set_basic_params(contract,
86                                        &zero_msec,
87                                        &zero_msec,
88                                        FRSH_WT_INDETERMINATE,
89                                        FRSH_CT_REGULAR);
90         return 0;
91 err:
92         return errno;
93 }
94
95 void
96 frsh_contract_destroy(frsh_contract_t *contract)
97 {
98         if (contract)
99                 fres_contract_destroy(*contract);
100 }
101
102 int frsh_contract_set_basic_params
103   (frsh_contract_t *contract,
104    const frsh_rel_time_t      *budget_min,
105    const frsh_rel_time_t      *period_max,
106    const frsh_workload_t      workload,
107    const frsh_contract_type_t contract_type)
108 {
109         fres_block_basic *b;
110         int ret;
111         if (!contract ||
112             !*contract ||
113             !budget_min ||
114             !period_max) {
115                 return FRSH_ERR_BAD_ARGUMENT;
116         }
117
118         if ((fosa_rel_time_is_null(*period_max) &&
119              !fosa_rel_time_is_null(*budget_min)) ||
120             (!fosa_rel_time_is_null(*period_max) &&
121              fosa_rel_time_is_null(*budget_min)) ||
122             fosa_rel_time_smaller(*period_max, *budget_min))
123                 return FRSH_ERR_BAD_ARGUMENT;
124
125         if (workload != FRSH_WT_BOUNDED &&
126             workload != FRSH_WT_INDETERMINATE)
127                 return FRSH_ERR_BAD_ARGUMENT;
128
129         if (contract_type != FRSH_CT_REGULAR &&
130             contract_type != FRSH_CT_BACKGROUND &&
131             contract_type != FRSH_CT_DUMMY)
132                 return FRSH_ERR_BAD_ARGUMENT;
133
134         b = malloc(sizeof(*b));
135         if (!b) return ENOMEM; 
136
137         b->budget = *budget_min;
138         b->period = *period_max;
139         b->workload = workload;
140         b->contract_type = contract_type;
141
142         fres_contract_del_basic(*contract);
143         ret = fres_contract_add_basic(*contract, b);
144
145         if (ret) {
146                 free(b);
147                 return errno;
148         }
149
150         return 0;
151 }
152
153 int frsh_contract_get_basic_params
154   (const frsh_contract_t *contract,
155    frsh_rel_time_t *budget_min,
156    frsh_rel_time_t *period_max,
157    frsh_workload_t *workload,
158    frsh_contract_type_t *contract_type)
159 {
160         fres_block_basic *b;
161
162         if (!contract || !*contract)
163                 return FRSH_ERR_BAD_ARGUMENT;
164
165         b = fres_contract_get_basic(*contract);
166
167         if (workload)
168                 *workload = b->workload;
169         if (budget_min)
170                 *budget_min = b->budget;
171         if (period_max)
172                 *period_max = b->period;
173         if (contract_type)
174                 *contract_type = b->contract_type;
175
176         return 0;
177 }
178
179 int frsh_contract_set_resource_and_label
180   (frsh_contract_t *contract,
181    const frsh_resource_type_t resource_type,
182    const frsh_resource_id_t resource_id,
183    const frsh_contract_label_t contract_label)
184 {
185         fres_block_label *label;
186         fres_block_resource *r;
187         int ret;
188         
189         if (!contract || !*contract) return FRSH_ERR_BAD_ARGUMENT;
190
191         r = malloc(sizeof(*r));
192         if (!r) return ENOMEM;
193         
194         r->resource_type = resource_type;
195         r->resource_id = resource_id;
196         fres_contract_del_resource(*contract);
197         ret = fres_contract_add_resource(*contract, r);
198
199         if (ret != 0) {
200                 free(r);
201                 return errno;
202         }
203         
204
205         if (contract_label) {
206                 label = malloc(sizeof(*label));
207                 if (!label) return ENOMEM;
208                 strncpy(label->label, contract_label, sizeof(label->label));
209                 label->label[sizeof(label->label)-1] = '\0';
210                 fres_contract_del_label(*contract);
211                 ret = fres_contract_add_label(*contract, label);
212                 if (ret) {
213                         free(label);
214                         return errno;
215                 }
216         }
217         return 0;
218 }
219
220 int frsh_contract_get_resource_and_label
221   (const frsh_contract_t *contract,
222    frsh_resource_type_t *resource_type,
223    frsh_resource_id_t *resource_id,
224    frsh_contract_label_t contract_label)
225 {
226         fres_block_resource *r;
227         fres_block_label *label;
228
229         if (!contract || !*contract)
230                 return FRSH_ERR_BAD_ARGUMENT;
231
232         if (resource_type || resource_id) {
233                 r = fres_contract_get_resource(*contract);
234                 if (resource_type)
235                         *resource_type = r->resource_type;
236                 if (resource_id)
237                         *resource_id = r->resource_id;
238         }
239
240         if (contract_label) {
241                 label = fres_contract_get_label(*contract);
242                 strncpy(contract_label, label->label, sizeof(label->label));
243                 contract_label[sizeof(label->label)-1] = '\0';
244         }
245
246         return 0;
247 }
248
249 int frsh_contract_set_timing_reqs
250   (frsh_contract_t *contract,
251    const bool                   d_equals_t,
252    const frsh_rel_time_t        *deadline,
253    const frsh_signal_t          budget_overrun_signal,
254    const frsh_signal_info_t     budget_overrun_siginfo,
255    const frsh_signal_t          deadline_miss_signal,
256    const frsh_signal_info_t     deadline_miss_siginfo)
257 {
258         int ret;
259         fres_block_basic *b;
260         fres_block_timing_reqs *t;
261
262         if (!contract  || !*contract)
263                 return FRSH_ERR_BAD_ARGUMENT;
264
265         /* deadline and period must be coherent between each other */
266         b = fres_contract_get_basic(*contract);
267
268         if ((d_equals_t && deadline != FRSH_NULL_DEADLINE) ||
269             (!d_equals_t && (deadline == FRSH_NULL_DEADLINE)))
270                 return FRSH_ERR_BAD_ARGUMENT;
271
272         /* signal delivery can only be requested for BUONDED workloads */
273         if (b->workload == FRSH_WT_INDETERMINATE &&
274             (deadline_miss_signal != FRSH_NULL_SIGNAL ||
275              budget_overrun_signal != FRSH_NULL_SIGNAL))
276                 return FRSH_ERR_BAD_ARGUMENT;
277
278         t = malloc(sizeof(*t));
279         if (!t) return ENOMEM;
280         
281         t->d_equals_t = d_equals_t;
282         if (!d_equals_t) {
283                 if (deadline) {
284                         t->deadline = *deadline;
285                 } else {
286                         free(t);
287                         return FRSH_ERR_BAD_ARGUMENT;
288                 }
289         }
290
291         /* Signals are currently ignored by this implementation as
292          * they are better implemented in frsh_thread_bind() */
293         /*t->budget_overrun_signal = budget_overrun_signal;
294         t->budget_overrun_siginfo = budget_overrun_siginfo;
295         t->deadline_miss_signal = deadline_miss_signal;
296         t->deadline_miss_siginfo = deadline_miss_siginfo;*/
297         fres_contract_del_timing_reqs(*contract);
298         ret = fres_contract_add_timing_reqs(*contract, t);
299         if (ret) {
300                 free(t);
301                 return errno;
302         }
303         return 0;
304 }
305
306 int frsh_contract_get_timing_reqs
307   (const frsh_contract_t *contract,
308    bool *d_equals_t,
309    frsh_rel_time_t *deadline,
310    frsh_signal_t *budget_overrun_signal,
311    frsh_signal_info_t *budget_overrun_siginfo,
312    frsh_signal_t *deadline_miss_signal,
313    frsh_signal_info_t *deadline_miss_siginfo)
314 {
315         fres_block_timing_reqs *t;
316
317         if (!contract || !*contract)
318                 return FRSH_ERR_BAD_ARGUMENT;
319
320         t = fres_contract_get_timing_reqs(*contract);   
321
322         if (d_equals_t)
323                 *d_equals_t = t->d_equals_t;
324
325         if (deadline)
326                 *deadline = t->deadline;
327
328         return 0;
329 }
330
331 static
332 int __contract_check_min_expiration(const frsh_contract_t *contract)
333 {
334         fres_block_power_management *p;
335         int ret = 0;
336
337         p = fres_contract_get_power_management(*contract);
338         if (p && !fosa_rel_time_is_null(p->min_expiration)) {
339                 frsh_abs_time_t req_time, exp_time;
340
341                 fosa_clock_get_time(FOSA_CLOCK_REALTIME, &req_time);
342                 req_time = fosa_abs_time_incr(req_time, p->min_expiration);
343
344                 ret = frsh_battery_get_expiration(&exp_time);
345                 if (ret) goto err;
346
347                 if (fosa_abs_time_smaller(exp_time, req_time))
348                         ret = FRSH_ERR_CONTRACT_REJECTED;
349         }
350
351 err:
352         return ret;
353 }
354
355
356 int frsh_contract_negotiate
357   (const frsh_contract_t *contract,
358    frsh_vres_id_t        *vres)
359 {
360         struct forb_env env;
361         int ret;
362         fres_contract_ptr_seq contracts;
363         fres_contract_ptr contracts_buf[1];
364         fres_contract_id_seq *ids;
365         fres_block_resource *r;
366
367         if (!contract || !*contract || !vres) {
368                 ret = FRSH_ERR_BAD_ARGUMENT;
369                 goto err;
370         }
371
372         /* TODO: Battery time check should be moved to
373          * FCB. Implementation of FRSH API is meant only as a thin
374          * wrapper of FRES framework and the FRES framework could
375          * theoretically be used without FRSH API. Moreover, if there
376          * is some logging mechanism in FCB, this contract rejection
377          * will not be logged. */
378         ret = __contract_check_min_expiration(contract);
379         if (ret) goto err;
380
381         /* Activate allocator */
382         r = fres_contract_get_resource(*contract);
383         if (r) {
384                 ret = fra_activate(r->resource_type,
385                                    r->resource_id);
386                 if (ret) goto err;
387         }
388
389         /* Negotiate contract */
390         contracts_buf[0] = *contract;
391         contracts._buffer = contracts_buf;
392         contracts._length = contracts._maximum = 1;
393         ret = fres_contract_broker_negotiate_contracts(frsh_forb_global.fcb,
394                                                        &contracts,
395                                                        &ids, &env);
396         if (forb_exception_occurred(&env)) {
397                 ret = fres_forbex2err(&env);
398                 goto err;
399         }
400
401         if (ret == 0) {
402                 assert(ids->_length == 1);
403                 *vres = fra_get_vres(&ids->_buffer[0]);
404         }
405         if (CORBA_sequence_get_release(ids))
406                 CORBA_free(ids->_buffer);
407         CORBA_free(ids);
408
409 err:    
410         return ret;
411 }
412
413 int frsh_contract_cancel (const frsh_vres_id_t vres)
414 {
415         int ret;
416         struct forb_env env;
417         struct fres_contract *empty_contract;
418         fres_contract_ptr_seq contracts;
419         fres_contract_id_seq *ids;
420         
421         if (!vres) {
422                 ret = FRSH_ERR_BAD_ARGUMENT;
423                 goto err;
424         }
425
426         empty_contract = fres_contract_new();
427         empty_contract->id = vres->id;
428         
429         contracts._buffer = &empty_contract;
430         contracts._length = contracts._maximum = 1;
431         ret = fres_contract_broker_negotiate_contracts(frsh_forb_global.fcb,
432                                                        &contracts,
433                                                        &ids, &env);
434         if (forb_exception_occurred(&env)) {
435                 ret = fres_forbex2err(&env);
436                 goto err;
437         }
438
439         /* The returned ID is the same as of vres */
440         if (CORBA_sequence_get_release(ids))
441                 CORBA_free(ids->_buffer);
442         CORBA_free(ids);
443 err:
444         return ret;
445 }
446
447 int frsh_contract_renegotiate_sync
448   (const frsh_contract_t *new_contract,
449    frsh_vres_id_t vres_id)
450 {
451         struct forb_env env;
452         struct fres_contract *contract;
453         int ret = 0;
454         fres_contract_ptr contracts_buf[1];
455         fres_contract_ptr_seq contracts;
456         fres_contract_id_seq *ids;
457         
458         if (!new_contract || !*new_contract || !vres_id) {
459                 ret = FRSH_ERR_BAD_ARGUMENT;
460                 goto out;
461         }
462
463         ret = __contract_check_min_expiration(new_contract);
464         if (ret) goto out;
465
466         contract = fres_contract_duplicate(*new_contract);
467         if (!contract) {
468                 ret = errno;
469                 goto out;
470         }
471
472         /* Assign the ID, so that FCB recognises that this is
473          * renegotiation */
474         contract->id = vres_id->id;
475
476         /* Renegotiate with FCB contract */
477         contracts_buf[0] = contract;
478         contracts._buffer = contracts_buf;
479         contracts._length = contracts._maximum = 1;
480         ret = fres_contract_broker_negotiate_contracts(frsh_forb_global.fcb,
481                                                        &contracts,
482                                                        &ids, &env);
483         if (forb_exception_occurred(&env)) {
484                 ret = fres_forbex2err(&env);
485                 goto err;
486         }
487
488         if (CORBA_sequence_get_release(ids))
489                 CORBA_free(ids->_buffer);
490         CORBA_free(ids);
491 err:
492         fres_contract_destroy(contract);
493 out:
494         return ret;;
495 }
496
497 int frsh_contract_renegotiate_async
498   (const frsh_contract_t *new_contract,
499    frsh_vres_id_t vres,
500    frsh_signal_t signal_to_notify,
501    frsh_signal_info_t signal_info)
502 {
503         return FRSH_ERR_NOT_IMPLEMENTED;
504 }
505
506 int frsh_group_change_mode_sync
507   (const frsh_contracts_group_t *contracts_to_neg,
508    const frsh_contracts_group_t *contracts_to_reneg,
509    const frsh_vres_group_t      *vres_to_reneg,
510    const frsh_vres_group_t      *vres_to_cancel,
511    frsh_vres_group_t            *new_vres)
512 {
513         return FRSH_ERR_NOT_IMPLEMENTED;
514 }
515
516 int frsh_group_change_mode_async
517   (const frsh_contracts_group_t *contracts_to_neg,
518    const frsh_contracts_group_t *contracts_to_reneg,
519    const frsh_vres_group_t      *vres_to_reneg,
520    const frsh_vres_group_t      *vres_to_cancel,
521    const frsh_signal_t          signal,
522    const frsh_signal_info_t     signal_info,
523    frsh_group_id_t              *group)
524 {
525         return FRSH_ERR_NOT_IMPLEMENTED;
526 }
527