]> rtime.felk.cvut.cz Git - frescor/frsh.git/blob - frsh_api/frsh_contract.c
fcb: Work on transaction support continues
[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 {
254         int ret;
255         fres_block_timing_reqs *t;
256
257         if (!contract  || !*contract)
258                 return FRSH_ERR_BAD_ARGUMENT;
259
260         if ((d_equals_t && deadline != FRSH_NULL_DEADLINE) ||
261             (!d_equals_t && (deadline == FRSH_NULL_DEADLINE)))
262                 return FRSH_ERR_BAD_ARGUMENT;
263
264         t = malloc(sizeof(*t));
265         if (!t) return ENOMEM;
266         
267         t->d_equals_t = d_equals_t;
268         if (!d_equals_t) {
269                 if (deadline) {
270                         t->deadline = *deadline;
271                 } else {
272                         free(t);
273                         return FRSH_ERR_BAD_ARGUMENT;
274                 }
275         }
276
277         fres_contract_del_timing_reqs(*contract);
278         ret = fres_contract_add_timing_reqs(*contract, t);
279         if (ret) {
280                 free(t);
281                 return errno;
282         }
283         return 0;
284 }
285
286 int frsh_contract_get_timing_reqs
287   (const frsh_contract_t *contract,
288    bool *d_equals_t,
289    frsh_rel_time_t *deadline)
290 {
291         fres_block_timing_reqs *t;
292
293         if (!contract || !*contract)
294                 return FRSH_ERR_BAD_ARGUMENT;
295
296         t = fres_contract_get_timing_reqs(*contract);   
297
298         if (d_equals_t)
299                 *d_equals_t = t->d_equals_t;
300
301         if (deadline)
302                 *deadline = t->deadline;
303
304         return 0;
305 }
306
307 static
308 int __contract_check_min_expiration(const frsh_contract_t *contract)
309 {
310         fres_block_power_management *p;
311         int ret = 0;
312
313         p = fres_contract_get_power_management(*contract);
314         if (p && !fosa_rel_time_is_null(p->min_expiration)) {
315                 frsh_abs_time_t req_time, exp_time;
316
317                 fosa_clock_get_time(FOSA_CLOCK_REALTIME, &req_time);
318                 req_time = fosa_abs_time_incr(req_time, p->min_expiration);
319
320                 ret = frsh_battery_get_expiration(&exp_time);
321                 if (ret) goto err;
322
323                 if (fosa_abs_time_smaller(exp_time, req_time))
324                         ret = FRSH_ERR_CONTRACT_REJECTED;
325         }
326
327 err:
328         return ret;
329 }
330
331
332 int frsh_contract_negotiate
333   (const frsh_contract_t *contract,
334    frsh_vres_id_t        *vres)
335 {
336         struct forb_env env;
337         int ret;
338         fres_contract_ptr_seq contracts;
339         fres_contract_ptr contracts_buf[1];
340         fres_contract_id_seq *ids;
341         fres_block_resource *r;
342
343         if (!contract || !*contract || !vres) {
344                 ret = FRSH_ERR_BAD_ARGUMENT;
345                 goto err;
346         }
347
348         /* TODO: Battery time check should be moved to
349          * FCB. Implementation of FRSH API is meant only as a thin
350          * wrapper of FRES framework and the FRES framework could
351          * theoretically be used without FRSH API. Moreover, if there
352          * is some logging mechanism in FCB, this contract rejection
353          * will not be logged. */
354         ret = __contract_check_min_expiration(contract);
355         if (ret) goto err;
356
357         /* Activate allocator */
358         r = fres_contract_get_resource(*contract);
359         if (r) {
360                 ret = fra_activate(r->resource_type,
361                                    r->resource_id);
362                 if (ret) goto err;
363         }
364
365         /* Negotiate contract */
366         contracts_buf[0] = *contract;
367         contracts._buffer = contracts_buf;
368         contracts._length = contracts._maximum = 1;
369         ret = fres_contract_broker_negotiate_contracts(frsh_forb_global.fcb,
370                                                        &contracts,
371                                                        &ids, &env);
372         if (forb_exception_occurred(&env)) {
373                 ret = fres_forbex2err(&env);
374                 goto err;
375         }
376
377         if (ret == 0) {
378                 assert(ids->_length == 1);
379                 *vres = fra_get_vres(&ids->_buffer[0]);
380                 assert(*vres != NULL);
381         }
382         if (CORBA_sequence_get_release(ids))
383                 CORBA_free(ids->_buffer);
384         CORBA_free(ids);
385
386 err:    
387         return ret;
388 }
389
390 int frsh_contract_cancel (const frsh_vres_id_t vres)
391 {
392         int ret;
393         struct forb_env env;
394         struct fres_contract *empty_contract;
395         fres_contract_ptr_seq contracts;
396         fres_contract_id_seq *ids;
397         
398         if (!vres) {
399                 ret = FRSH_ERR_BAD_ARGUMENT;
400                 goto err;
401         }
402
403         empty_contract = fres_contract_new();
404         empty_contract->id = vres->id;
405         
406         contracts._buffer = &empty_contract;
407         contracts._length = contracts._maximum = 1;
408         ret = fres_contract_broker_negotiate_contracts(frsh_forb_global.fcb,
409                                                        &contracts,
410                                                        &ids, &env);
411         if (forb_exception_occurred(&env)) {
412                 ret = fres_forbex2err(&env);
413                 goto err;
414         }
415
416         /* The returned ID is the same as of vres */
417         if (CORBA_sequence_get_release(ids))
418                 CORBA_free(ids->_buffer);
419         CORBA_free(ids);
420 err:
421         return ret;
422 }
423
424 int frsh_contract_renegotiate_sync
425   (const frsh_contract_t *new_contract,
426    frsh_vres_id_t vres_id)
427 {
428         struct forb_env env;
429         struct fres_contract *contract;
430         int ret = 0;
431         fres_contract_ptr contracts_buf[1];
432         fres_contract_ptr_seq contracts;
433         fres_contract_id_seq *ids;
434         
435         if (!new_contract || !*new_contract || !vres_id) {
436                 ret = FRSH_ERR_BAD_ARGUMENT;
437                 goto out;
438         }
439
440         ret = __contract_check_min_expiration(new_contract);
441         if (ret) goto out;
442
443         contract = fres_contract_duplicate(*new_contract);
444         if (!contract) {
445                 ret = errno;
446                 goto out;
447         }
448
449         /* Assign the ID, so that FCB recognises that this is
450          * renegotiation */
451         contract->id = vres_id->id;
452
453         /* Renegotiate with FCB contract */
454         contracts_buf[0] = contract;
455         contracts._buffer = contracts_buf;
456         contracts._length = contracts._maximum = 1;
457         ret = fres_contract_broker_negotiate_contracts(frsh_forb_global.fcb,
458                                                        &contracts,
459                                                        &ids, &env);
460         if (forb_exception_occurred(&env)) {
461                 ret = fres_forbex2err(&env);
462                 goto err;
463         }
464
465         if (CORBA_sequence_get_release(ids))
466                 CORBA_free(ids->_buffer);
467         CORBA_free(ids);
468 err:
469         fres_contract_destroy(contract);
470 out:
471         return ret;;
472 }
473
474 int frsh_contract_renegotiate_async
475   (const frsh_contract_t *new_contract,
476    frsh_vres_id_t vres,
477    frsh_signal_t signal_to_notify,
478    frsh_signal_info_t signal_info)
479 {
480         return FRSH_ERR_NOT_IMPLEMENTED;
481 }
482
483 int frsh_group_change_mode_sync
484   (const frsh_contracts_group_t *contracts_to_neg,
485    const frsh_contracts_group_t *contracts_to_reneg,
486    const frsh_vres_group_t      *vres_to_reneg,
487    const frsh_vres_group_t      *vres_to_cancel,
488    frsh_vres_group_t            *new_vres)
489 {
490         return FRSH_ERR_NOT_IMPLEMENTED;
491 }
492
493 int frsh_group_change_mode_async
494   (const frsh_contracts_group_t *contracts_to_neg,
495    const frsh_contracts_group_t *contracts_to_reneg,
496    const frsh_vres_group_t      *vres_to_reneg,
497    const frsh_vres_group_t      *vres_to_cancel,
498    const frsh_signal_t          signal,
499    const frsh_signal_info_t     signal_info,
500    frsh_group_id_t              *group)
501 {
502         return FRSH_ERR_NOT_IMPLEMENTED;
503 }
504