From 9483d1c9372f42d39af18b6615ea13052a5702ed Mon Sep 17 00:00:00 2001 From: Michal Sojka Date: Thu, 23 Apr 2009 13:23:20 +0200 Subject: [PATCH] Implemented support for contract renegotiation This patch changes significantly the interface between FCB and resource managers and allocators. There no longer exist cancel_* method. The main negotiation methods (manager.reserve_contracts, allocator.change_vreses) now use an interface which supports the semantic offered by frsh_group_change_mode_sync() i.e. in one negotiation operation, there might be a combination of multiple requests to negotiate, renegotiate or cancel contracts. Resource managers process these requests atomically, i.e. either all requests succeed or none of them. The interface for implementing individual resource managers and allocators remains the same with one exception - fres_sa_scenario_for_each_contract() was replaced by fres_sa_scenario_for_each_no_cancel_contract(). --- .topdeps | 1 + .topmsg | 6 + fres/cbroker/fcb.c | 271 ++++++++++++++-------- fres/cbroker/fcb.idl | 40 ++-- fres/contract/fres_contract.h | 14 ++ fres/contract/fres_error.c | 2 + fres/contract/fres_error.h | 2 + fres/resalloc/fra.idl | 12 +- fres/resalloc/fra_generic.c | 53 ++--- fres/resalloc/fra_generic.h | 29 ++- fres/resalloc/fres_vres.h | 4 +- fres/resmng/fres_sa_scenario.h | 25 +- fres/resmng/frm.idl | 19 +- fres/resmng/frm_generic.c | 79 +++++-- fres/resmng/frm_generic.h | 13 +- frsh_api/frsh_contract.c | 38 ++- resources/cluster_tree/frm_cluster_tree.c | 2 +- resources/cpucg/mngr/frm_cgcpu.c | 2 +- resources/dummy/frm_dummy.c | 18 +- resources/fpga/frm_fpga.c | 2 +- resources/item/frm_item.c | 2 +- 21 files changed, 418 insertions(+), 216 deletions(-) create mode 100644 .topdeps create mode 100644 .topmsg diff --git a/.topdeps b/.topdeps new file mode 100644 index 0000000..1f7391f --- /dev/null +++ b/.topdeps @@ -0,0 +1 @@ +master diff --git a/.topmsg b/.topmsg new file mode 100644 index 0000000..1e1cd7c --- /dev/null +++ b/.topmsg @@ -0,0 +1,6 @@ +From: Michal Sojka +Subject: [PATCH] api-enhancements + + + +Signed-off-by: Michal Sojka diff --git a/fres/cbroker/fcb.c b/fres/cbroker/fcb.c index 386d0b8..407f630 100644 --- a/fres/cbroker/fcb.c +++ b/fres/cbroker/fcb.c @@ -216,56 +216,139 @@ GAVL_CUST_NODE_INT_IMP(fcb_contract /* cust_prefix */, \ #define o2fcb(o) (struct fcb*)forb_instance_data(o) -static struct resource * -get_resource(const struct fcb *fcb, const struct fres_contract *contract) +struct res_key * +get_res_key(const struct fcb *fcb, const struct fres_contract *contract, struct res_key *key) { fres_block_resource *block_res; - struct res_key res_key; - struct resource *resource; - + block_res = fres_contract_get_resource(contract); + if (!block_res && !fres_contract_id_is_empty(&contract->id)) { + /* If the contract doesn't have resource information, + * this might be cancelation or renegotiation request, + * so look at our database for formerly submited + * contract. */ + struct fcb_contract *fcb_contract; + fcb_contract = fcb_contract_find(fcb, &contract->id); + if (fcb_contract) { + block_res = fres_contract_get_resource(fcb_contract->user_contract); + } + } if (!block_res) { ul_logerr("No resource specified\n"); return NULL; + } else { + key->type = block_res->resource_type; + key->id = block_res->resource_id; + } + return key; +} + +/** + * Checks whether all contracts refers to a single resource. + * + * @param fcb + * @param contracts Array of contract pointers. + * @param num Number of contracts. + * + * @return If all contracts refer to a signle resource, pointer to the + * coresponding resource structure is returned. Otherwise, NULL is + * returned. + */ +struct resource * +check_single_resource(struct fcb *fcb, struct fres_contract *contracts[], int num) +{ + struct resource *resource = NULL; + unsigned i; + struct res_key key, key2; + + for (i=0; iresource_type; - res_key.id = block_res->resource_id; - resource = fcb_resource_find(fcb, &res_key); + resource = fcb_resource_find(fcb, &key); if (!resource) { ul_logerr("No resource manager for %d.%d registered\n", - res_key.type, res_key.id); - return NULL; + key.type, key.id); } return resource; } +/** + * + * + * @param fcb + * @param contracts + * @param num + * + * @return Zero on success, non-zero error code on error. + */ +static int +prepare_reservation_contracts(struct fcb *fcb, struct fres_contract *contracts[], int num) +{ + unsigned i; + struct fcb_contract *fcb_contract; + + for (i=0; iid)) { + forb_uuid_generate((forb_uuid_t *)&c->id); + continue; + } + if (fres_contract_get_num_blocks(c) == 0) { + /* Nothing to do for deletion requesst */ + continue; + } + + /* Renegotiation */ + fcb_contract = fcb_contract_find(fcb, &c->id); + if (fcb_contract) { + /* Copy missing blocks from fcb_contract to contract */ + fres_contract_merge(c, fcb_contract->user_contract); + } else { + char str[60]; + fres_contract_id_to_string(str, &c->id, sizeof(str)); + ul_logerr("Attempt to renegotiate unknown contract %s\n", str); + return FRES_ERR_NOTHING_TO_RENEGOTIATE; + } + + } + return 0; +} + CORBA_long -negotiate_contract(fres_contract_broker obj, - const fres_contract_ptr contract, - fres_contract_id_t* id, - CORBA_Environment *ev) +negotiate_contracts(fres_contract_broker obj, + const fres_contract_ptr_seq* contracts, + fres_contract_id_seq** ids_out, + CORBA_Environment *ev) { struct fcb *fcb = o2fcb(obj); struct resource *resource; struct res_alloc *ra; int ret; forb_server_id app; - fres_contract_ptr contract_seq_buf; - fres_contract_ptr_seq contracts; fres_contract_ptr_seq *schedulable_contracts; - fres_contract_id_seq ids; - struct fcb_contract *fcb_contract; - - resource = get_resource(fcb, contract); + struct fcb_contract **fcb_contracts; + unsigned i; + fres_contract_id_seq* ids; + + resource = check_single_resource(fcb, contracts->_buffer, contracts->_length); if (!resource) { ret = FRSH_ERR_RESOURCE_ID_INVALID; goto err; } - - forb_uuid_generate((forb_uuid_t *)id); - contract->id = *id; + ret = prepare_reservation_contracts(fcb, contracts->_buffer, contracts->_length); + if (ret) + goto err; + forb_get_req_source(obj, &app); ra = fcb_alloc_find(resource, &app); if (!ra) { @@ -273,38 +356,73 @@ negotiate_contract(fres_contract_broker obj, forb_server_id_to_string(str, &app, sizeof(str)); ul_logerr("No resource allocator found for %d.%d and %s\n", resource->key.type, resource->key.id, str); - ret = -1; + ret = FRES_ERR_NO_RESOURCE_ALLOCATOR; goto err; } - fcb_contract = fcb_contract_new(id); - if (!fcb_contract) { - ret = -1; + /* Allocate all the needed memory before doing reservation. If + * there is no enough memory, it has no sense to call resource + * manager. */ + ids = malloc(sizeof(*ids)); + if (!ids) { + ev->major = FORB_EX_NO_MEMORY; + goto err; + } + memset(ids, 0, sizeof(*ids)); + CORBA_sequence_set_release(ids, CORBA_TRUE); + *ids_out = ids; + ids->_buffer = malloc(contracts->_length*sizeof(ids->_buffer[0])); + if (!ids->_buffer) { + ret = errno; + goto err; + } + ids->_length = ids->_maximum = contracts->_length; + for (i=0; i_length; i++) { + ids->_buffer[i] = contracts->_buffer[i]->id; + } + + fcb_contracts = malloc(sizeof(fcb_contracts[0])*contracts->_length); + if (!fcb_contracts) { + ret = errno; goto err; } - fcb_contract->user_contract = fres_contract_duplicate(contract); + memset(fcb_contracts, 0, sizeof(fcb_contracts[0])*contracts->_length); + + for (i=0; i_length; i++) { + struct fres_contract *c = contracts->_buffer[i]; + if (fres_contract_get_num_blocks(c) > 0) { + fcb_contracts[i] = fcb_contract_new(&c->id); + if (!fcb_contracts[i]) { + ret = errno ? errno : -1; + goto err_free_fcb_contracts; + } + fcb_contracts[i]->user_contract = fres_contract_duplicate(c); + if (!fcb_contracts[i]->user_contract) { + ret = errno ? errno : -1; + goto err_free_fcb_contracts; + } + } + } + /* TODO: Optimize the following by introducing + * reserve_and_commit FRM method. */ + /* Reserve contract */ - contracts._length = 1; - contract_seq_buf = contract; - contracts._buffer = &contract_seq_buf; - ret = fres_resource_manager_reserve_contracts(resource->mng, &contracts, ev); + ret = fres_resource_manager_reserve_contracts(resource->mng, contracts, ev); if (forb_exception_occurred(ev) || ret < 0) { - goto err_free_fcb_contract; + goto err_free_fcb_contracts; } if (ret == 1) { ul_logmsg("Contract was not accepted\n"); - goto err_free_fcb_contract; + goto err_free_fcb_contracts; } /* Commit contract */ - ids._length = ids._maximum = 1; - ids._buffer = id; - fres_resource_manager_commit_contracts(resource->mng, &ids, + fres_resource_manager_commit_contracts(resource->mng, ids, &schedulable_contracts, ev); if (forb_exception_occurred(ev)) { ret = FRES_ERR_FORB_EXCEPTION; - goto err_free_fcb_contract; + goto err_cancel_reservation; } /* Create VRes */ @@ -326,65 +444,29 @@ negotiate_contract(fres_contract_broker obj, goto err_cancel_reservation; } - /* Store the negotiated contract for later reference */ - fcb_contract_insert(fcb, fcb_contract); + /* Update database of negotiated contracts stored for later reference */ + for (i=0; i_length; i++) { + struct fcb_contract *fcb_contract; + fcb_contract = fcb_contract_find(fcb, &contracts->_buffer[i]->id); + /* Delete canceled or renegotiated user contract */ + if (fcb_contract) { + fcb_contract_delete(fcb, fcb_contract); + fcb_contract_destroy(fcb_contract); + } + if (fcb_contracts[i]) { + /* Insert new contracts */ + fcb_contract_insert(fcb, fcb_contracts[i]); + } + } return 0; err_cancel_reservation: - fres_resource_manager_cancel_contracts(resource->mng, &ids, ev); -err_free_fcb_contract: - fcb_contract_destroy(fcb_contract); -err: - return ret; -} - -CORBA_long cancel_contract(fres_contract_broker obj, - const fres_contract_id_t* id, - CORBA_Environment *ev) -{ - struct fcb *fcb = o2fcb(obj); - struct fcb_contract *fcb_contract; - struct resource *resource; - struct res_alloc *ra; - fres_contract_id_t id_buffer[1] = { *id }; - fres_contract_id_seq ids; - forb_server_id app; - int ret; - - fcb_contract = fcb_contract_find(fcb, &id_buffer[0]); /* FIXME: id */ - if (!fcb_contract) { - ret = FRSH_ERR_NOT_CONTRACTED_VRES; - goto err; - } - - resource = get_resource(fcb, fcb_contract->user_contract); - if (!resource) { - ret = FRSH_ERR_RESOURCE_ID_INVALID; - goto err; - } - - forb_get_req_source(obj, &app); - ra = fcb_alloc_find(resource, &app); - if (!ra) { - char str[60]; - forb_server_id_to_string(str, &app, sizeof(str)); - ul_logerr("No resource allocator found for %d.%d and %s\n", - resource->key.type, resource->key.id, str); - ret = -1; - goto err; - } - - ids._length = ids._maximum = 1; - ids._buffer = id_buffer; - ret = fres_resource_allocator_cancel_vreses(ra->ra, &ids, ev); - if (ret) { - ul_logerr("Cannot cancel vres\n"); - goto err; - } - fres_resource_manager_cancel_contracts(resource->mng, &ids, ev); - - return 0; + fres_resource_manager_cancel_reservations(resource->mng, ids, ev); +err_free_fcb_contracts: + for (i=0; i_length; i++) + fcb_contract_destroy(fcb_contracts[i]); + free(fcb_contracts); err: return ret; } @@ -534,8 +616,7 @@ static int register_inet_port(forb_orb orb) #endif struct forb_fres_contract_broker_impl impl = { - .negotiate_contract = negotiate_contract, - .cancel_contract = cancel_contract, + .negotiate_contracts = negotiate_contracts, .register_resource = register_resource, .register_allocator = register_allocator, .get_resources = get_resources, diff --git a/fres/cbroker/fcb.idl b/fres/cbroker/fcb.idl index 7d7ad3d..b4d2fc2 100644 --- a/fres/cbroker/fcb.idl +++ b/fres/cbroker/fcb.idl @@ -77,7 +77,7 @@ module fres { }; typedef sequence resource_seq; - + interface contract_broker { const string reg_name = "fcb"; /** @@ -109,30 +109,30 @@ module fres { long deregister_allocator(in resource_allocator rs_obj); /** - * Tries to negotiate a contract + * This function performs a set of negotiation + * operations with one resource. The oprations can + * include: adding new contracts (neg), modifying + * existing vres (reneg) or cancelling existing vres + * (cancel). It is guarantied that either all + * operation will be completed or none of them. * - * @param[in] contract Contract to negotiate + * @param[in] contracts Contract(s) to negotiate, + * renegotiate or cancel. The operation on the + * contract is determined as follows: + * - neg: contracts without ID + * - cancel: contracts with an ID and without any block + * - reneg: contracts without ID and some blocks (these + * blocks will be replaced in the previous contract). * - * @param[out] id Global ID of the contract if - * negotiation was successful. + * @param[out] ids IDs of the newly negotiated + * contracts, if negotiation was successful. Ordering + * of IDs is the same as in @a contracts. * - * @return Zero if the contract was successfully - * negotiated, non-zero code on error or when + * @return Zero if all operations were successfully + * carried out, non-zero code on error or when * negotiation failed. - * - * @todo Convert @a contract to @c sequence. - */ - long negotiate_contract(in contract::ptr contract, out fres::contract::id_t id); - - /** - * Cancels a previously negotiated contract - * - * @param id ID of the contract to cancel - * - * @return Zero if the contract was successfully - * canceled, non-zero code on error. */ - long cancel_contract(in contract::id_t id); + long negotiate_contracts(in contract::ptr_seq contracts, out contract::id_seq ids); /** * Returns sequence of registered resources. diff --git a/fres/contract/fres_contract.h b/fres/contract/fres_contract.h index 897e05b..5f426c3 100644 --- a/fres/contract/fres_contract.h +++ b/fres/contract/fres_contract.h @@ -83,6 +83,20 @@ static inline int fres_contract_id_cmp(const fres_contract_id_t *a, (forb_server_id*)b); } +static inline bool fres_contract_id_is_empty(const fres_contract_id_t *id) +{ + bool empty = true; + unsigned i; + + for (i=0; iallocated) { + if (fres_contract_get_num_blocks(vres->new) == 0) { + /* VRES cancleation */ + ret = alloc->cancel_vres(vres, alloc->priv); + + fres_vreses_delete(vres); + fres_vres_destroy(vres); + vreses[i] = NULL; + } else if (vres->allocated) { + /* VRES change */ struct fres_contract *last_perceived = vres->perceived; ret = alloc->change_vres(vreses[i], alloc->priv); if (last_perceived == vres->perceived) { @@ -192,6 +200,7 @@ CORBA_long change_vreses(fres_resource_allocator obj, vres->perceived = vres->new; } } else { + /* VRES creation */ ret = alloc->create_vres(vreses[i], alloc->priv); vres->perceived = vres->new; } @@ -202,52 +211,28 @@ CORBA_long change_vreses(fres_resource_allocator obj, } } - /* Update the vres structures */ + /* Update the vres structures (move new to allocated) */ for (i=0; iallocated; - vres->allocated = vres->new; - if (tmp) fres_contract_destroy(tmp); + + if (vres) { + tmp = vres->allocated; + vres->allocated = vres->new; + if (tmp) fres_contract_destroy(tmp); + } } - free(vreses); - return 0; + ret = 0; + err_free_vreses: free(vreses); err: return ret; } -CORBA_long cancel_vreses(fres_resource_allocator obj, - const fres_contract_id_seq* ids, - CORBA_Environment *ev) -{ - int ret, i; - struct fres_allocator *alloc = forb_instance_data(obj); - - for (i=0; i < ids->_length; i++) { - struct fres_vres *vres; - fres_contract_id_t *id = &ids->_buffer[i]; - - vres = fres_vreses_find(id); - if (!vres) goto err; - - ret = alloc->cancel_vres(vres, alloc->priv); - if (ret != 0) goto err; - - fres_vreses_delete(vres); - fres_vres_destroy(vres); - } - return 0; -err: - return ret; -} - static const struct forb_fres_resource_allocator_impl fra_impl = { .change_vreses = change_vreses, - .cancel_vreses = cancel_vreses, }; diff --git a/fres/resalloc/fra_generic.h b/fres/resalloc/fra_generic.h index 415193e..4c58b19 100644 --- a/fres/resalloc/fra_generic.h +++ b/fres/resalloc/fra_generic.h @@ -117,7 +117,7 @@ struct fres_allocator { * fres_vres::new. * * @param vres VRES to create. - * @param priv + * @param priv User supplied pointer registered by fra_register() * * @return Zero in case of success, nonzero error code on error. */ @@ -132,14 +132,26 @@ struct fres_allocator { * the return of this function. * * @param vres VRES to change. - * @param priv + * @param priv User supplied pointer registered by fra_register() * * @return Zero in case of success, nonzero error code on error. */ int (*change_vres)(fres_vres_t *vres, void *priv); + /** + * Cancel the CRES + * + * @param cancel_vres VRES to cancel + * + * @return Zero on succaess, non-zero error code on error. + */ + int (*cancel_vres)(fres_vres_t *vres, void *priv); /*@}*/ + /** @name Full interface - * The allocator can influence the order of applying changes. */ + * + * Full interface provides a way for the allocator to + * influence the order of applying changes. + */ /*@{*/ /** * A more general (and more compilcated) allocator @@ -154,7 +166,8 @@ struct fres_allocator { * fres_vres::perceived to @a fres_vres::new at some point in * time (depending on the kind of the change) as the * fres_vres::allocated parameters will be freed after the - * return of this function. + * return of this function. When the fres_vres::new contains + * no blocks, the VRES should be canceled. * * @param vreses Array of pointers to VRESes. * @param length The number of elements in @a vreses. @@ -165,14 +178,6 @@ struct fres_allocator { int (*apply_vres_changes)(fres_vres_t *vreses[], unsigned length, void *priv); /*@}*/ - /** - * - * - * @param cancel_vres - * - * @return - */ - int (*cancel_vres)(fres_vres_t *vres, void *priv); void *priv; /**< Pointer to allocator's private data */ /** diff --git a/fres/resalloc/fres_vres.h b/fres/resalloc/fres_vres.h index e468a32..95e8545 100644 --- a/fres/resalloc/fres_vres.h +++ b/fres/resalloc/fres_vres.h @@ -72,8 +72,8 @@ typedef struct fres_vres { /** * Stores actual allocation of the resource. During a mode * change, the callbacks can compare this old allocation with - * the changed (stored in @a new) one and depending on the - * kind of difference, it can apply the change + * the changed one (stored in @a new) and depending on the + * kind of difference, they can apply the change * differently. Callbacks must not change this field. as well as * the @a perceived field. */ diff --git a/fres/resmng/fres_sa_scenario.h b/fres/resmng/fres_sa_scenario.h index 75c7390..9b138e6 100644 --- a/fres/resmng/fres_sa_scenario.h +++ b/fres/resmng/fres_sa_scenario.h @@ -125,6 +125,30 @@ GAVL_CUST_NODE_INT_DEC(fres_sa_scenario_contract /* cust_prefix */, fres_contract_id_cmp /* cust_cmp_fnc */); +static inline struct fres_sa_contract * +fres_sa_scenario_contract_next_non_cancelation(struct fres_sa_scenario *scenario, + struct fres_sa_contract *contract) +{ + do { + if (!contract) + contract = fres_sa_scenario_contract_first(scenario); + else + contract = fres_sa_scenario_contract_next(scenario, contract); + } while (contract && (fres_contract_get_num_blocks(contract->contract) == 0)); + return contract; +} + +/** + * Expands to for-cycle for traversing all contracts in a scenario, + * which are not going to be canceled. The actual contract is stored + * in @a contract variable. + * + */ +#define fres_sa_scenario_for_each_no_cancel_contract(scenario, contract) \ + for((contract) = fres_sa_scenario_contract_next_non_cancelation((scenario), NULL); \ + contract; \ + (contract) = fres_sa_scenario_contract_next_non_cancelation((scenario), (contract))) + /** * Expands to for-cycle for traversing all contracts in a * scenario. The actual contract is stored in @a contract variable. @@ -133,7 +157,6 @@ GAVL_CUST_NODE_INT_DEC(fres_sa_scenario_contract /* cust_prefix */, #define fres_sa_scenario_for_each_contract(scenario, contract) \ gavl_cust_for_each(fres_sa_scenario_contract, scenario, contract) - struct fres_sa_contract * fres_sa_contract_new(void); diff --git a/fres/resmng/frm.idl b/fres/resmng/frm.idl index e161990..2775ac2 100644 --- a/fres/resmng/frm.idl +++ b/fres/resmng/frm.idl @@ -81,7 +81,16 @@ module fres { * contract, the previously reserved contract should * be replaced with the new one. * - * @param contracts New contracts to be reserved. + * @param[in] contracts Contract(s) to negotiate, + * renegotiate or cancel. The operation on the + * contract is determined as follows: + * - cancel: contracts with an ID and without any block + * + * - neg: contracts with ID not present in current + * schedulability scenario. + * + * - reneg: contracts with ID present in current + * schedulability scenario. * * @return * - Zero if reservation (admisson test) was successfull, @@ -106,8 +115,14 @@ module fres { */ void commit_contracts(in contract::id_seq ids, out contract::ptr_seq schedulable_contracts); - void cancel_contracts(in contract::id_seq ids); + /** + * Cancels not-commited reservations. + * + * @param ids ID's of reserved contracts to be rolled-back + * to the state before reservation. + */ + void cancel_reservations(in contract::id_seq ids); /** * Returns the list of commited contracts * diff --git a/fres/resmng/frm_generic.c b/fres/resmng/frm_generic.c index 27ff4c9..f1a80dd 100644 --- a/fres/resmng/frm_generic.c +++ b/fres/resmng/frm_generic.c @@ -60,7 +60,7 @@ #include UL_LOG_CUST(ulogd_frm_generic); -ul_log_domain_t ulogd_frm_generic = {UL_LOGL_MSG, "frm"}; +ul_log_domain_t ulogd_frm_generic = {UL_LOGL_DEB, "frm"}; #define object_to_frm(o) (struct frm_data*)forb_instance_data(o) #define save_errno(cmd) do { int _e = errno; cmd; errno = _e; } while(0) @@ -116,6 +116,7 @@ static CORBA_long reserve_contracts(fres_resource_manager obj, for (i=0; i_length; i++) { struct fres_contract *cin = contracts->_buffer[i]; + c = fres_sa_scenario_find_contract(scenario, &cin->id); if (!c) { c = fres_sa_contract_new(); @@ -125,6 +126,17 @@ static CORBA_long reserve_contracts(fres_resource_manager obj, } } if (!c) goto err; + + { + char id[40]; + char *operation; + fres_contract_id_to_string(id, &c->id, sizeof(id)); + if (fres_contract_get_num_blocks(cin) == 0) operation = "cancelation"; + else if (c->committed) operation = "renegotiation"; + else if (c->reserved) operation = "negotiation (already reserved)"; + else operation = "negotiation"; + ul_logdeb(" reserve contract %s %s\n", id, operation); + } assert(c->new == NULL); c->new = fres_contract_duplicate(cin); c->contract = c->new; @@ -133,7 +145,7 @@ static CORBA_long reserve_contracts(fres_resource_manager obj, ret = frm->desc->admission_test(scenario, frm->desc->priv, &schedulable); if (ret) { - ul_logerr("admission_test failed: %d\n", ret); + ul_logmsg("admission_test failed: %d\n", ret); goto err; } @@ -149,9 +161,9 @@ err: } static void commit_contracts(fres_resource_manager obj, - const fres_contract_id_seq* ids, - fres_contract_ptr_seq** contracts_with_scheduling_data, - CORBA_Environment *ev) + const fres_contract_id_seq* ids, + fres_contract_ptr_seq** contracts_with_scheduling_data, + CORBA_Environment *ev) { struct frm_data *frm = object_to_frm(obj); int i, num; @@ -174,43 +186,74 @@ static void commit_contracts(fres_resource_manager obj, * priorities). Question: How to recognize which contracts are * changed because of this commit? */ for (i=0; i < num; i++) { + char id[40]; + const char *operation; + fres_contract_id_to_string(id, &ids->_buffer[i], sizeof(id)); + c = fres_sa_scenario_find_contract(frm->scenario, &ids->_buffer[i]); if (c && c->reserved) { - if (c->committed) fres_contract_destroy(c->committed); - c->committed = c->reserved; - c->reserved = NULL; - contracts->_buffer[i] = fres_contract_duplicate(c->committed); + if (fres_contract_get_num_blocks(c->reserved) == 0) { + /* Cancelation request */ + operation = "cancelation"; + contracts->_buffer[i] = c->reserved; + c->reserved = NULL; + fres_sa_scenario_del_contract(frm->scenario, c); + fres_sa_contract_destroy(c); + } else { + /* Normal reservation */ + if (c->committed) { + operation = "renegotiation"; + fres_contract_destroy(c->committed); + } else { + operation = "negotiation"; + } + c->committed = c->reserved; + c->reserved = NULL; + contracts->_buffer[i] = fres_contract_duplicate(c->committed); + } } else { + operation = "error"; contracts->_buffer[i] = NULL; if (!c) ul_logerr("Commit to unknown contract ID\n"); else if (!c->reserved) ul_logerr("Commit to not reserved contract\n"); } + + ul_logdeb(" commit contract %s %s\n", id, operation); } - + *contracts_with_scheduling_data = contracts; err:; } -static void cancel_contracts(fres_resource_manager obj, - const fres_contract_id_seq* ids, - CORBA_Environment *ev) +static void cancel_reservations(fres_resource_manager obj, + const fres_contract_id_seq* ids, + CORBA_Environment *ev) { int i; struct frm_data *frm = object_to_frm(obj); - ul_logmsg("cancel_contracts\n"); + ul_logmsg("cancel_reservations\n"); for (i=0; i_length; i++) { struct fres_sa_contract *c; c = fres_sa_scenario_find_contract(frm->scenario, &ids->_buffer[i]); - if (c) { - fres_sa_scenario_del_contract(frm->scenario, c); - fres_sa_contract_destroy(c); + if (c->reserved) { + if (c->committed) { + /* Roll-back renegotiation */ + fres_contract_destroy(c->reserved); + c->reserved = NULL; + c->contract = c->committed; + } else { + /* Roll-back negotiation */ + fres_sa_scenario_del_contract(frm->scenario, c); + fres_sa_contract_destroy(c); + } } } } + static void get_contracts(fres_resource_manager obj, fres_contract_ptr_seq** contracts_out, CORBA_long* utilization, CORBA_Environment *ev) @@ -246,7 +289,7 @@ err:; static const struct forb_fres_resource_manager_impl frm_impl = { .reserve_contracts = reserve_contracts, .commit_contracts = commit_contracts, - .cancel_contracts = cancel_contracts, + .cancel_reservations = cancel_reservations, .get_contracts = get_contracts, }; diff --git a/fres/resmng/frm_generic.h b/fres/resmng/frm_generic.h index 13931d3..d6d0e91 100644 --- a/fres/resmng/frm_generic.h +++ b/fres/resmng/frm_generic.h @@ -69,12 +69,13 @@ extern ul_log_domain_t ulogd_frm_generic; * The admission test is called from * fres::resource_manager::reserve_contracts() to evaluate * schedulability of the scenario given as a parameter. It can use - * fres_sa_scenario_for_each_contract() macro to traverse through all - * the contracts in the scenario. No constract should be added or - * deleted, but any data (blocks) can be added to the contracts. If - * the scenario is schedulable, the contracts (with possibly added - * data) are sent to resource scheduler, which can use this additional - * data as parameters for VRes creation. + * fres_sa_scenario_for_each_no_cancel_contract() or + * fres_sa_scenario_for_each_no_cancel_contract() macros to traverse + * all the relevant contracts in the scenario. No constract should be + * added or deleted, but any data (blocks) can be added to the + * contracts. If the scenario is schedulable, the contracts (with + * possibly added data) are sent to resource scheduler, which can use + * this additional data as parameters for VRes creation. * * During the admission test, the contracts in scenariou can be * processed in any way as the test desires. The contract to be tested diff --git a/frsh_api/frsh_contract.c b/frsh_api/frsh_contract.c index 63c746c..f3010e9 100644 --- a/frsh_api/frsh_contract.c +++ b/frsh_api/frsh_contract.c @@ -326,7 +326,9 @@ int frsh_contract_negotiate { struct forb_env env; int ret; - fres_contract_id_t id; + fres_contract_ptr_seq contracts; + fres_contract_ptr contracts_buf; + fres_contract_id_seq *ids; fres_block_resource *r; if (!contract || !*contract || !vres) { @@ -342,16 +344,24 @@ int frsh_contract_negotiate } /* Negotiate contract */ - ret = fres_contract_broker_negotiate_contract(frsh_forb_global.fcb, - *contract, - &id, &env); + contracts_buf = *contract; + contracts._buffer = &contracts_buf; + contracts._length = contracts._maximum = 1; + ret = fres_contract_broker_negotiate_contracts(frsh_forb_global.fcb, + &contracts, + &ids, &env); if (forb_exception_occurred(&env)) { ret = FRES_ERR_FORB_EXCEPTION; + goto err; } if (ret == 0) { - *vres = fra_get_vres(&id); + assert(ids->_length == 1); + *vres = fra_get_vres(&ids->_buffer[0]); } + if (CORBA_sequence_get_release(ids)) + CORBA_free(ids->_buffer); + CORBA_free(ids); err: return ret; @@ -361,18 +371,32 @@ int frsh_contract_cancel (const frsh_vres_id_t vres) { int ret; struct forb_env env; + struct fres_contract *empty_contract; + fres_contract_ptr_seq contracts; + fres_contract_id_seq *ids; if (!vres) { ret = FRSH_ERR_BAD_ARGUMENT; goto err; } + + empty_contract = fres_contract_new(); + empty_contract->id = vres->id; - ret = fres_contract_broker_cancel_contract(frsh_forb_global.fcb, - &vres->id, &env); + contracts._buffer = &empty_contract; + contracts._length = contracts._maximum = 1; + ret = fres_contract_broker_negotiate_contracts(frsh_forb_global.fcb, + &contracts, + &ids, &env); if (forb_exception_occurred(&env)) { ret = FRES_ERR_FORB_EXCEPTION; + goto err; } + /* The returned ID is the same as of vres */ + if (CORBA_sequence_get_release(ids)) + CORBA_free(ids->_buffer); + CORBA_free(ids); err: return ret; } diff --git a/resources/cluster_tree/frm_cluster_tree.c b/resources/cluster_tree/frm_cluster_tree.c index 6d76d6d..f6342fc 100644 --- a/resources/cluster_tree/frm_cluster_tree.c +++ b/resources/cluster_tree/frm_cluster_tree.c @@ -96,7 +96,7 @@ int admission_test(struct fres_sa_scenario *scenario, void *priv, bool *schedula cum_traffic.length = 0; cum_traffic.p_nodes = NULL; - fres_sa_scenario_for_each_contract(scenario, c) { + fres_sa_scenario_for_each_no_cancel_contract(scenario, c) { fres_block_cluster_tree_traffic *contract_traffic; frsh_rel_time_t deadline; diff --git a/resources/cpucg/mngr/frm_cgcpu.c b/resources/cpucg/mngr/frm_cgcpu.c index 5f3a2d5..89f6c28 100644 --- a/resources/cpucg/mngr/frm_cgcpu.c +++ b/resources/cpucg/mngr/frm_cgcpu.c @@ -82,7 +82,7 @@ static int cpucg_admtest(struct fres_sa_scenario *scenario, void *priv, long int period, budget; long int sum_utilization = 0; - fres_sa_scenario_for_each_contract(scenario, c) { + fres_sa_scenario_for_each_no_cancel_contract(scenario, c) { fres_block_basic *basic; char id[40]; fres_contract_id_to_string(id, &c->contract->id, sizeof(id)); diff --git a/resources/dummy/frm_dummy.c b/resources/dummy/frm_dummy.c index 8f8a5a3..1700e92 100644 --- a/resources/dummy/frm_dummy.c +++ b/resources/dummy/frm_dummy.c @@ -81,12 +81,22 @@ int admission_test(struct fres_sa_scenario *scenario, void *priv, bool *schedula #endif data->some_data++; - fres_sa_scenario_for_each_contract(scenario, c) { + fres_sa_scenario_for_each_no_cancel_contract(scenario, c) { fres_block_basic *basic; fres_block_dummy_sched *dummy_sched; char id[40]; fres_contract_id_to_string(id, &c->id, sizeof(id)); +#ifdef CONFIG_RESOURCE_DUMMY_VERBOSE + printf(" %s contract: id=%s num_blocks=%d\n", + c->contract == c->new ? "new" : "old", id, + fres_contract_get_num_blocks(c->contract)); +#endif + basic = fres_contract_get_basic(c->contract); + if (!basic) { + fprintf(stderr, "No basic block present\n"); + return -1; + } if (c->contract == c->new) { /* Add data for scheduler to the new contracts */ @@ -95,7 +105,7 @@ int admission_test(struct fres_sa_scenario *scenario, void *priv, bool *schedula dummy_sched->priority = 100 - fosa_rel_time_to_msec(basic->budget); ret = fres_contract_add_dummy_sched(c->contract, dummy_sched); if (ret) { - fprintf(stderr, "Cannpt add dummy_sched block\n"); + fprintf(stderr, "Cannot add dummy_sched block\n"); return -1; } } else { @@ -106,12 +116,10 @@ int admission_test(struct fres_sa_scenario *scenario, void *priv, bool *schedula } } #ifdef CONFIG_RESOURCE_DUMMY_VERBOSE - printf(" %s contract: id=%s, period=%ld ms, budget=%ld ms, priority=%d\n", - c->contract == c->new ? "new" : "old", id, + printf(" period=%ld ms, budget=%ld ms, priority=%d\n", fosa_rel_time_to_msec(basic->period), fosa_rel_time_to_msec(basic->budget), dummy_sched->priority); #endif - } *schedulable = scenario->num_contracts <= 3; #ifdef CONFIG_RESOURCE_DUMMY_VERBOSE diff --git a/resources/fpga/frm_fpga.c b/resources/fpga/frm_fpga.c index 7597cb7..c82ca32 100644 --- a/resources/fpga/frm_fpga.c +++ b/resources/fpga/frm_fpga.c @@ -78,7 +78,7 @@ int admission_test(struct fres_sa_scenario *scenario, void *priv, bool *schedula struct fpga_state *data = priv; struct fres_sa_contract *c; - fres_sa_scenario_for_each_contract(scenario, c) { + fres_sa_scenario_for_each_no_cancel_contract(scenario, c) { fres_block_fpga *fpga; fpga = fres_contract_get_fpga(c->contract); diff --git a/resources/item/frm_item.c b/resources/item/frm_item.c index c0ceb44..cfe4db7 100644 --- a/resources/item/frm_item.c +++ b/resources/item/frm_item.c @@ -91,7 +91,7 @@ admission_test(struct fres_sa_scenario *scenario, void *priv, bool *schedulable) /* Find communicating nodes and the most restricting deadline */ all_nodes = 0; - fres_sa_scenario_for_each_contract(scenario, c) { + fres_sa_scenario_for_each_no_cancel_contract(scenario, c) { fres_block_item_nodes *nodes; fosa_rel_time_t deadline; -- 2.39.2