Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge context_start into context_new to simplify the soup
[simgrid.git] / src / simix / smx_process.c
index 76643e8..601f2c4 100644 (file)
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(simix_process, simix,
                                 "Logging specific to SIMIX (process)");
 
-/******************************** Process ************************************/
 /**
- * \brief Creates and runs a new #smx_process_t.
+ * \brief Move a process to the list of process to destroy. *
+ */
+void SIMIX_process_cleanup(void *arg)
+{
+  xbt_swag_remove(arg, simix_global->process_to_run);
+  xbt_swag_remove(arg, simix_global->process_list);
+  xbt_swag_remove(arg, ((smx_process_t) arg)->smx_host->process_list);
+  xbt_swag_insert(arg, simix_global->process_to_destroy);
+}
+
+/** 
+ * Garbage collection
  *
- * Does exactly the same as #SIMIX_process_create_with_arguments but without
-   providing standard arguments (\a argc, \a argv).
- * \see SIMIX_process_create_with_arguments
+ * Should be called some time to time to free the memory allocated for processes
+ * that have finished (or killed).
  */
+void SIMIX_process_empty_trash(void)
+{
+  smx_process_t process = NULL;
 
+  while ((process = xbt_swag_extract(simix_global->process_to_destroy))) {
+    SIMIX_context_free(process->context);
 
-void SIMIX_process_cleanup(void *arg)
+    /* Free the exception allocated at creation time */
+    if (process->exception)
+      free(process->exception);
+    if (process->properties)
+      xbt_dict_free(&process->properties);
+
+    free(process->name);
+    process->name = NULL;
+    free(process);
+  }
+}
+
+/**
+ * \brief Creates and runs the maestro process
+ */
+void SIMIX_create_maestro_process()
 {
-  xbt_swag_remove(arg, simix_global->process_list);
-  xbt_swag_remove(arg, simix_global->process_to_run);
-  xbt_swag_remove(arg,
-                  ((smx_process_t) arg)->simdata->smx_host->
-                  simdata->process_list);
-  free(((smx_process_t) arg)->name);
-  ((smx_process_t) arg)->name = NULL;
-
-  free(((smx_process_t) arg)->simdata);
-  ((smx_process_t) arg)->simdata = NULL;
-  free(arg);
+  smx_process_t process = NULL;
+  process = xbt_new0(s_smx_process_t, 1);
+
+  /* Process data */
+  process->name = (char *) "";
+
+  process->exception = xbt_new(ex_ctx_t, 1);
+  XBT_CTX_INITIALIZE(process->exception);
+
+  /* Create a dummy context for maestro */
+  process->context = SIMIX_context_new(NULL, 0, NULL, NULL, NULL);
+
+  /* Set it as the maestro process */
+  simix_global->maestro_process = process;
+  simix_global->current_process = process;
+
+  return;
 }
 
 /**
@@ -45,7 +80,7 @@ void SIMIX_process_cleanup(void *arg)
  * A constructor for #m_process_t taking four arguments and returning the corresponding object. The structure (and the corresponding thread) is created, and put in the list of ready process.
  *
  * \param name a name for the object. It is for user-level information and can be NULL.
-* \param data a pointer to any data one may want to attach to the new object.  It is for user-level information and can be NULL. It can be retrieved with the function \ref MSG_process_get_data.
+ * \param data a pointer to any data one may want to attach to the new object.  It is for user-level information and can be NULL. It can be retrieved with the function \ref MSG_process_get_data.
  * \param host the location where the new agent is executed.
  * \param argc first argument passed to \a code
  * \param argv second argument passed to \a code
@@ -58,127 +93,51 @@ smx_process_t SIMIX_process_create(const char *name,
                                    const char *hostname, int argc,
                                    char **argv, xbt_dict_t properties)
 {
-  smx_simdata_process_t simdata = NULL;
   smx_process_t process = NULL;
-  smx_process_t self = NULL;
   smx_host_t host = SIMIX_host_get_by_name(hostname);
 
-  DEBUG2("Start process %s on host %s",name,hostname);
+  DEBUG2("Start process %s on host %s", name, hostname);
 
   if (!SIMIX_host_get_state(host)) {
     WARN2("Cannot launch process '%s' on failed host '%s'", name, hostname);
     return NULL;
   }
-  simdata = xbt_new0(s_smx_simdata_process_t, 1);
   process = xbt_new0(s_smx_process_t, 1);
-  /*char alias[MAX_ALIAS_NAME + 1] = {0};
-     msg_mailbox_t mailbox; */
 
   xbt_assert0(((code != NULL) && (host != NULL)), "Invalid parameters");
-  /* Simulator Data */
-
-  simdata->smx_host = host;
-  simdata->mutex = NULL;
-  simdata->cond = NULL;
-  simdata->argc = argc;
-  simdata->argv = argv;
-  simdata->context = xbt_context_new(name, code, NULL, NULL,
-                                     simix_global->cleanup_process_function,
-                                     process, simdata->argc, simdata->argv);
-
-  /* Process structure */
-  process->name = xbt_strdup(name);
-  process->simdata = simdata;
-  process->data = data;
-
-  /* Add properties */
-  simdata->properties = properties;
-
-  xbt_swag_insert(process, host->simdata->process_list);
-
-  /* fix current_process, about which xbt_context_start mocks around */
-  self = simix_global->current_process;
-  xbt_context_start(process->simdata->context);
-  simix_global->current_process = self;
-
-  xbt_swag_insert(process, simix_global->process_list);
-  DEBUG2("Inserting %s(%s) in the to_run list", process->name, host->name);
-  xbt_swag_insert(process, simix_global->process_to_run);
-
-  /*sprintf(alias,"%s:%s",hostname,process->name);
 
-     mailbox = MSG_mailbox_new(alias);
-     MSG_mailbox_set_hostname(mailbox, hostname); */
-
-  return process;
-}
-
-/**
- * \brief Creates and runs a new #smx_process_t hosting a JAVA thread
- *
- * Warning: this should only be used in libsimgrid4java, since it create
- * a context with no code, which leads to segfaults in plain libsimgrid
- */
-void SIMIX_jprocess_create(const char *name, smx_host_t host,
-                           void *data,
-                           void *jprocess, void *jenv, smx_process_t * res)
-{
-  smx_simdata_process_t simdata = xbt_new0(s_smx_simdata_process_t, 1);
-  smx_process_t process = xbt_new0(s_smx_process_t, 1);
-  smx_process_t self = NULL;
-
-  /* HACK: We need this trick because when we xbt_context_new() do
-     syncronization stuff, the s_process field in the m_process needs
-     to have a valid value, and we call xbt_context_new() before
-     returning, of course, ie, before providing a right value to the
-     caller (Java_simgrid_msg_Msg_processCreate) have time to store it
-     in place. This way, we initialize the m_process->simdata->s_process
-     field ourself ASAP.
-
-     All this would be much simpler if the synchronization stuff would be done
-     in the JAVA world, I think.
-   */
-  *res = process;
-
-
-
-  DEBUG5("jprocess_create(name=%s,host=%p,data=%p,jproc=%p,jenv=%p)",
-         name, host, data, jprocess, jenv);
-  xbt_assert0(host, "Invalid parameters");
-  /* Simulator Data */
-  simdata->smx_host = host;
-  simdata->mutex = NULL;
-  simdata->cond = NULL;
-  simdata->argc = 0;
-  simdata->argv = NULL;
-
-
-  simdata->context = xbt_context_new(name, NULL, NULL, jprocess,
-                                     simix_global->cleanup_process_function,
-                                     process,
-                                     /* argc/argv */ 0, NULL);
-
-  /* Process structure */
+  /* Process data */
   process->name = xbt_strdup(name);
-  process->simdata = simdata;
+  process->smx_host = host;
+  process->mutex = NULL;
+  process->cond = NULL;
+  process->iwannadie = 0;
   process->data = data;
 
-  xbt_swag_insert(process, host->simdata->process_list);
+  VERB1("Create context %s", process->name);
+  process->context = SIMIX_context_new(code, argc, argv,
+                                       simix_global->cleanup_process_function,
+                                       process);
+
+  process->exception = xbt_new(ex_ctx_t, 1);
+  XBT_CTX_INITIALIZE(process->exception);
 
-  /* fix current_process, about which xbt_context_start mocks around */
-  self = simix_global->current_process;
+  /* Add properties */
+  process->properties = properties;
 
-  xbt_context_start(process->simdata->context);
+  /* Add the process to it's host process list */
+  xbt_swag_insert(process, host->process_list);
 
-  simix_global->current_process = self;
+  DEBUG1("Start context '%s'", process->name);
 
+  /* Now insert it in the global process list and in the process to run list */
   xbt_swag_insert(process, simix_global->process_list);
   DEBUG2("Inserting %s(%s) in the to_run list", process->name, host->name);
   xbt_swag_insert(process, simix_global->process_to_run);
 
+  return process;
 }
 
-
 /** \brief Kill a SIMIX process
  *
  * This function simply kills a \a process... scarry isn't it ? :).
@@ -187,26 +146,48 @@ void SIMIX_jprocess_create(const char *name, smx_host_t host,
  */
 void SIMIX_process_kill(smx_process_t process)
 {
-  smx_simdata_process_t p_simdata = process->simdata;
+  DEBUG2("Killing process %s on %s", process->name, process->smx_host->name);
 
-  DEBUG2("Killing process %s on %s", process->name,
-         p_simdata->smx_host->name);
+  process->iwannadie = 1;
 
-  /* Cleanup if we were waiting for something */
-  if (p_simdata->mutex)
-    xbt_swag_remove(process, p_simdata->mutex->sleeping);
-
-  if (p_simdata->cond)
-    xbt_swag_remove(process, p_simdata->cond->sleeping);
+  /* If I'm killing myself then stop otherwise schedule the process to kill
+   * Two different behaviors, if I'm killing my self, remove from mutex and condition and stop. Otherwise, first we must schedule the process, wait its ending and after remove it from mutex and condition */
+  if (process == SIMIX_process_self()) {
+    /* Cleanup if we were waiting for something */
+    if (process->mutex)
+      xbt_swag_remove(process, process->mutex->sleeping);
+
+    if (process->cond)
+      xbt_swag_remove(process, process->cond->sleeping);
+    if (process->waiting_action) {
+      SIMIX_unregister_action_to_condition(process->waiting_action, process->cond);
+      SIMIX_action_destroy(process->waiting_action);
+    }
+    SIMIX_context_stop(process->context);
+  } else {
+    DEBUG2("%p here! killing %p", simix_global->current_process, process);
+    SIMIX_process_schedule(process);
+    /* Cleanup if we were waiting for something */
+    if (process->mutex)
+      xbt_swag_remove(process, process->mutex->sleeping);
+
+    if (process->cond) {
+      xbt_swag_remove(process, process->cond->sleeping);
+
+      if (process->waiting_action) {
+        SIMIX_unregister_action_to_condition(process->waiting_action, process->cond);
+        SIMIX_action_destroy(process->waiting_action);
+      }
+    }
 
-  xbt_swag_remove(process, simix_global->process_to_run);
-  xbt_swag_remove(process, simix_global->process_list);
-  DEBUG2("%p here! killing %p", simix_global->current_process, process);
-  xbt_context_kill(process->simdata->context);
+    if (process->sem) {
+       xbt_swag_remove(process, process->sem->sleeping);
 
-  if (process == SIMIX_process_self()) {
-    /* I just killed myself */
-    xbt_context_yield();
+      if (process->waiting_action) {
+       SIMIX_unregister_action_to_semaphore(process->waiting_action, process->sem);
+       SIMIX_action_destroy(process->waiting_action);
+      }
+    }
   }
 }
 
@@ -217,10 +198,9 @@ void SIMIX_process_kill(smx_process_t process)
  * \param process SIMIX process
  * \return A void pointer to the user data
  */
-void *SIMIX_process_get_data(smx_process_t process)
+XBT_INLINE void *SIMIX_process_get_data(smx_process_t process)
 {
   xbt_assert0((process != NULL), "Invalid parameters");
-
   return (process->data);
 }
 
@@ -231,13 +211,11 @@ void *SIMIX_process_get_data(smx_process_t process)
  * \param process SIMIX process
  * \param data User data
  */
-void SIMIX_process_set_data(smx_process_t process, void *data)
+XBT_INLINE void SIMIX_process_set_data(smx_process_t process, void *data)
 {
   xbt_assert0((process != NULL), "Invalid parameters");
-  //xbt_assert0((process->data == NULL), "Data already set");
 
   process->data = data;
-
   return;
 }
 
@@ -248,12 +226,10 @@ void SIMIX_process_set_data(smx_process_t process, void *data)
  * \param process SIMIX process
  * \return SIMIX host
  */
-smx_host_t SIMIX_process_get_host(smx_process_t process)
+XBT_INLINE smx_host_t SIMIX_process_get_host(smx_process_t process)
 {
-  xbt_assert0(((process != NULL)
-               && (process->simdata)), "Invalid parameters");
-
-  return (process->simdata->smx_host);
+  xbt_assert0((process != NULL), "Invalid parameters");
+  return (process->smx_host);
 }
 
 /**
@@ -263,11 +239,9 @@ smx_host_t SIMIX_process_get_host(smx_process_t process)
  * \param process SIMIX process
  * \return The process name
  */
-const char *SIMIX_process_get_name(smx_process_t process)
+XBT_INLINE const char *SIMIX_process_get_name(smx_process_t process)
 {
-  xbt_assert0(((process != NULL)
-               && (process->simdata)), "Invalid parameters");
-
+  xbt_assert0((process != NULL), "Invalid parameters");
   return (process->name);
 }
 
@@ -278,11 +252,9 @@ const char *SIMIX_process_get_name(smx_process_t process)
  * \param process SIMIX process
  * \param name The new process name
  */
-void SIMIX_process_set_name(smx_process_t process, char *name)
+XBT_INLINE void SIMIX_process_set_name(smx_process_t process, char *name)
 {
-  xbt_assert0(((process != NULL)
-               && (process->simdata)), "Invalid parameters");
-
+  xbt_assert0((process != NULL), "Invalid parameters");
   process->name = name;
 }
 
@@ -291,9 +263,9 @@ void SIMIX_process_set_name(smx_process_t process, char *name)
  *
  * This functions returns the properties associated with this process
  */
-xbt_dict_t SIMIX_process_get_properties(smx_process_t process)
+XBT_INLINE xbt_dict_t SIMIX_process_get_properties(smx_process_t process)
 {
-  return process->simdata->properties;
+  return process->properties;
 }
 
 /**
@@ -302,7 +274,7 @@ xbt_dict_t SIMIX_process_get_properties(smx_process_t process)
  * This functions returns the currently running #smx_process_t.
  * \return The SIMIX process
  */
-smx_process_t SIMIX_process_self(void)
+XBT_INLINE smx_process_t SIMIX_process_self(void)
 {
   return simix_global ? simix_global->current_process : NULL;
 }
@@ -317,17 +289,14 @@ smx_process_t SIMIX_process_self(void)
  */
 void SIMIX_process_suspend(smx_process_t process)
 {
-  smx_simdata_process_t simdata = NULL;
-
-  xbt_assert0(((process) && (process->simdata)), "Invalid parameters");
+  xbt_assert0(process, "Invalid parameters");
 
   if (process != SIMIX_process_self()) {
-    simdata = process->simdata;
 
-    if (simdata->mutex) {
+    if (process->mutex) {
       /* process blocked on a mutex, only set suspend=1 */
-      simdata->suspended = 1;
-    } else if (simdata->cond) {
+      process->suspended = 1;
+    } else if (process->cond) {
       /* process blocked cond, suspend all actions */
 
       /* temporaries variables */
@@ -335,28 +304,28 @@ void SIMIX_process_suspend(smx_process_t process)
       xbt_fifo_item_t i;
       smx_action_t act;
 
-      simdata->suspended = 1;
-      c = simdata->cond;
+      process->suspended = 1;
+      c = process->cond;
       xbt_fifo_foreach(c->actions, i, act, smx_action_t) {
-        surf_workstation_model->common_public->suspend(act->
-                                                       simdata->surf_action);
+        surf_workstation_model->suspend(act->surf_action);
       }
     } else {
-      simdata->suspended = 1;
+      process->suspended = 1;
     }
   } else {
     /* process executing, I can create an action and suspend it */
     smx_action_t dummy;
     smx_cond_t cond;
     char name[] = "dummy";
-    process->simdata->suspended = 1;
+    process->suspended = 1;
 
     cond = SIMIX_cond_init();
     dummy = SIMIX_action_execute(SIMIX_process_get_host(process), name, 0);
-    surf_workstation_model->common_public->suspend(dummy->simdata->
-                                                   surf_action);
+    SIMIX_process_self()->waiting_action = dummy;
+    surf_workstation_model->suspend(dummy->surf_action);
     SIMIX_register_action_to_condition(dummy, cond);
     __SIMIX_cond_wait(cond);
+    SIMIX_process_self()->waiting_action = NULL;
     SIMIX_unregister_action_to_condition(dummy, cond);
     SIMIX_action_destroy(dummy);
     SIMIX_cond_destroy(cond);
@@ -372,40 +341,33 @@ void SIMIX_process_suspend(smx_process_t process)
  */
 void SIMIX_process_resume(smx_process_t process)
 {
-  smx_simdata_process_t simdata = NULL;
-
-  xbt_assert0(((process != NULL)
-               && (process->simdata)), "Invalid parameters");
+  xbt_assert0((process != NULL), "Invalid parameters");
   SIMIX_CHECK_HOST();
 
-  if (process == SIMIX_process_self()) {
+  if (process == SIMIX_process_self())
     return;
-  }
 
-  simdata = process->simdata;
-  if (simdata->mutex) {
+  if (process->mutex) {
     DEBUG0("Resume process blocked on a mutex");
-    simdata->suspended = 0;     /* He'll wake up by itself */
+    process->suspended = 0;     /* It'll wake up by itself when mutex releases */
     return;
-  } else if (simdata->cond) {
+  } else if (process->cond) {
     /* temporaries variables */
     smx_cond_t c;
     xbt_fifo_item_t i;
     smx_action_t act;
     DEBUG0("Resume process blocked on a conditional");
-    simdata->suspended = 0;
-    c = simdata->cond;
+    process->suspended = 0;
+    c = process->cond;
     xbt_fifo_foreach(c->actions, i, act, smx_action_t) {
-      surf_workstation_model->common_public->resume(act->simdata->
-                                                    surf_action);
+      surf_workstation_model->resume(act->surf_action);
     }
     SIMIX_cond_signal(c);
     return;
   } else {
-    simdata->suspended = 0;
+    process->suspended = 0;
     xbt_swag_insert(process, simix_global->process_to_run);
   }
-
 }
 
 /**
@@ -416,12 +378,12 @@ void SIMIX_process_resume(smx_process_t process)
 void SIMIX_process_change_host(smx_process_t process, char *source,
                                char *dest)
 {
-  smx_simdata_process_t p_simdata = process->simdata;
+  xbt_assert0((process != NULL), "Invalid parameters");
   smx_host_t h1 = SIMIX_host_get_by_name(source);
   smx_host_t h2 = SIMIX_host_get_by_name(dest);
-  p_simdata->smx_host = h2;
-  xbt_swag_remove(process, h1->simdata->process_list);
-  xbt_swag_insert(process, h2->simdata->process_list);
+  process->smx_host = h2;
+  xbt_swag_remove(process, h1->process_list);
+  xbt_swag_insert(process, h2->process_list);
 }
 
 /**
@@ -431,10 +393,71 @@ void SIMIX_process_change_host(smx_process_t process, char *source,
  * \param process SIMIX process
  * \return 1, if the process is suspended, else 0.
  */
-int SIMIX_process_is_suspended(smx_process_t process)
+XBT_INLINE int SIMIX_process_is_suspended(smx_process_t process)
+{
+  xbt_assert0((process != NULL), "Invalid parameters");
+
+  return (process->suspended);
+}
+
+/**
+ * \brief Returns the amount of SIMIX processes in the system
+ *
+ * Maestro internal process is not counted, only user code processes are
+ */
+XBT_INLINE int SIMIX_process_count()
 {
-  xbt_assert0(((process != NULL)
-               && (process->simdata)), "Invalid parameters");
+  return xbt_swag_size(simix_global->process_list);
+}
+
+/** 
+ * Calling this function makes the process process to yield. The process
+ * that scheduled it returns from __SIMIX_process_schedule as if nothing
+ * had happened.
+ * 
+ * Only the processes can call this function, giving back the control
+ * to the maestro
+ */
+void SIMIX_process_yield(void)
+{
+  DEBUG1("Yield process '%s'", simix_global->current_process->name);
+  xbt_assert0((simix_global->current_process !=
+               simix_global->maestro_process),
+              "You are not supposed to run this function in maestro context!");
+
+  SIMIX_context_suspend(simix_global->current_process->context);
 
-  return (process->simdata->suspended);
+  if (simix_global->current_process->iwannadie)
+    SIMIX_context_stop(simix_global->current_process->context);
+}
+
+void SIMIX_process_schedule(smx_process_t new_process)
+{
+  DEBUG1("Scheduling context: '%s'", new_process->name);
+
+  /* save the current process */
+  smx_process_t old_process = simix_global->current_process;
+
+  /* update the current process */
+  simix_global->current_process = new_process;
+
+  /* schedule the context */
+  SIMIX_context_resume(old_process->context, new_process->context);
+  DEBUG1("Resumed from scheduling context: '%s'", new_process->name);
+
+  /* restore the current process to the previously saved process */
+  simix_global->current_process = old_process;
+}
+
+/* callback: context fetching */
+ex_ctx_t *SIMIX_process_get_exception(void)
+{
+  return simix_global->current_process->exception;
+}
+
+/* callback: termination */
+void SIMIX_process_exception_terminate(xbt_ex_t * e)
+{
+  xbt_ex_display(e);
+  abort();
 }