]> rtime.felk.cvut.cz Git - frescor/frsh.git/commitdiff
Update of resource manager semantic
authorMichal Sojka <sojkam1@fel.cvut.cz>
Thu, 6 Nov 2008 15:15:00 +0000 (16:15 +0100)
committerMichal Sojka <sojkam1@fel.cvut.cz>
Thu, 6 Nov 2008 15:15:00 +0000 (16:15 +0100)
fres_sa_contract was changed to be able to contain multiple versions of
contract. With this change, the admission test can test even if the
schedulability will be maintained during mode change.

fres/resmng/fres_sa_scenario.c
fres/resmng/fres_sa_scenario.h
fres/resmng/frm.idl
fres/resmng/frm_generic.c
fres/resmng/frm_generic.h
resources/dummy/frm_dummy.c

index a6a4181454be0d806f167a75806ec9633c85c888..12c46c1a822cc1db92df65cffb45086451a7d560 100644 (file)
@@ -18,8 +18,15 @@ void
 fres_sa_contract_destroy(struct fres_sa_contract *c)
 {
        if (c) {
-               if (c->contract) {
-                       fres_contract_destroy(c->contract);
+               if (c->commited) {
+                       fres_contract_destroy(c->commited);
+               }
+               if (c->reserved && c->reserved != c->commited) {
+                       fres_contract_destroy(c->reserved);
+               }
+               if (c->new && c->new != c->commited
+                          && c->new != c->reserved) {
+                       fres_contract_destroy(c->new);
                }
                free(c->priv);
                free(c);
@@ -41,8 +48,11 @@ fres_sa_contract_duplicate(const struct fres_sa_contract *src)
        dst = fres_sa_contract_new();
        if (!dst) goto err;
 
-       dst->status = src->status;
-       dst->contract = fres_contract_duplicate(src->contract);
+       dst->commited = fres_contract_duplicate(src->commited);
+       dst->reserved = fres_contract_duplicate(src->reserved);
+       dst->new      = fres_contract_duplicate(src->new);
+
+       /* TODO: How about duplication of src->priv? */
        
        return dst;
 err:
@@ -56,7 +66,7 @@ GAVL_CUST_NODE_INT_IMP(fres_sa_scenario_contract /* cust_prefix */,
                       fres_contract_id_t        /* cust_key_t */,
                       contracts                 /* cust_root_node */,
                       node                      /* cust_item_node */,
-                      contract->id              /* cust_item_key */,
+                      id                        /* cust_item_key */,
                       fres_contract_id_cmp      /* cust_cmp_fnc */);
 
 struct fres_sa_scenario *
index b6cde0119bd191f11d94067c4206f82a407f75ac..54c7e4e12960924f3d12bc2a62501208ffd7e78f 100644 (file)
@@ -15,8 +15,35 @@ enum fres_sa_contract_status {
  * 
  */
 struct fres_sa_contract {
-       enum fres_sa_contract_status status;
+       fres_contract_id_t id; /**< ID of all contract versions stored here. */
+
+       /** If the contract was already commited, the commited version
+        * is stored here. The contract is moved here from @a reserved
+        * field in fres_resource_manager::commit_contracts(). */
+       struct fres_contract *commited;
+
+       /** The reserved (and not yet commited) version of the
+        * contract.  If a new contract is to be negotiated or an old
+        * one is to be changed, the new version is stored here after
+        * successful admission test. */
+       struct fres_contract *reserved;
+
+       /** If a new contract is to be negotiated it is stored
+        * here. After sucessfull admission test, the contract is
+        * moved to @a reserved field. If the contract is to be
+        * changed, the admission test can compare the commited and
+        * new version and analyze not only the target state but also
+        * the mode change. */
+       struct fres_contract *new;
+
+       /** Convenience pointer, which has the same value as one of @a
+        * new, @a reserved and @a commited. It is meant for simpler
+        * admission tests, which do not evaluate mode changes and
+        * therefore have no need for comparison of commited and new
+        * version of contact. */
        struct fres_contract *contract;
+
+       
        void *priv;             /**< Private data for use by admission test  */
        gavl_node_t node;
 };
@@ -40,7 +67,7 @@ GAVL_CUST_NODE_INT_DEC(fres_sa_scenario_contract /* cust_prefix */,
                       fres_contract_id_t        /* cust_key_t */,
                       contracts                 /* cust_root_node */,
                       node                      /* cust_item_node */,
-                      contract->id              /* cust_item_key */,
+                      id                        /* cust_item_key */,
                       fres_contract_id_cmp      /* cust_cmp_fnc */);
 
 
index 1d2c39263ce65a4f9898fd81302053b8e9ddedac..b270891ccaaf010e2405c3fc5d301475415cc04b 100644 (file)
@@ -34,20 +34,21 @@ module fres {
                long reserve_contracts(in contract::ptr_seq contracts);
 
                /** 
-                * Put contracts with gived IDs to "commited" state.
+                * Puts contracts with given IDs to the "commited"
+                * state and sends back the changes to VRESes to reach
+                * the new state.
                 *
-                * @todo If some contract is in "commited" state, any
-                * change to this contract must go through mode chage
-                * protocol.
-                * 
                 * @param[in] ids IDs of contracts to be commited.
                 * 
-                * @param[out] contracts_with_scheduling_data Commited
-                * contracts with (possibly added data block(s) for
-                * scheduler).
+                * @param[out] schedulable_contracts Schedulable
+                * contracts, for new or changed VRESes. These
+                * contract may be extened by one or more data blocks
+                * for use by the scheduler. The scheduler receives
+                * the contracts in the same order as they are
+                * returned.
                 */
                void commit_contracts(in contract::id_seq ids,
-                                     out contract::ptr_seq contracts_with_scheduling_data);
+                                     out contract::ptr_seq schedulable_contracts);
                void cancel_contracts(in contract::id_seq ids);
        };
 };
index 9c5a8a67849aa3c731f8c625516abf99f95f2fc6..c91df163848f4db2dbafa99b2f00bab6a4787293 100644 (file)
@@ -8,58 +8,93 @@ UL_LOG_CUST(ulogd_frm);
 ul_log_domain_t ulogd_frm = {UL_LOGL_MSG, "frm"};
 
 struct frm_data {
-       struct fres_sa_scenario *reserved;
-       frm_adm_test_fnc_t admission_test;
-       void *priv;
+       struct fres_sa_scenario *scenario;
+       const struct fres_res_manager *desc;
 };
 
 #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)
 
+void fres_sa_scenario_reserve_new(struct fres_sa_scenario *scenario)
+{
+       struct fres_sa_contract *c;
+       fres_sa_scenario_for_each_contract(scenario, c) {
+               if (c->new) {
+                       if (c->reserved) {
+                               fres_contract_destroy(c->reserved);
+                       }
+                       c->reserved = c->new;
+                       c->new = NULL;
+               }
+       }
+}
+
+void fres_sa_scenario_rollback(struct fres_sa_scenario *scenario)
+{
+       struct fres_sa_contract *c, *c_next;
+
+       /* Deleteion safe scenario traverse */
+       for(c=fres_sa_scenario_contract_first(scenario),
+                   c_next=c?fres_sa_scenario_contract_next(scenario,c):NULL;
+           c;
+           c=c_next,c_next=c?fres_sa_scenario_contract_next(scenario,c):NULL) {
+               if (c->new) {
+                       if (c->commited || c->reserved) {
+                                       fres_contract_destroy(c->new);
+                                       c->new = NULL;
+                                       c->contract = c->reserved ? c->reserved : c->commited;
+                       } else {
+                               fres_sa_scenario_del_contract(scenario, c);
+                               fres_sa_contract_destroy(c);
+                       }
+               }
+       }
+}
+
+
 static CORBA_long reserve_contracts(fres_resource_manager obj,
                                    const fres_contract_ptr_seq* contracts,
                                    CORBA_Environment *ev)
 {
        struct frm_data *frm = object_to_frm(obj);
-       struct fres_sa_scenario *prospective;
-       bool schedulable;
+       struct fres_sa_scenario *scenario = frm->scenario;
+       bool schedulable =false;
        int i, ret;
+       struct fres_sa_contract *c;
 
        ul_logmsg("reserve_contracts\n");
        
-       prospective = fres_sa_scenario_duplicate(frm->reserved);
-       if (!prospective) goto err;
        for (i=0; i<contracts->_length; i++) {
-               struct fres_sa_contract *c;
-               c = fres_sa_contract_new();
+               struct fres_contract *cin = contracts->_buffer[i];
+               c = fres_sa_scenario_find_contract(scenario, &cin->id);
+               if (!c) {
+                       c = fres_sa_contract_new();
+                       if (c) {
+                               c->id = cin->id;
+                               fres_sa_scenario_add_contract(scenario, c);
+                       }
+               }
                if (!c) goto err;
-               c->status = FRES_SA_CONTRACT_NEW;
-               c->contract = fres_contract_duplicate(contracts->_buffer[i]);
-               if (!c->contract) goto err;
-               fres_sa_scenario_add_contract(prospective, c);
+               assert(c->new == NULL);
+               c->new = fres_contract_duplicate(cin);
+               c->contract = c->new;
+               if (!c->new) goto err;
        }
 
-       ret = frm->admission_test(prospective, frm->priv, &schedulable);
+       ret = frm->desc->admission_test(scenario, frm->desc->priv, &schedulable);
        if (ret) {
                ul_logerr("admission_test failed: %d\n", ret);
                goto err;
        }
 
        if (schedulable) {
-               struct fres_sa_contract *c;
-               fres_sa_scenario_for_each_contract(prospective, c) {
-                       if (c->status == FRES_SA_CONTRACT_NEW) {
-                               c->status = FRES_SA_CONTRACT_RESERVED;
-                       }
-               }
-               fres_sa_scenario_destroy(frm->reserved);
-               frm->reserved = prospective;
+               fres_sa_scenario_reserve_new(scenario);
        } else {
-               fres_sa_scenario_destroy(prospective);
+               fres_sa_scenario_rollback(scenario);
        }
        return schedulable ? 0 : 1;
 err:
-       fres_sa_scenario_destroy(prospective);
+       fres_sa_scenario_rollback(scenario);
        return -1;
 }
 
@@ -84,11 +119,22 @@ static void commit_contracts(fres_resource_manager obj,
        contracts->_buffer = CORBA_sequence_fres_contract_ptr_allocbuf(num);
        CORBA_sequence_set_release(contracts, CORBA_TRUE);
        contracts->_maximum = contracts->_length = num;
-       
+
+       /* TODO: Add also the changed contracts (e.g. because of
+        * priorities). Question: How to recognize which contracts are
+        * changed because of this commit? */
        for (i=0; i < num; i++) {
-               c = fres_sa_scenario_find_contract(frm->reserved, &ids->_buffer[i]);
-               c->status = FRES_SA_CONTRACT_COMMITED;
-               contracts->_buffer[i] = c->contract;
+               c = fres_sa_scenario_find_contract(frm->scenario, &ids->_buffer[i]);
+               if (c && c->reserved) {
+                       if (c->commited) fres_contract_destroy(c->commited);
+                       c->commited = c->reserved;
+                       c->reserved = NULL;
+                       contracts->_buffer[i] = fres_contract_duplicate(c->commited);
+               } else {
+                       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");
+               }
        }
        
        *contracts_with_scheduling_data = contracts;
@@ -106,10 +152,11 @@ static void cancel_contracts(fres_resource_manager obj,
 
        for (i=0; i<ids->_length; i++) {
                struct fres_sa_contract *c;
-               c = fres_sa_scenario_find_contract(frm->reserved, &ids->_buffer[i]);
+               c = fres_sa_scenario_find_contract(frm->scenario, &ids->_buffer[i]);
 
                if (c) {
-                       fres_sa_scenario_del_contract(frm->reserved, c);
+                       fres_sa_scenario_del_contract(frm->scenario, c);
+                       fres_sa_contract_destroy(c);
                }
        }
 }
@@ -121,83 +168,104 @@ static const struct forb_fres_resource_manager_impl frm_impl = {
        .cancel_contracts  = cancel_contracts,
 };
 
-/** 
- * Initializes and runs a generic resource manager. The only thing a
- * caller has to supply is admission test function, which is passed in
- * @a frm_data->admission_test.
- * 
- * @param orb FORB object used to communicate with other components.
- * @param admission_test Admission test function.
- * @param priv Pointer to passed as priv parameter to frm_adm_test_fnc_t.
- * 
- * @return 
- */
-int frm_register_and_run(forb_orb orb, const struct fres_res_manager *res_manager)
+fres_resource_manager frm_register(forb_orb orb, struct frm_data *frm_data,
+                                  forb_executor_t *executor,
+                                  const struct fres_res_manager *desc)
 {
        fres_contract_broker fcb;
        fres_resource_manager frm;
        struct forb_env env;
-       struct frm_data frm_data;
-       forb_executor_t executor;
        int ret;
 
-       memset(&frm_data, 0, sizeof(frm_data));
-       frm_data.admission_test = res_manager->admission_test;
-       frm_data.priv = res_manager->priv;
-       frm_data.reserved = fres_sa_scenario_new();
-       if (!frm_data.reserved) {
+       memset(frm_data, 0, sizeof(*frm_data));
+       frm_data->desc = desc;
+       frm_data->scenario = fres_sa_scenario_new();
+       if (!frm_data->scenario) {
                save_errno(ul_logerr("fres_sa_scenario_new failed\n"));
                goto err;
        }
 
        fcb = forb_resolve_reference(orb, fres_contract_broker_reg_name);
        if (!fcb) {
-               save_errno(ul_logerr("Could not find contract broker"));
+               save_errno(ul_logerr("Could not find contract broker\n"));
                goto err;
        }
 
-       frm = forb_fres_resource_manager_new(orb, &frm_impl, &frm_data);
+       frm = forb_fres_resource_manager_new(orb, &frm_impl, frm_data);
        if (!frm) {
-               save_errno(ul_logerr("forb_fres_resource_manager_new error"));
+               save_errno(ul_logerr("forb_fres_resource_manager_new error\n"));
                goto err_release_fcb;
        }
 
-       /* Prepare executor before we register the resource manager
-        * with contract broker */
-       ret = forb_executor_init(&executor);
-       if (ret) {
-               save_errno(ul_logerr("forb_executor_init failed"));
-               goto err_release_frm;
-       }
-               
-       ret = forb_executor_register_object(&executor, frm);
+       ret = forb_executor_register_object(executor, frm);
        if (ret) {
-               save_errno(ul_logerr("forb_executor_register_object failed"));
+               save_errno(ul_logerr("forb_executor_register_object failed\n"));
                goto err_executor;
        }
 
        /* Register resource manager */
        ret = fres_contract_broker_register_manager(fcb,
-                                                   res_manager->res_type,
-                                                   res_manager->res_id,
+                                                   desc->res_type,
+                                                   desc->res_id,
                                                    frm, &env);
        if (forb_exception_occured(&env) || ret != 0) {
-               save_errno(ul_logerr("fres_contract_broker_register_manager exception\n"));
-               goto err_executor;
+               save_errno(ul_logerr("fres_contract_broker_register_resource exception\n"));
+               goto err_register;
        }
 
+       forb_object_release(fcb);
+       return frm;
+err_register:  
+       forb_executor_unregister_object(executor, frm);
+err_executor:
+       forb_object_release(frm);
+err_release_fcb:       
+       forb_object_release(fcb);
+err:
+       return NULL;
+}
+
+/** 
+ * Initializes and runs a generic resource manager. The only thing a
+ * caller has to supply is admission test function, which is passed in
+ * @a frm_data->admission_test.
+ * 
+ * @param orb FORB object used to communicate with other components.
+ * @param desc Description on the resource manager
+ * 
+ * @return 
+ */
+int frm_register_and_run(forb_orb orb, const struct fres_res_manager *desc)
+{
+       fres_resource_manager frm;
+       struct frm_data frm_data;
+       forb_executor_t executor;
+       int ret = -1;
+
+       /* Prepare executor before we register the resource manager
+        * with contract broker */
+       ret = forb_executor_init(&executor);
+       if (ret) {
+               save_errno(ul_logerr("forb_executor_init failed\n"));
+               goto err;
+       }
+
+       frm = frm_register(orb, &frm_data, &executor, desc);
+       if (!frm) {
+               ret = -1;
+               save_errno(ul_logerr("frm_register failed\n"));
+               goto err_destroy_executor;
+       }
+               
        /* Start request processing */
        ul_logmsg("Waiting for requests\n");
        ret = forb_executor_run(&executor);
-       if (ret) goto err_executor;
-       
-       return 0;
-err_executor:
-       forb_executor_destroy(&executor);
+       if (ret) goto err_release_frm;
+
 err_release_frm:       
        forb_object_release(frm);
-err_release_fcb:       
-       forb_object_release(fcb);
+err_destroy_executor:
+       forb_executor_destroy(&executor);
 err:
-       return -1;
+       return ret;
 }
index 9ef51d5c9973c8ddd12e02269ef06994a5498313..dc948a4675745b8457cd824ddc810eb902c46b3b 100644 (file)
@@ -3,18 +3,27 @@
 
 #include <frm.h>
 #include <fres_sa_scenario.h>
+#include <frs_generic.h>
 
 /**
  * Admission test for a given resource.
  *
- * The admission test has to evaluate schedulability of the scenario
- * given as a parameter. It can use
+ * 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.
+ *
+ * During the admission test, the contracts in scenariou can be
+ * processed in any way as the test desires. The contract to be tested
+ * is stored in fres_sa_contract::contract. If the test want to know
+ * about the state of the contract it can compare the value of
+ * fres_sa_contract::contract with fres_sa_contract::new,
+ * fres_sa_contract::reserved and fres_sa_contract::commited.
  * 
  * @param[in] scenario Scenario to check its schedulability.
  * @param[in] priv Pointer to private data, registered by frm_generic_run().
@@ -29,10 +38,10 @@ struct fres_res_manager {
        frsh_resource_type_t res_type;
        frsh_resource_id_t res_id;
        frm_adm_test_fnc_t admission_test;
-       void *priv;             /**< Any data to be passed to admission test  */
+       void *priv;             /**< Any data to be passed to admission test */
 };
 
 int frm_register_and_run(forb_orb orb,
-                        const struct fres_res_manager *res_manager);
+                        const struct fres_res_manager *desc);
 
 #endif
index b623c0d49f638c8eb8ff6994a3ad236b67ce83a0..6e3e371782307d5268329ee1ee5497dc0588616f 100644 (file)
@@ -29,7 +29,7 @@ int admission_test(struct fres_sa_scenario *scenario, void *priv, bool *schedula
                fres_contract_id_to_string(id, &c->contract->id, sizeof(id));
                basic = fres_contract_get_basic(c->contract);
 
-               if (c->status == FRES_SA_CONTRACT_NEW) {
+               if (c->contract == c->new) {
                        /* Add data for scheduler to the new contracts */
                        dummy_sched = malloc(sizeof(*dummy_sched));
                        if (!dummy_sched) return -1;
@@ -48,7 +48,7 @@ int admission_test(struct fres_sa_scenario *scenario, void *priv, bool *schedula
                }
 
                printf("  %s contract: id=%s, period=%ld ms, budget=%ld ms, priority=%d\n",
-                      c->status == FRES_SA_CONTRACT_NEW ? "new" : "old", id,
+                      c->contract == c->new ? "new" : "old", id,
                       fosa_rel_time_to_msec(basic->period),
                       fosa_rel_time_to_msec(basic->budget), dummy_sched->priority);