1 /**************************************************************************/
2 /* ---------------------------------------------------------------------- */
3 /* Copyright (C) 2006 - 2008 FRESCOR consortium partners: */
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 */
12 /* Thales Communication S.A. FRANCE */
13 /* Visual Tools S.A. SPAIN */
14 /* Rapita Systems Ltd UK */
17 /* See http://www.frescor.org for a link to partners' websites */
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. */
25 /* This file is part of FRSH (FRescor ScHeduler) */
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. */
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 /**************************************************************************/
49 * @author Michal Sojka <sojkam1@fel.cvut.cz>
50 * @date Tue Nov 11 08:34:34 2008
52 * @brief Generic resource manager implementation.
56 #include <frm_generic.h>
59 #include <ul_logreg.h>
60 #include <fres_sa_scenario.h>
63 UL_LOG_CUST(ulogd_frm_generic);
64 ul_log_domain_t ulogd_frm_generic = {UL_LOGL_DEB, "frm"};
65 UL_LOGREG_SINGLE_DOMAIN_INIT_FUNCTION(frm_generic_logreg_domains, ulogd_frm_generic);
67 #define object_to_frm(o) (struct frm_data*)forb_instance_data(o)
68 #define save_errno(cmd) do { int _e = errno; cmd; errno = _e; } while(0)
70 void fres_sa_scenario_reserve_new(struct fres_sa_scenario *scenario)
72 struct fres_sa_contract *c;
73 fres_sa_scenario_for_each_contract(scenario, c) {
76 fres_contract_destroy(c->reserved);
84 void fres_sa_scenario_rollback(struct fres_sa_scenario *scenario)
86 struct fres_sa_contract *c, *c_next;
88 /* Deleteion safe scenario traverse */
89 for(c=fres_sa_scenario_contract_first(scenario),
90 c_next=c?fres_sa_scenario_contract_next(scenario,c):NULL;
92 c=c_next,c_next=c?fres_sa_scenario_contract_next(scenario,c):NULL) {
94 if (c->committed || c->reserved) {
95 fres_contract_destroy(c->new);
97 c->contract = c->reserved ? c->reserved : c->committed;
99 fres_sa_scenario_del_contract(scenario, c);
100 fres_sa_contract_destroy(c);
107 static CORBA_long reserve_contracts(fres_resource_manager obj,
108 const fres_contract_ptr_seq* contracts,
109 CORBA_Environment *ev)
111 struct frm_data *frm = object_to_frm(obj);
112 struct fres_sa_scenario *scenario = frm->scenario;
113 bool schedulable =false;
115 struct fres_sa_contract *c;
117 ul_logmsg("reserve_contracts\n");
119 for (i=0; i<contracts->_length; i++) {
120 struct fres_contract *cin = contracts->_buffer[i];
122 c = fres_sa_scenario_find_contract(scenario, &cin->id);
124 c = fres_sa_contract_new();
127 fres_sa_scenario_add_contract(scenario, c);
135 fres_contract_id_to_string(id, &c->id, sizeof(id));
136 if (fres_contract_get_num_blocks(cin) == 0) operation = "cancelation";
137 else if (c->committed) operation = "renegotiation";
138 else if (c->reserved) operation = "negotiation (already reserved)";
139 else operation = "negotiation";
140 ul_logdeb(" reserve contract %s %s\n", id, operation);
142 assert(c->new == NULL);
143 c->new = fres_contract_duplicate(cin);
144 c->contract = c->new;
145 if (!c->new) goto err;
148 ret = frm->desc->admission_test(scenario, frm->desc->priv, &schedulable);
150 ul_logmsg("admission_test failed: %d\n", ret);
155 fres_sa_scenario_reserve_new(scenario);
157 fres_sa_scenario_rollback(scenario);
159 return schedulable ? 0 : 1;
161 fres_sa_scenario_rollback(scenario);
165 static int utilization(struct fres_contract *c)
168 b = fres_contract_get_basic(c);
170 uint64_t budget, period;
171 budget = fosa_rel_time_to_nsec(b->budget);
172 period = fosa_rel_time_to_nsec(b->period);
173 return budget*100000/period;
178 static void clear_id(fres_contract_id_t *id)
180 memset(id, 0, sizeof(*id));
183 static void commit_contracts(fres_resource_manager obj,
184 const fres_contract_id_seq* ids,
185 fres_contract_ptr_seq** contracts_with_scheduling_data,
186 CORBA_Environment *ev)
188 struct frm_data *frm = object_to_frm(obj);
190 struct fres_sa_contract *c;
191 fres_contract_ptr_seq *contracts;
192 enum { CANCELATION, DECREASE, INCREASE } pass;
194 ul_logmsg("commit_contracts\n");
196 contracts = forb_malloc(sizeof(*contracts));
198 ev->major = FORB_EX_NO_MEMORY;
202 contracts->_buffer = CORBA_sequence_fres_contract_ptr_allocbuf(num);
203 CORBA_sequence_set_release(contracts, CORBA_TRUE);
204 contracts->_maximum = num;
205 contracts->_length = 0;
207 /* TODO: Add also the changed contracts (e.g. because of
208 * priorities). Question: How to recognize which contracts are
209 * changed because of this commit? */
210 for (pass = CANCELATION; pass <= INCREASE; pass++) {
211 for (i=0; i < num; i++) {
213 const char *operation = NULL;
214 if (fres_contract_id_is_empty(&ids->_buffer[i])) {
215 /* This ID was handled in a previous pass */
218 fres_contract_id_to_string(id, &ids->_buffer[i], sizeof(id));
220 c = fres_sa_scenario_find_contract(frm->scenario, &ids->_buffer[i]);
221 if (c && c->reserved) {
222 if (fres_contract_get_num_blocks(c->reserved) == 0 &&
223 pass == CANCELATION) {
224 /* Cancelation request */
225 operation = "cancelation";
226 contracts->_buffer[contracts->_length++] = c->reserved;
228 fres_sa_scenario_del_contract(frm->scenario, c);
229 fres_sa_contract_destroy(c);
230 clear_id(&ids->_buffer[i]);
232 /* Normal reservation */
234 if ((utilization(c->reserved) < utilization(c->committed) && pass == DECREASE) ||
235 (utilization(c->reserved) >= utilization(c->committed) && pass == INCREASE)) {
236 operation = "renegotiation";
237 fres_contract_destroy(c->committed);
238 c->committed = c->reserved;
240 contracts->_buffer[contracts->_length++] = fres_contract_duplicate(c->committed);
241 clear_id(&ids->_buffer[i]);
243 } else if (pass == INCREASE) {
244 operation = "negotiation";
245 c->committed = c->reserved;
247 contracts->_buffer[contracts->_length++] = fres_contract_duplicate(c->committed);
248 clear_id(&ids->_buffer[i]);
253 contracts->_buffer[contracts->_length++] = NULL;
254 if (!c) ul_logerr("Commit to unknown contract ID\n");
255 else if (!c->reserved) ul_logerr("Commit to not reserved contract\n");
258 ul_logdeb(" commit contract %s %s\n", id, operation);
263 *contracts_with_scheduling_data = contracts;
267 static void cancel_reservations(fres_resource_manager obj,
268 const fres_contract_id_seq* ids,
269 CORBA_Environment *ev)
272 struct frm_data *frm = object_to_frm(obj);
274 ul_logmsg("cancel_reservations\n");
276 for (i=0; i<ids->_length; i++) {
277 struct fres_sa_contract *c;
278 c = fres_sa_scenario_find_contract(frm->scenario, &ids->_buffer[i]);
282 fres_contract_id_to_string(id, &ids->_buffer[i], sizeof(id));
283 ul_logerr("Cannot cancel reservation of unknown contract %s\n",
289 /* Roll-back renegotiation */
290 fres_contract_destroy(c->reserved);
292 c->contract = c->committed;
294 /* Roll-back negotiation */
295 fres_sa_scenario_del_contract(frm->scenario, c);
296 fres_sa_contract_destroy(c);
303 static void get_contracts(fres_resource_manager obj,
304 fres_contract_ptr_seq** contracts_out,
305 CORBA_long* utilization, CORBA_Environment *ev)
307 struct frm_data *frm = object_to_frm(obj);
308 struct fres_sa_contract *c;
309 fres_contract_ptr_seq *contracts;
311 contracts = forb_malloc(sizeof(*contracts));
313 ev->major = FORB_EX_NO_MEMORY;
316 contracts->_buffer = CORBA_sequence_fres_contract_ptr_allocbuf(frm->scenario->num_contracts);
317 CORBA_sequence_set_release(contracts, CORBA_TRUE);
318 contracts->_maximum = frm->scenario->num_contracts;
319 contracts->_length = 0;
321 fres_sa_scenario_for_each_contract(frm->scenario, c) {
323 int i = contracts->_length;
324 contracts->_buffer[i] = fres_contract_duplicate(c->committed);
325 contracts->_length++;
329 *contracts_out = contracts;
330 *utilization = frm->scenario->utilization;
335 static const struct forb_fres_resource_manager_impl frm_impl = {
336 .reserve_contracts = reserve_contracts,
337 .commit_contracts = commit_contracts,
338 .cancel_reservations = cancel_reservations,
339 .get_contracts = get_contracts,
343 * Initializes generic resource manager. The only thing a
344 * caller has to supply is admission test function, which is passed in
345 * @a frm_data->admission_test.
347 * @param orb FORB object used to communicate with other components.
348 * @param[out] frm_data Pointer to frm_data structure
349 * @param executor Executor used for this resource manager.
350 * @param desc Description on the resource manager
352 * @return Resource manager object reference of NULL in case of error.
354 fres_resource_manager frm_register(forb_orb orb, struct frm_data *frm_data,
355 forb_executor_t *executor,
356 const struct fres_res_manager *desc)
358 fres_contract_broker fcb;
359 fres_resource_desc res_desc;
360 fres_resource_manager frm;
364 memset(frm_data, 0, sizeof(*frm_data));
365 frm_data->desc = desc;
366 frm_data->scenario = fres_sa_scenario_new();
367 if (!frm_data->scenario) {
368 save_errno(ul_logerr("fres_sa_scenario_new failed\n"));
372 fcb = forb_resolve_reference(orb, fres_contract_broker_reg_name);
374 save_errno(ul_logerr("Could not find contract broker\n"));
378 frm = forb_fres_resource_manager_new(orb, &frm_impl, frm_data);
380 save_errno(ul_logerr("forb_fres_resource_manager_new error\n"));
381 goto err_release_fcb;
384 ret = forb_executor_register_object(executor, frm);
386 save_errno(ul_logerr("forb_executor_register_object failed\n"));
390 /* Register resource manager */
391 res_desc.manager = frm;
392 res_desc.name = desc->name;
393 ret = fres_contract_broker_register_resource(fcb,
397 if (forb_exception_occurred(&env)) {
398 save_errno(ul_logerr("fres_contract_broker_register_resource: %s\n", forb_strerror(&env)));
400 } else if (ret != 0) {
401 save_errno(ul_logerr("fres_contract_broker_register_resource error: %d\n", ret));
405 forb_object_release(fcb);
408 forb_executor_unregister_object(executor, frm);
410 forb_object_release(frm);
412 forb_object_release(fcb);
418 * Initializes and runs a generic resource manager. The only thing a
419 * caller has to supply is admission test function, which is passed in
420 * @a frm_data->admission_test.
422 * @param orb FORB object used to communicate with other components.
423 * @param desc Description on the resource manager
427 int frm_register_and_run(forb_orb orb, const struct fres_res_manager *desc)
429 fres_resource_manager frm;
430 struct frm_data frm_data;
431 forb_executor_t executor;
434 /* Prepare executor before we register the resource manager
435 * with contract broker */
436 ret = forb_executor_init(&executor);
438 save_errno(ul_logerr("forb_executor_init failed\n"));
442 frm = frm_register(orb, &frm_data, &executor, desc);
445 save_errno(ul_logerr("frm_register failed\n"));
446 goto err_destroy_executor;
449 /* Start request processing */
450 ul_logmsg("Waiting for requests\n");
451 ret = forb_executor_run(&executor);
452 if (ret) goto err_release_frm;
455 forb_object_release(frm);
456 err_destroy_executor:
457 forb_executor_destroy(&executor);