Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Change dependence function to mimic the one in AVOCS article
[simgrid.git] / src / mc / mc_transition.c
index 6b9d7f8..dcc1915 100644 (file)
 #include "private.h"
 
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_trans, mc,
+                               "Logging specific to MC transitions");
+
+/* Creates a new iSend transition */
+mc_transition_t MC_trans_isend_new(smx_rdv_t rdv)
+{
+  mc_transition_t trans = xbt_new0(s_mc_transition_t, 1);
+
+  trans->type = mc_isend;
+  trans->process = SIMIX_process_self();
+  trans->isend.rdv = rdv;
+  trans->name = bprintf("[%s][%s] iSend (%p)", trans->process->smx_host->name,
+                        trans->process->name, trans); 
+  return trans;
+}
+
+/* Creates a new iRecv transition */
+mc_transition_t MC_trans_irecv_new(smx_rdv_t rdv)
+{
+  mc_transition_t trans = xbt_new0(s_mc_transition_t, 1);
+
+  trans->type = mc_irecv;
+  trans->process = SIMIX_process_self();
+  trans->irecv.rdv = rdv;
+  trans->name = bprintf("[%s][%s] iRecv (%p)", trans->process->smx_host->name, 
+                        trans->process->name, trans);
+  return trans;
+}
+
+/* Creates a new Wait transition */
+mc_transition_t MC_trans_wait_new(smx_comm_t comm)
+{
+  mc_transition_t trans = xbt_new0(s_mc_transition_t, 1);
+
+  trans->type = mc_wait;
+  trans->process = SIMIX_process_self();
+  trans->wait.comm = comm;
+  trans->name = bprintf("[%s][%s] Wait (%p)", trans->process->smx_host->name,
+                        trans->process->name, trans);
+  return trans;
+}
+
+/* Creates a new test transition */
+mc_transition_t MC_trans_test_new(smx_comm_t comm)
+{
+  mc_transition_t trans = xbt_new0(s_mc_transition_t, 1);
+
+  trans->type = mc_test;
+  trans->process = SIMIX_process_self();
+  trans->test.comm = comm;
+  trans->name = bprintf("[%s][%s] Test (%p)", trans->process->smx_host->name,
+                        trans->process->name, trans);      
+  return trans;
+}
+
+/* Creates a new WaitAny transition */
+mc_transition_t MC_trans_waitany_new(xbt_dynar_t comms)
+{
+  mc_transition_t trans = xbt_new0(s_mc_transition_t, 1);
+
+  trans->type = mc_waitany;
+  trans->process = SIMIX_process_self();
+  trans->waitany.comms = comms;
+  trans->name = bprintf("[%s][%s] WaitAny (%p)", trans->process->smx_host->name,
+                        trans->process->name, trans);
+  return trans;
+}
+
+/* Creates a new Random transition */
+mc_transition_t MC_trans_random_new(int value)
+{
+  mc_transition_t trans = xbt_new0(s_mc_transition_t, 1);
+
+  trans->type = mc_random;
+  trans->process = SIMIX_process_self();
+  trans->random.value = value;
+  trans->name = bprintf("[%s][%s] Random %d (%p)", trans->process->smx_host->name, 
+                        trans->process->name, value, trans);
+
+  return trans;
+}
+
+/**
+ * \brief Deletes a transition
+ * \param trans The transition to be deleted
+ */
+void MC_transition_delete(mc_transition_t trans)
+{
+  xbt_free(trans->name);
+  xbt_free(trans);
+}
+
+/************************** Interception Functions ****************************/
+/* These functions intercept all the actions relevant to the model-checking
+ * process, the only difference between them is the type of transition they
+ * create. The interception works by yielding the process performer of the
+ * action, and depending on the execution mode it behaves diferently.
+ * There are two running modes, a replay (back-track process) in which no 
+ * transition needs to be created, or a new state expansion, which in 
+ * consecuence a transition needs to be created and added to the set of
+ * transitions associated to the current state.
+ */
+
 /**
- * \brief Create a model-checker transition and add it to the set of avaiable
- *        transitions of the current state, if not running in replay mode.
- * \param process The process who wants to perform the transition
- * \param comm The type of then transition (comm_send, comm_recv)
-*/
-mc_transition_t MC_create_transition(mc_trans_type_t type, smx_process_t p, smx_rdv_t rdv, smx_comm_t comm)
+ * \brief Intercept an iSend action
+ * \param rdv The rendez-vous of the iSend
+ */
+void MC_trans_intercept_isend(smx_rdv_t rdv)
 {
+  mc_transition_t trans=NULL;
   mc_state_t current_state = NULL;
-  char *type_str = NULL;
-  
   if(!mc_replay_mode){
     MC_SET_RAW_MEM;
-    mc_transition_t trans = xbt_new0(s_mc_transition_t, 1);
+    trans = MC_trans_isend_new(rdv);
+    current_state = (mc_state_t) 
+      xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_stack));
+    xbt_setset_set_insert(current_state->created_transitions, trans);
+    xbt_setset_set_insert(current_state->transitions, trans);
+    MC_UNSET_RAW_MEM;
+  }
+  SIMIX_process_yield();  
+}
 
-    /* Generate a string for the "type" */
-    switch(type){
-      case mc_isend:
-        type_str = bprintf("iSend");
-        break;
-      case mc_irecv:
-        type_str = bprintf("iRecv");
-        break;
-      case mc_wait:
-        type_str = bprintf("Wait");
-        break;
-      case mc_waitany:
-        type_str = bprintf("WaitAny");
-        break;
-      default:
-        xbt_die("Invalid transition type");
-    }
-    
-    trans->name = bprintf("[%s][%s] %s (%p)", p->smx_host->name, p->name, type_str, trans);
-    xbt_free(type_str);
-    
-    trans->type = type;
-    trans->process = p;
-    trans->rdv = rdv;
-    trans->comm = comm;
-    /* Push it onto the enabled transitions set of the current state */
-
-   current_state = (mc_state_t) 
+/**
+ * \brief Intercept an iRecv action
+ * \param rdv The rendez-vous of the iRecv
+ */
+void MC_trans_intercept_irecv(smx_rdv_t rdv)
+{
+  mc_transition_t trans=NULL;
+  mc_state_t current_state = NULL;
+  if(!mc_replay_mode){
+    MC_SET_RAW_MEM;
+    trans = MC_trans_irecv_new(rdv);
+    current_state = (mc_state_t) 
       xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_stack));
     xbt_setset_set_insert(current_state->created_transitions, trans);
     xbt_setset_set_insert(current_state->transitions, trans);
     MC_UNSET_RAW_MEM;
-    return trans;
   }
-  return NULL;
+  SIMIX_process_yield();
 }
 
-void MC_random_create(int min, int max)
+/**
+ * \brief Intercept a Wait action
+ * \param comm The communication associated to the wait
+ */
+void MC_trans_intercept_wait(smx_comm_t comm)
 {
-  smx_process_t p;
+  mc_transition_t trans=NULL;
   mc_state_t current_state = NULL;
-  char *type_str = NULL;
-  
   if(!mc_replay_mode){
-    p = SIMIX_process_self();
-    
     MC_SET_RAW_MEM;
-    mc_transition_t trans = xbt_new0(s_mc_transition_t, 1);
-    
-    trans->name = bprintf("[%s][%s] mc_random(%d,%d) (%p)", p->smx_host->name, p->name, min, max, trans);
-    xbt_free(type_str);
-
-    trans->type = mc_random ;
-    trans->process = p;
-    trans->min = min;
-    trans->max = max;
-    trans->current_value = min;
-    
-    /* Push it onto the enabled transitions set of the current state */
+    trans = MC_trans_wait_new(comm);
     current_state = (mc_state_t) 
       xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_stack));
     xbt_setset_set_insert(current_state->created_transitions, trans);
     xbt_setset_set_insert(current_state->transitions, trans);
     MC_UNSET_RAW_MEM;
   }
+  SIMIX_process_yield();
 }
 
-/** 
- * \brief Associate a communication to a transition
- * \param trans The transition
- * \param comm The communication
+/**
+ * \brief Intercept a Test action
+ * \param comm The communication associated to the Test
  */
-void MC_transition_set_comm(mc_transition_t trans, smx_comm_t comm)
+void MC_trans_intercept_test(smx_comm_t comm)
 {
-  if(trans)
-    trans->comm = comm;
-  return;
+  mc_transition_t trans=NULL;
+  mc_state_t current_state = NULL;
+  if(!mc_replay_mode){
+    MC_SET_RAW_MEM;
+    trans = MC_trans_test_new(comm);
+    current_state = (mc_state_t) 
+      xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_stack));
+    xbt_setset_set_insert(current_state->created_transitions, trans);
+    xbt_setset_set_insert(current_state->transitions, trans);
+    MC_UNSET_RAW_MEM;
+  }
+  SIMIX_process_yield();
 }
 
 /**
- * \brief Deletes a transition
- * \param trans The transition to be deleted
+ * \brief Intercept a WaitAny action
+ * \param comms The communications associated to the WaitAny
  */
-void MC_transition_delete(mc_transition_t trans)
+void MC_trans_intercept_waitany(xbt_dynar_t comms)
 {
-  xbt_free(trans->name);
-  xbt_free(trans);
+  unsigned int cursor;
+  mc_transition_t trans = NULL;
+  mc_state_t current_state = NULL;
+  smx_comm_t comm = NULL;
+  
+  if(!mc_replay_mode){
+    MC_SET_RAW_MEM;
+    current_state = (mc_state_t) 
+      xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_stack));
+    xbt_dynar_foreach(comms, cursor, comm){ 
+      trans = MC_trans_wait_new(comm);
+      xbt_setset_set_insert(current_state->created_transitions, trans);
+      xbt_setset_set_insert(current_state->transitions, trans);
+    }
+    MC_UNSET_RAW_MEM;
+  }
+  SIMIX_process_yield();
+}
+
+/**
+ * \brief Intercept a Random action
+ * \param min The minimum value that can be returned by the Random action
+ * \param max The maximum value that can be returned by the Random action
+ */
+void MC_trans_intercept_random(int min, int max)
+{
+  int i;
+  mc_transition_t trans=NULL;
+  mc_state_t current_state = NULL;
+  if(!mc_replay_mode){
+    MC_SET_RAW_MEM;
+    current_state = (mc_state_t) 
+      xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_stack));
+    for(i=min; i <= max; i++){    
+      trans = MC_trans_random_new(i);
+      xbt_setset_set_insert(current_state->created_transitions, trans);
+      xbt_setset_set_insert(current_state->transitions, trans);
+    }
+    MC_UNSET_RAW_MEM;
+  }
+  SIMIX_process_yield();
+}
+
+/* Compute the subset of enabled transitions of the transition set */
+void MC_trans_compute_enabled(xbt_setset_set_t enabled, xbt_setset_set_t transitions)
+{
+  unsigned int index = 0;
+  smx_comm_t comm = NULL;
+  mc_transition_t trans = NULL;
+  xbt_setset_cursor_t cursor = NULL;
+  xbt_setset_foreach(transitions, cursor, trans){
+    switch(trans->type){
+      /* Wait transitions are enabled only if the communication has both a
+         sender and receiver */
+      case mc_wait:
+        if(trans->wait.comm->src_proc && trans->wait.comm->dst_proc){
+          xbt_setset_set_insert(enabled, trans);
+          DEBUG1("Transition %p is enabled for next state", trans);
+        }
+        break;
+
+      /* WaitAny transitions are enabled if any of it's communications has both
+         a sender and a receiver */
+      case mc_waitany:
+        xbt_dynar_foreach(trans->waitany.comms, index, comm){
+          if(comm->src_proc && comm->dst_proc){
+            xbt_setset_set_insert(enabled, trans);
+            DEBUG1("Transition %p is enabled for next state", trans);
+            break;
+          }
+        }
+        break;
+
+      /* The rest of the transitions cannot be disabled */
+      default:
+        xbt_setset_set_insert(enabled, trans);
+        DEBUG1("Transition %p is enabled for next state", trans);
+        break;
+    } 
+  }
 }
 
 /**
@@ -115,27 +282,33 @@ int MC_transition_depend(mc_transition_t t1, mc_transition_t t2)
   if(t1->process == t2->process) 
     return FALSE;
 
-  if(t1->type != t2->type)
+  if(t1->type == mc_isend && t2->type == mc_irecv)
+    return FALSE;
+
+  if(t1->type == mc_irecv && t2->type == mc_isend)
     return FALSE;
   
-  if(t1->type == mc_isend && t2->type == mc_isend && t1->rdv != t2->rdv)
+  if(t1->type == mc_random || t2->type == mc_random)
+    return FALSE;
+  
+  if(t1->type == mc_isend && t2->type == mc_isend && t1->isend.rdv != t2->isend.rdv)
     return FALSE;
 
-  if(t1->type == mc_irecv && t2->type == mc_irecv && t1->rdv != t2->rdv)
+  if(t1->type == mc_irecv && t2->type == mc_irecv && t1->irecv.rdv != t2->irecv.rdv)
     return FALSE;
 
-  if(t1->type == mc_wait && t2->type == mc_wait && t1->comm == t2->comm)
+  if(t1->type == mc_wait && t2->type == mc_wait && t1->wait.comm == t2->wait.comm)
     return FALSE;
   
   if(t1->type == mc_wait && t2->type == mc_wait 
-     && t1->comm->src_buff != NULL
-     && t1->comm->dst_buff != NULL
-     && t2->comm->src_buff != NULL
-     && t2->comm->dst_buff != NULL
-     && t1->comm->dst_buff != t2->comm->src_buff
-     && t1->comm->dst_buff != t2->comm->dst_buff
-     && t2->comm->dst_buff != t1->comm->src_buff)
+     && t1->wait.comm->src_buff != NULL
+     && t1->wait.comm->dst_buff != NULL
+     && t2->wait.comm->src_buff != NULL
+     && t2->wait.comm->dst_buff != NULL
+     && t1->wait.comm->dst_buff != t2->wait.comm->src_buff
+     && t1->wait.comm->dst_buff != t2->wait.comm->dst_buff
+     && t2->wait.comm->dst_buff != t1->wait.comm->src_buff)
     return FALSE;
-  
+
   return TRUE;
 }
\ No newline at end of file