+int lmm_concurrency_slack(lmm_constraint_t cnstr){
+ //FIXME MARTIN: Replace by infinite value std::numeric_limits<int>::(max)(), or something better within Simgrid?
+ if(cnstr->concurrency_limit<0)
+ return 666;
+
+ return cnstr->concurrency_limit - cnstr->concurrency_current;
+}
+
+/** \brief Measure the minimum concurrency slack across all constraints where the given var is involved */
+int lmm_cnstrs_min_concurrency_slack(lmm_variable_t var){
+ int minslack = std::numeric_limits<int>::max();
+ for (int i = 0; i < var->cnsts_number; i++) {
+ int slack = lmm_concurrency_slack(var->cnsts[i].constraint);
+
+ //This is only an optimization, to avoid looking at more constraints when slack is already zero
+ //Disable it when debugging to let lmm_concurrency_slack catch nasty things
+ if (not slack && not XBT_LOG_ISENABLED(surf_maxmin, xbt_log_priority_debug))
+ return 0;
+
+ if(minslack>slack)
+ minslack=slack;
+ }
+
+ return minslack;
+}
+
+/* /Check if a variable can be enabled
+ *
+ * Make sure to set staged_weight before, if your intent is only to check concurrency
+ */
+int lmm_can_enable_var(lmm_variable_t var){
+ return var->staged_weight>0 && lmm_cnstrs_min_concurrency_slack(var)>=var->concurrency_share;
+}
+
+//Small remark: In this implementation of lmm_enable_var and lmm_disable_var, we will meet multiple times with var when
+// running lmm_update_modified_set.
+//A priori not a big performance issue, but we might do better by calling lmm_update_modified_set within the for loops
+// (after doing the first for enabling==1, and before doing the last for disabling==1)
+void lmm_enable_var(lmm_system_t sys, lmm_variable_t var){
+ xbt_assert(lmm_can_enable_var(var));
+
+ var->sharing_weight = var->staged_weight;
+ var->staged_weight = 0;
+
+ // Enabling the variable, move to var to list head. Subtlety is: here, we need to call lmm_update_modified_set AFTER
+ // moving at least one element of var.
+
+ xbt_swag_remove(var, &(sys->variable_set));
+ xbt_swag_insert_at_head(var, &(sys->variable_set));
+ for (int i = 0; i < var->cnsts_number; i++) {
+ lmm_element_t elem = &var->cnsts[i];
+ xbt_swag_remove(elem, &(elem->constraint->disabled_element_set));
+ xbt_swag_insert_at_head(elem, &(elem->constraint->enabled_element_set));
+ lmm_increase_concurrency(elem);
+ }
+ if (var->cnsts_number)
+ lmm_update_modified_set(sys, var->cnsts[0].constraint);
+
+ //When used within lmm_on_disabled_var, we would get an assertion fail, because transiently there can be variables
+ // that are staged and could be activated.
+ //Anyway, caller functions all call lmm_check_concurrency() in the end.
+ // lmm_check_concurrency(sys);
+}
+
+void lmm_disable_var(lmm_system_t sys, lmm_variable_t var){
+ xbt_assert(not var->staged_weight, "Staged weight should have been cleared");
+ // Disabling the variable, move to var to list tail. Subtlety is: here, we need to call lmm_update_modified_set BEFORE
+ // moving the last element of var.
+ xbt_swag_remove(var, &(sys->variable_set));
+ xbt_swag_insert_at_tail(var, &(sys->variable_set));
+ if (var->cnsts_number)
+ lmm_update_modified_set(sys, var->cnsts[0].constraint);
+ for (int i = 0; i < var->cnsts_number; i++) {
+ lmm_element_t elem = &var->cnsts[i];
+ xbt_swag_remove(elem, &(elem->constraint->enabled_element_set));
+ xbt_swag_insert_at_tail(elem, &(elem->constraint->disabled_element_set));
+
+ xbt_swag_remove(elem, &(elem->constraint->active_element_set));
+
+ lmm_decrease_concurrency(elem);
+ }
+
+ var->sharing_weight = 0.0;
+ var->staged_weight=0.0;
+ var->value = 0.0;
+ lmm_check_concurrency(sys);
+}
+
+/* /brief Find variables that can be enabled and enable them.
+ *
+ * Assuming that the variable has already been removed from non-zero weights
+ * Can we find a staged variable to add?
+ * If yes, check that none of the constraints that this variable is involved in is at the limit of its concurrency
+ * And then add it to enabled variables
+ */
+void lmm_on_disabled_var(lmm_system_t sys, lmm_constraint_t cnstr){
+
+ if(cnstr->concurrency_limit<0)
+ return;
+
+ int numelem = xbt_swag_size(&(cnstr->disabled_element_set));
+ if (not numelem)
+ return;
+
+ lmm_element_t elem = (lmm_element_t)xbt_swag_getFirst(&(cnstr->disabled_element_set));
+
+ //Cannot use xbt_swag_foreach, because lmm_enable_var will modify disabled_element_set.. within the loop
+ while (numelem-- && elem) {
+
+ lmm_element_t nextelem = (lmm_element_t)xbt_swag_getNext(elem, cnstr->disabled_element_set.offset);
+
+ if (elem->variable->staged_weight>0 ){
+ //Found a staged variable
+ //TODOLATER: Add random timing function to model reservation protocol fuzziness? Then how to make sure that
+ //staged variables will eventually be called?
+ if(lmm_can_enable_var(elem->variable)){
+ lmm_enable_var(sys,elem->variable);
+ }
+ }
+
+ xbt_assert(cnstr->concurrency_current<=cnstr->concurrency_limit,"Concurrency overflow!");
+ if(cnstr->concurrency_current==cnstr->concurrency_limit)
+ break;
+
+ elem = nextelem;
+ }