3 * @author Michal Sojka <sojkam1@fel.cvut.cz>
4 * @date Tue Nov 11 08:34:34 2008
6 * @brief Generic resource manager implementation.
10 #include <frm_generic.h>
13 #include <fres_sa_scenario.h>
16 UL_LOG_CUST(ulogd_frm);
17 ul_log_domain_t ulogd_frm = {UL_LOGL_MSG, "frm"};
19 #define object_to_frm(o) (struct frm_data*)forb_instance_data(o)
20 #define save_errno(cmd) do { int _e = errno; cmd; errno = _e; } while(0)
22 void fres_sa_scenario_reserve_new(struct fres_sa_scenario *scenario)
24 struct fres_sa_contract *c;
25 fres_sa_scenario_for_each_contract(scenario, c) {
28 fres_contract_destroy(c->reserved);
36 void fres_sa_scenario_rollback(struct fres_sa_scenario *scenario)
38 struct fres_sa_contract *c, *c_next;
40 /* Deleteion safe scenario traverse */
41 for(c=fres_sa_scenario_contract_first(scenario),
42 c_next=c?fres_sa_scenario_contract_next(scenario,c):NULL;
44 c=c_next,c_next=c?fres_sa_scenario_contract_next(scenario,c):NULL) {
46 if (c->committed || c->reserved) {
47 fres_contract_destroy(c->new);
49 c->contract = c->reserved ? c->reserved : c->committed;
51 fres_sa_scenario_del_contract(scenario, c);
52 fres_sa_contract_destroy(c);
59 static CORBA_long reserve_contracts(fres_resource_manager obj,
60 const fres_contract_ptr_seq* contracts,
61 CORBA_Environment *ev)
63 struct frm_data *frm = object_to_frm(obj);
64 struct fres_sa_scenario *scenario = frm->scenario;
65 bool schedulable =false;
67 struct fres_sa_contract *c;
69 ul_logmsg("reserve_contracts\n");
71 for (i=0; i<contracts->_length; i++) {
72 struct fres_contract *cin = contracts->_buffer[i];
73 c = fres_sa_scenario_find_contract(scenario, &cin->id);
75 c = fres_sa_contract_new();
78 fres_sa_scenario_add_contract(scenario, c);
82 assert(c->new == NULL);
83 c->new = fres_contract_duplicate(cin);
85 if (!c->new) goto err;
88 ret = frm->desc->admission_test(scenario, frm->desc->priv, &schedulable);
90 ul_logerr("admission_test failed: %d\n", ret);
95 fres_sa_scenario_reserve_new(scenario);
97 fres_sa_scenario_rollback(scenario);
99 return schedulable ? 0 : 1;
101 fres_sa_scenario_rollback(scenario);
105 static void commit_contracts(fres_resource_manager obj,
106 const fres_contract_id_seq* ids,
107 fres_contract_ptr_seq** contracts_with_scheduling_data,
108 CORBA_Environment *ev)
110 struct frm_data *frm = object_to_frm(obj);
112 struct fres_sa_contract *c;
113 fres_contract_ptr_seq *contracts;
115 ul_logmsg("commit_contracts\n");
117 contracts = forb_malloc(sizeof(*contracts));
119 ev->major = FORB_EX_NO_MEMORY;
123 contracts->_buffer = CORBA_sequence_fres_contract_ptr_allocbuf(num);
124 CORBA_sequence_set_release(contracts, CORBA_TRUE);
125 contracts->_maximum = contracts->_length = num;
127 /* TODO: Add also the changed contracts (e.g. because of
128 * priorities). Question: How to recognize which contracts are
129 * changed because of this commit? */
130 for (i=0; i < num; i++) {
131 c = fres_sa_scenario_find_contract(frm->scenario, &ids->_buffer[i]);
132 if (c && c->reserved) {
133 if (c->committed) fres_contract_destroy(c->committed);
134 c->committed = c->reserved;
136 contracts->_buffer[i] = fres_contract_duplicate(c->committed);
138 contracts->_buffer[i] = NULL;
139 if (!c) ul_logerr("Commit to unknown contract ID\n");
140 else if (!c->reserved) ul_logerr("Commit to not reserved contract\n");
144 *contracts_with_scheduling_data = contracts;
148 static void cancel_contracts(fres_resource_manager obj,
149 const fres_contract_id_seq* ids,
150 CORBA_Environment *ev)
153 struct frm_data *frm = object_to_frm(obj);
155 ul_logmsg("cancel_contracts\n");
157 for (i=0; i<ids->_length; i++) {
158 struct fres_sa_contract *c;
159 c = fres_sa_scenario_find_contract(frm->scenario, &ids->_buffer[i]);
162 fres_sa_scenario_del_contract(frm->scenario, c);
163 fres_sa_contract_destroy(c);
168 static void get_contracts(fres_resource_manager obj,
169 fres_contract_ptr_seq** contracts_out,
170 CORBA_long* utilization, CORBA_Environment *ev)
172 struct frm_data *frm = object_to_frm(obj);
173 struct fres_sa_contract *c;
174 fres_contract_ptr_seq *contracts;
176 contracts = forb_malloc(sizeof(*contracts));
178 ev->major = FORB_EX_NO_MEMORY;
181 contracts->_buffer = CORBA_sequence_fres_contract_ptr_allocbuf(frm->scenario->num_contracts);
182 CORBA_sequence_set_release(contracts, CORBA_TRUE);
183 contracts->_maximum = frm->scenario->num_contracts;
184 contracts->_length = 0;
186 fres_sa_scenario_for_each_contract(frm->scenario, c) {
188 int i = contracts->_length;
189 contracts->_buffer[i] = fres_contract_duplicate(c->committed);
190 contracts->_length++;
194 *contracts_out = contracts;
195 *utilization = frm->scenario->utilization;
200 static const struct forb_fres_resource_manager_impl frm_impl = {
201 .reserve_contracts = reserve_contracts,
202 .commit_contracts = commit_contracts,
203 .cancel_contracts = cancel_contracts,
204 .get_contracts = get_contracts,
208 * Initializes generic resource manager. The only thing a
209 * caller has to supply is admission test function, which is passed in
210 * @a frm_data->admission_test.
212 * @param orb FORB object used to communicate with other components.
213 * @param[out] frm_data Pointer to frm_data structure
214 * @param executor Executor used for this resource manager.
215 * @param desc Description on the resource manager
217 * @return Resource manager object reference of NULL in case of error.
219 fres_resource_manager frm_register(forb_orb orb, struct frm_data *frm_data,
220 forb_executor_t *executor,
221 const struct fres_res_manager *desc)
223 fres_contract_broker fcb;
224 fres_resource_desc res_desc;
225 fres_resource_manager frm;
229 memset(frm_data, 0, sizeof(*frm_data));
230 frm_data->desc = desc;
231 frm_data->scenario = fres_sa_scenario_new();
232 if (!frm_data->scenario) {
233 save_errno(ul_logerr("fres_sa_scenario_new failed\n"));
237 fcb = forb_resolve_reference(orb, fres_contract_broker_reg_name);
239 save_errno(ul_logerr("Could not find contract broker\n"));
243 frm = forb_fres_resource_manager_new(orb, &frm_impl, frm_data);
245 save_errno(ul_logerr("forb_fres_resource_manager_new error\n"));
246 goto err_release_fcb;
249 ret = forb_executor_register_object(executor, frm);
251 save_errno(ul_logerr("forb_executor_register_object failed\n"));
255 /* Register resource manager */
256 res_desc.manager = frm;
257 ret = fres_contract_broker_register_resource(fcb,
261 if (forb_exception_occurred(&env) || ret != 0) {
262 save_errno(ul_logerr("fres_contract_broker_register_resource exception\n"));
266 forb_object_release(fcb);
269 forb_executor_unregister_object(executor, frm);
271 forb_object_release(frm);
273 forb_object_release(fcb);
279 * Initializes and runs a generic resource manager. The only thing a
280 * caller has to supply is admission test function, which is passed in
281 * @a frm_data->admission_test.
283 * @param orb FORB object used to communicate with other components.
284 * @param desc Description on the resource manager
288 int frm_register_and_run(forb_orb orb, const struct fres_res_manager *desc)
290 fres_resource_manager frm;
291 struct frm_data frm_data;
292 forb_executor_t executor;
295 /* Prepare executor before we register the resource manager
296 * with contract broker */
297 ret = forb_executor_init(&executor);
299 save_errno(ul_logerr("forb_executor_init failed\n"));
303 frm = frm_register(orb, &frm_data, &executor, desc);
306 save_errno(ul_logerr("frm_register failed\n"));
307 goto err_destroy_executor;
310 /* Start request processing */
311 ul_logmsg("Waiting for requests\n");
312 ret = forb_executor_run(&executor);
313 if (ret) goto err_release_frm;
316 forb_object_release(frm);
317 err_destroy_executor:
318 forb_executor_destroy(&executor);