]> rtime.felk.cvut.cz Git - frescor/frsh.git/blob - fres/resmng/frm_generic.c
Added license headers and authorship info
[frescor/frsh.git] / fres / resmng / frm_generic.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   frm_generic.c
49  * @author Michal Sojka <sojkam1@fel.cvut.cz>
50  * @date   Tue Nov 11 08:34:34 2008
51  * 
52  * @brief  Generic resource manager implementation.
53  * 
54  * 
55  */
56 #include <frm_generic.h>
57 #include <forb.h>
58 #include <ul_log.h>
59 #include <fres_sa_scenario.h>
60 #include <fcb.h>
61
62 UL_LOG_CUST(ulogd_frm);
63 ul_log_domain_t ulogd_frm = {UL_LOGL_MSG, "frm"};
64
65 #define object_to_frm(o) (struct frm_data*)forb_instance_data(o)
66 #define save_errno(cmd) do { int _e = errno; cmd; errno = _e; } while(0)
67
68 void fres_sa_scenario_reserve_new(struct fres_sa_scenario *scenario)
69 {
70         struct fres_sa_contract *c;
71         fres_sa_scenario_for_each_contract(scenario, c) {
72                 if (c->new) {
73                         if (c->reserved) {
74                                 fres_contract_destroy(c->reserved);
75                         }
76                         c->reserved = c->new;
77                         c->new = NULL;
78                 }
79         }
80 }
81
82 void fres_sa_scenario_rollback(struct fres_sa_scenario *scenario)
83 {
84         struct fres_sa_contract *c, *c_next;
85
86         /* Deleteion safe scenario traverse */
87         for(c=fres_sa_scenario_contract_first(scenario),
88                     c_next=c?fres_sa_scenario_contract_next(scenario,c):NULL;
89             c;
90             c=c_next,c_next=c?fres_sa_scenario_contract_next(scenario,c):NULL) {
91                 if (c->new) {
92                         if (c->committed || c->reserved) {
93                                         fres_contract_destroy(c->new);
94                                         c->new = NULL;
95                                         c->contract = c->reserved ? c->reserved : c->committed;
96                         } else {
97                                 fres_sa_scenario_del_contract(scenario, c);
98                                 fres_sa_contract_destroy(c);
99                         }
100                 }
101         }
102 }
103
104
105 static CORBA_long reserve_contracts(fres_resource_manager obj,
106                                     const fres_contract_ptr_seq* contracts,
107                                     CORBA_Environment *ev)
108 {
109         struct frm_data *frm = object_to_frm(obj);
110         struct fres_sa_scenario *scenario = frm->scenario;
111         bool schedulable =false;
112         int i, ret;
113         struct fres_sa_contract *c;
114
115         ul_logmsg("reserve_contracts\n");
116         
117         for (i=0; i<contracts->_length; i++) {
118                 struct fres_contract *cin = contracts->_buffer[i];
119                 c = fres_sa_scenario_find_contract(scenario, &cin->id);
120                 if (!c) {
121                         c = fres_sa_contract_new();
122                         if (c) {
123                                 c->id = cin->id;
124                                 fres_sa_scenario_add_contract(scenario, c);
125                         }
126                 }
127                 if (!c) goto err;
128                 assert(c->new == NULL);
129                 c->new = fres_contract_duplicate(cin);
130                 c->contract = c->new;
131                 if (!c->new) goto err;
132         }
133
134         ret = frm->desc->admission_test(scenario, frm->desc->priv, &schedulable);
135         if (ret) {
136                 ul_logerr("admission_test failed: %d\n", ret);
137                 goto err;
138         }
139
140         if (schedulable) {
141                 fres_sa_scenario_reserve_new(scenario);
142         } else {
143                 fres_sa_scenario_rollback(scenario);
144         }
145         return schedulable ? 0 : 1;
146 err:
147         fres_sa_scenario_rollback(scenario);
148         return -1;
149 }
150
151 static void commit_contracts(fres_resource_manager obj,
152                       const fres_contract_id_seq* ids,
153                       fres_contract_ptr_seq** contracts_with_scheduling_data,
154                       CORBA_Environment *ev)
155 {
156         struct frm_data *frm = object_to_frm(obj);
157         int i, num;
158         struct fres_sa_contract *c;
159         fres_contract_ptr_seq *contracts;
160
161         ul_logmsg("commit_contracts\n");
162
163         contracts = forb_malloc(sizeof(*contracts));
164         if (!contracts) {
165                 ev->major = FORB_EX_NO_MEMORY;
166                 goto err;
167         }
168         num = ids->_length;
169         contracts->_buffer = CORBA_sequence_fres_contract_ptr_allocbuf(num);
170         CORBA_sequence_set_release(contracts, CORBA_TRUE);
171         contracts->_maximum = contracts->_length = num;
172
173         /* TODO: Add also the changed contracts (e.g. because of
174          * priorities). Question: How to recognize which contracts are
175          * changed because of this commit? */
176         for (i=0; i < num; i++) {
177                 c = fres_sa_scenario_find_contract(frm->scenario, &ids->_buffer[i]);
178                 if (c && c->reserved) {
179                         if (c->committed) fres_contract_destroy(c->committed);
180                         c->committed = c->reserved;
181                         c->reserved = NULL;
182                         contracts->_buffer[i] = fres_contract_duplicate(c->committed);
183                 } else {
184                         contracts->_buffer[i] = NULL;
185                         if (!c) ul_logerr("Commit to unknown contract ID\n");
186                         else if (!c->reserved) ul_logerr("Commit to not reserved contract\n");
187                 }
188         }
189         
190         *contracts_with_scheduling_data = contracts;
191 err:;
192 }
193
194 static void cancel_contracts(fres_resource_manager obj,
195                       const fres_contract_id_seq* ids,
196                       CORBA_Environment *ev)
197 {
198         int i;
199         struct frm_data *frm = object_to_frm(obj);
200
201         ul_logmsg("cancel_contracts\n");
202
203         for (i=0; i<ids->_length; i++) {
204                 struct fres_sa_contract *c;
205                 c = fres_sa_scenario_find_contract(frm->scenario, &ids->_buffer[i]);
206
207                 if (c) {
208                         fres_sa_scenario_del_contract(frm->scenario, c);
209                         fres_sa_contract_destroy(c);
210                 }
211         }
212 }
213
214 static void get_contracts(fres_resource_manager obj,
215                           fres_contract_ptr_seq** contracts_out,
216                           CORBA_long* utilization, CORBA_Environment *ev)
217 {
218         struct frm_data *frm = object_to_frm(obj);
219         struct fres_sa_contract *c;
220         fres_contract_ptr_seq *contracts;
221
222         contracts = forb_malloc(sizeof(*contracts));
223         if (!contracts) {
224                 ev->major = FORB_EX_NO_MEMORY;
225                 goto err;
226         }
227         contracts->_buffer = CORBA_sequence_fres_contract_ptr_allocbuf(frm->scenario->num_contracts);
228         CORBA_sequence_set_release(contracts, CORBA_TRUE);
229         contracts->_maximum = frm->scenario->num_contracts;
230         contracts->_length = 0;
231
232         fres_sa_scenario_for_each_contract(frm->scenario, c) {
233                 if (c->committed) {
234                         int i = contracts->_length;
235                         contracts->_buffer[i] = fres_contract_duplicate(c->committed);
236                         contracts->_length++;
237                 }
238                                         
239         }
240         *contracts_out = contracts;
241         *utilization = frm->scenario->utilization;
242 err:;
243 }
244
245
246 static const struct forb_fres_resource_manager_impl frm_impl = {
247         .reserve_contracts = reserve_contracts,
248         .commit_contracts  = commit_contracts,
249         .cancel_contracts  = cancel_contracts,
250         .get_contracts  = get_contracts,
251 };
252
253 /** 
254  * Initializes generic resource manager. The only thing a
255  * caller has to supply is admission test function, which is passed in
256  * @a frm_data->admission_test.
257  * 
258  * @param orb FORB object used to communicate with other components.
259  * @param[out] frm_data Pointer to frm_data structure
260  * @param executor Executor used for this resource manager.
261  * @param desc Description on the resource manager
262  * 
263  * @return Resource manager object reference of NULL in case of error.
264  */
265 fres_resource_manager frm_register(forb_orb orb, struct frm_data *frm_data,
266                                    forb_executor_t *executor,
267                                    const struct fres_res_manager *desc)
268 {
269         fres_contract_broker fcb;
270         fres_resource_desc res_desc;
271         fres_resource_manager frm;
272         struct forb_env env;
273         int ret;
274
275         memset(frm_data, 0, sizeof(*frm_data));
276         frm_data->desc = desc;
277         frm_data->scenario = fres_sa_scenario_new();
278         if (!frm_data->scenario) {
279                 save_errno(ul_logerr("fres_sa_scenario_new failed\n"));
280                 goto err;
281         }
282
283         fcb = forb_resolve_reference(orb, fres_contract_broker_reg_name);
284         if (!fcb) {
285                 save_errno(ul_logerr("Could not find contract broker\n"));
286                 goto err;
287         }
288
289         frm = forb_fres_resource_manager_new(orb, &frm_impl, frm_data);
290         if (!frm) {
291                 save_errno(ul_logerr("forb_fres_resource_manager_new error\n"));
292                 goto err_release_fcb;
293         }
294
295         ret = forb_executor_register_object(executor, frm);
296         if (ret) {
297                 save_errno(ul_logerr("forb_executor_register_object failed\n"));
298                 goto err_executor;
299         }
300
301         /* Register resource manager */
302         res_desc.manager = frm;
303         ret = fres_contract_broker_register_resource(fcb,
304                                                      desc->res_type,
305                                                      desc->res_id,
306                                                      &res_desc, &env);
307         if (forb_exception_occurred(&env) || ret != 0) {
308                 save_errno(ul_logerr("fres_contract_broker_register_resource exception\n"));
309                 goto err_register;
310         }
311
312         forb_object_release(fcb);
313         return frm;
314 err_register:   
315         forb_executor_unregister_object(executor, frm);
316 err_executor:
317         forb_object_release(frm);
318 err_release_fcb:        
319         forb_object_release(fcb);
320 err:
321         return NULL;
322 }
323
324 /** 
325  * Initializes and runs a generic resource manager. The only thing a
326  * caller has to supply is admission test function, which is passed in
327  * @a frm_data->admission_test.
328  * 
329  * @param orb FORB object used to communicate with other components.
330  * @param desc Description on the resource manager
331  * 
332  * @return 
333  */
334 int frm_register_and_run(forb_orb orb, const struct fres_res_manager *desc)
335 {
336         fres_resource_manager frm;
337         struct frm_data frm_data;
338         forb_executor_t executor;
339         int ret = -1;
340
341         /* Prepare executor before we register the resource manager
342          * with contract broker */
343         ret = forb_executor_init(&executor);
344         if (ret) {
345                 save_errno(ul_logerr("forb_executor_init failed\n"));
346                 goto err;
347         }
348
349         frm = frm_register(orb, &frm_data, &executor, desc);
350         if (!frm) {
351                 ret = -1;
352                 save_errno(ul_logerr("frm_register failed\n"));
353                 goto err_destroy_executor;
354         }
355                 
356         /* Start request processing */
357         ul_logmsg("Waiting for requests\n");
358         ret = forb_executor_run(&executor);
359         if (ret) goto err_release_frm;
360
361 err_release_frm:        
362         forb_object_release(frm);
363 err_destroy_executor:
364         forb_executor_destroy(&executor);
365 err:
366         return ret;
367 }