Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Make sure all the source files have an reference of the copyright and of the licence
[simgrid.git] / src / xbt / xbt_context.c
index ea50160..03ff6d1 100644 (file)
-/* a fast and simple context switching library                              */\r
-\r
-/* Copyright (c) 2004 Arnaud Legrand.                                       */\r
-/* Copyright (c) 2004, 2005 Martin Quinson.                                 */\r
-/* All rights reserved.                                                     */\r
-\r
-/* This program is free software; you can redistribute it and/or modify it\r
- * under the terms of the license (GNU LGPL) which comes with this package. */\r
-\r
-#include "portable.h"\r
-#include "xbt/log.h"\r
-#include "xbt/swag.h"\r
-#include "xbt_context_private.h"\r
-\r
-/* the context associated with the current process                             */\r
-xbt_context_t current_context = NULL;\r
-\r
-/* the context associated with the maestro                                             */\r
-xbt_context_t  maestro_context = NULL;\r
-\r
-\r
-/* this list contains the contexts to destroy                                  */\r
-xbt_swag_t context_to_destroy = NULL;\r
-\r
-/* this list contains the contexts in use                                              */\r
-xbt_swag_t context_living = NULL;\r
-\r
-/* the context factory used to create the appropriate context  \r
- * each context implementation define its own context factory\r
- * a context factory is responsable of the creation of the context\r
- * associated with the maestro and of all the context based on\r
- * the selected implementation.\r
- *\r
- * for example, the context switch based on java thread use the\r
- * java implementation of the context and the java factory build\r
- * the context depending of this implementation.\r
- */\r
-static xbt_context_factory_t\r
-context_factory = NULL;\r
-\r
-/**\r
- * This function is call by the xbt_init() function to initialize the context module.\r
- */\r
-void\r
-xbt_context_mod_init(void)\r
-{\r
-       if(!context_factory)\r
-       {\r
-               /* select context factory to use to create the context(depends of the macro definitions) */\r
-\r
-               #ifdef CONTEXT_THREADS\r
-                       /* context switch based os thread */\r
-                       xbt_ctx_thread_factory_init(&context_factory);\r
-               #elif !defined(WIN32)\r
-                       /* context switch based ucontext */\r
-                       xbt_ctx_sysv_factory_init(&context_factory);\r
-               #else\r
-                       /* context switch is not allowed on Windows */\r
-                       #error ERROR [__FILE__, line __LINE__]: no context based implementation specified.\r
-               #endif\r
-               \r
-               /* maestro context specialisation (this create the maestro with the good implementation */\r
-               (*(context_factory->create_maestro_context))(&maestro_context);\r
-               \r
-               /* the current context is the context of the maestro */\r
-               current_context = maestro_context;\r
-               \r
-               /* the current context doesn't want to die */\r
-               current_context->iwannadie = 0;\r
-               \r
-               /* intantiation of the lists containing the contexts to destroy and the contexts in use */  \r
-               context_to_destroy = xbt_swag_new(xbt_swag_offset(*current_context, hookup));\r
-               context_living = xbt_swag_new(xbt_swag_offset(*current_context, hookup));\r
-               \r
-               /* insert the current context in the list of the contexts in use */\r
-               xbt_swag_insert(current_context, context_living);\r
-               \r
-       }                \r
-} \r
-\r
-/**\r
- * This function is call by the xbt_exit() function to finalize the context module.\r
- */\r
-void\r
-xbt_context_mod_exit(void)\r
-{\r
-       if(context_factory)\r
-       {\r
-               xbt_context_t context = NULL;\r
-               xbt_pfn_context_factory_finalize_t finalize_factory;\r
-               \r
-               /* finalize the context factory */\r
-               finalize_factory = context_factory->finalize;\r
-               \r
-               (*finalize_factory)(&context_factory);\r
-               \r
-               /* destroy all contexts in the list of contexts to destroy */\r
-               xbt_context_empty_trash();\r
-               \r
-               /* remove the context of the scheduler from the list of the contexts in use */\r
-               xbt_swag_remove(maestro_context, context_living);\r
-               \r
-               /*  \r
-                * kill all the contexts in use :\r
-                * the killed contexts are added in the list of the contexts to destroy\r
-                */\r
-               while((context = xbt_swag_extract(context_living))) \r
-                               (*(context->kill))(context);    \r
-       \r
-               \r
-               /* destroy all contexts in the list of contexts to destroy */\r
-               xbt_context_empty_trash();\r
-               \r
-               free(maestro_context);\r
-               maestro_context = current_context = NULL;\r
-               \r
-               /* destroy the lists */\r
-               xbt_swag_free(context_to_destroy);\r
-               xbt_swag_free(context_living);\r
-       }\r
-}\r
-\r
-/*******************************/\r
-/* Object creation/destruction */\r
-/*******************************/\r
-/** \r
- * \param code a main function\r
- * \param startup_func a function to call when running the context for\r
- *      the first time and just before the main function \a code\r
- * \param startup_arg the argument passed to the previous function (\a startup_func)\r
- * \param cleanup_func a function to call when running the context, just after \r
-        the termination of the main function \a code\r
- * \param cleanup_arg the argument passed to the previous function (\a cleanup_func)\r
- * \param argc first argument of function \a code\r
- * \param argv seconde argument of function \a code\r
- */\r
-xbt_context_t\r
-xbt_context_new(const char *name,\r
-                xbt_main_func_t code,\r
-                void_f_pvoid_t startup_func,\r
-                void *startup_arg,\r
-                void_f_pvoid_t cleanup_func,\r
-                void *cleanup_arg, int argc, char *argv[]\r
-)\r
-{\r
-       /* use the appropriate context factory to create the appropriate context */\r
-       xbt_context_t context = (*(context_factory->create_context))(name, code, startup_func, startup_arg, cleanup_func, cleanup_arg, argc, argv);\r
-       \r
-       /* add the context in the list of the contexts in use */\r
-       xbt_swag_insert(context, context_living);\r
-\r
-       return context;\r
-}\r
-\r
-/* Scenario for the end of a context:\r
- * \r
- * CASE 1: death after end of function\r
- *   __context_wrapper, called by os thread, calls xbt_context_stop after user code stops\r
- *   xbt_context_stop calls user cleanup_func if any (in context settings),\r
- *                    add current to trashbin\r
- *                    yields back to maestro (destroy os thread on need)\r
- *   From time to time, maestro calls xbt_context_empty_trash, \r
- *       which maps xbt_context_free on the content\r
- *   xbt_context_free frees some more memory, \r
- *                    joins os thread\r
- * \r
- * CASE 2: brutal death\r
- *   xbt_context_kill (from any context)\r
- *                    set context->wannadie to 1\r
- *                    yields to the context\r
- *   the context is awaken in the middle of __yield. \r
- *   At the end of it, it checks that wannadie == 1, and call xbt_context_stop\r
- *   (same than first case afterward)\r
- */\r
-\r
-\r
-/* Argument must be stopped first -- runs in maestro context */\r
-void\r
-xbt_context_free(xbt_context_t context)\r
-{\r
-       (*(context->free))(context);    \r
-}\r
-\r
-\r
-void\r
-xbt_context_kill(xbt_context_t context)\r
-{\r
-       (*(context->kill))(context);    \r
-}\r
-\r
-/** \r
- * \param context the context to start\r
- * \r
- * Calling this function prepares \a context to be run. It will \r
-   however run effectively only when calling #xbt_context_schedule\r
- */\r
-void\r
-xbt_context_start(xbt_context_t context)\r
-{\r
-       (*(context->start))(context);\r
-}\r
-\r
-/** \r
- * Calling this function makes the current context yield. The context\r
- * that scheduled it returns from xbt_context_schedule as if nothing\r
- * had happened.\r
- * \r
- * Only the processes can call this function, giving back the control\r
- * to the maestro\r
- */\r
-void\r
-xbt_context_yield(void)\r
-{\r
-       (*(current_context->yield))();  \r
-}\r
-\r
-/** \r
- * \param context the winner\r
- *\r
- * Calling this function blocks the current context and schedule \a context.  \r
- * When \a context will call xbt_context_yield, it will return\r
- * to this function as if nothing had happened.\r
- * \r
- * Only the maestro can call this function to run a given process.\r
- */\r
-void\r
-xbt_context_schedule(xbt_context_t context)\r
-{\r
-       (*(context->schedule))(context);        \r
-}\r
-\r
-void\r
-xbt_context_stop(int exit_code)\r
-{\r
-\r
-       (*(current_context->stop))(exit_code);\r
-}\r
-\r
-int\r
-xbt_context_select_factory(const char* name)\r
-{\r
-       /* if a factory is already instantiated (xbt_context_mod_init() was called) */\r
-       if(NULL != context_factory)\r
-       {\r
-               /* if the desired factory is different of the current factory, call xbt_context_mod_exit() */\r
-               if(strcmp(context_factory->name,name))\r
-               {\r
-                       xbt_context_mod_exit();\r
-                               \r
-               }\r
-               else\r
-               {\r
-                       /* the same context factory is requested return directly */\r
-                       return 0;\r
-               }\r
-       }\r
-       \r
-       /* get the desired factory */\r
-       xbt_context_init_factory_by_name(&context_factory,name);\r
-       \r
-       /* maestro context specialisation */\r
-       (*(context_factory->create_maestro_context))(&maestro_context);\r
-       \r
-       /* the current context is the context of the maestro */\r
-       current_context = maestro_context;\r
-       \r
-       /* the current context doesn't want to die */\r
-       current_context->iwannadie = 0;\r
-       \r
-       /* intantiation of the lists containing the contexts to destroy and the contexts in use */  \r
-       context_to_destroy = xbt_swag_new(xbt_swag_offset(*current_context, hookup));\r
-       context_living = xbt_swag_new(xbt_swag_offset(*current_context, hookup));\r
-       \r
-       /* insert the current context in the list of the contexts in use */\r
-       xbt_swag_insert(current_context, context_living);       \r
-       \r
-       return 0;       \r
-}\r
-\r
-int\r
-xbt_context_init_factory_by_name(xbt_context_factory_t* factory, const char* name)\r
-{\r
-       if(!strcmp(name,"java"))\r
-       {\r
-               return xbt_ctx_java_factory_init(factory);      \r
-       }\r
-       #ifdef CONTEXT_THREADS\r
-       else if(!strcmp(name,"thread")) \r
-       {\r
-               return xbt_ctx_thread_factory_init(factory);    \r
-       }\r
-       #elif !defined(WIN32)\r
-       else if(!strcmp(name,"sysv"))\r
-       {\r
-               return xbt_ctx_sysv_factory_init(factory);      \r
-       }\r
-       #endif\r
-       \r
-       return EINVAL;\r
-}\r
-\r
-/** Garbage collection\r
- *\r
- * Should be called some time to time to free the memory allocated for contexts\r
- * that have finished executing their main functions.\r
- */\r
-void \r
-xbt_context_empty_trash(void)\r
-{\r
-       xbt_context_t context = NULL;\r
-       \r
-       while((context = xbt_swag_extract(context_to_destroy)))\r
-               (*(context->free))(context);\r
-}\r
-\r
-\r
-\r
+/* a fast and simple context switching library                              */
+
+/* Copyright (c) 2004-2008 the SimGrid team.                                */
+/* All rights reserved.                                                     */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "portable.h"
+#include "xbt/log.h"
+#include "xbt/swag.h"
+#include "xbt_context_private.h"
+
+/* the context associated with the current process                             */
+xbt_context_t current_context = NULL;
+
+/* the context associated with the maestro                                             */
+xbt_context_t maestro_context = NULL;
+
+
+/* this list contains the contexts to destroy                                  */
+xbt_swag_t context_to_destroy = NULL;
+
+/* this list contains the contexts in use                                              */
+xbt_swag_t context_living = NULL;
+
+/* the context factory used to create the appropriate context  
+ * each context implementation define its own context factory
+ * a context factory is responsable of the creation of the context
+ * associated with the maestro and of all the context based on
+ * the selected implementation.
+ *
+ * for example, the context switch based on java thread use the
+ * java implementation of the context and the java factory build
+ * the context depending of this implementation.
+ */
+static xbt_context_factory_t context_factory = NULL;
+
+/**
+ * This function is call by the xbt_init() function to initialize the context module.
+ */
+void xbt_context_mod_init(void)
+{
+  if (!context_factory) {
+    /* select context factory to use to create the context(depends of the macro definitions) */
+
+#ifdef CONTEXT_THREADS
+    /* context switch based os thread */
+    xbt_ctx_thread_factory_init(&context_factory);
+#elif !defined(WIN32)
+    /* context switch based ucontext */
+    xbt_ctx_sysv_factory_init(&context_factory);
+#else
+    /* context switch is not allowed on Windows */
+#error ERROR [__FILE__, line __LINE__]: no context based implementation specified.
+#endif
+
+    /* maestro context specialisation (this create the maestro with the good implementation */
+    (*(context_factory->create_maestro_context)) (&maestro_context);
+
+    /* the current context is the context of the maestro */
+    current_context = maestro_context;
+
+    /* the current context doesn't want to die */
+    current_context->iwannadie = 0;
+
+    /* intantiation of the lists containing the contexts to destroy and the contexts in use */
+    context_to_destroy =
+      xbt_swag_new(xbt_swag_offset(*current_context, hookup));
+    context_living = xbt_swag_new(xbt_swag_offset(*current_context, hookup));
+
+    /* insert the current context in the list of the contexts in use */
+    xbt_swag_insert(current_context, context_living);
+
+  }
+}
+
+/**
+ * This function is call by the xbt_exit() function to finalize the context module.
+ */
+void xbt_context_mod_exit(void)
+{
+  if (context_factory) {
+    xbt_context_t context = NULL;
+    xbt_pfn_context_factory_finalize_t finalize_factory;
+
+    /* finalize the context factory */
+    finalize_factory = context_factory->finalize;
+
+    (*finalize_factory) (&context_factory);
+
+    /* destroy all contexts in the list of contexts to destroy */
+    xbt_context_empty_trash();
+
+    /* remove the context of the scheduler from the list of the contexts in use */
+    xbt_swag_remove(maestro_context, context_living);
+
+    /*  
+     * kill all the contexts in use :
+     * the killed contexts are added in the list of the contexts to destroy
+     */
+    while ((context = xbt_swag_extract(context_living)))
+      (*(context->kill)) (context);
+
+
+    /* destroy all contexts in the list of contexts to destroy */
+    xbt_context_empty_trash();
+
+    free(maestro_context);
+    maestro_context = current_context = NULL;
+
+    /* destroy the lists */
+    xbt_swag_free(context_to_destroy);
+    xbt_swag_free(context_living);
+  }
+}
+
+/*******************************/
+/* Object creation/destruction */
+/*******************************/
+/** 
+ * \param code a main function
+ * \param startup_func a function to call when running the context for
+ *      the first time and just before the main function \a code
+ * \param startup_arg the argument passed to the previous function (\a startup_func)
+ * \param cleanup_func a function to call when running the context, just after 
+        the termination of the main function \a code
+ * \param cleanup_arg the argument passed to the previous function (\a cleanup_func)
+ * \param argc first argument of function \a code
+ * \param argv seconde argument of function \a code
+ */
+xbt_context_t
+xbt_context_new(const char *name,
+                xbt_main_func_t code,
+                void_f_pvoid_t startup_func,
+                void *startup_arg,
+                void_f_pvoid_t cleanup_func,
+                void *cleanup_arg, int argc, char *argv[]
+  )
+{
+  /* use the appropriate context factory to create the appropriate context */
+  xbt_context_t context =
+    (*(context_factory->create_context)) (name, code, startup_func,
+                                          startup_arg, cleanup_func,
+                                          cleanup_arg, argc, argv);
+
+  /* add the context in the list of the contexts in use */
+  xbt_swag_insert(context, context_living);
+
+  return context;
+}
+
+/* Scenario for the end of a context:
+ * 
+ * CASE 1: death after end of function
+ *   __context_wrapper, called by os thread, calls xbt_context_stop after user code stops
+ *   xbt_context_stop calls user cleanup_func if any (in context settings),
+ *                    add current to trashbin
+ *                    yields back to maestro (destroy os thread on need)
+ *   From time to time, maestro calls xbt_context_empty_trash, 
+ *       which maps xbt_context_free on the content
+ *   xbt_context_free frees some more memory, 
+ *                    joins os thread
+ * 
+ * CASE 2: brutal death
+ *   xbt_context_kill (from any context)
+ *                    set context->wannadie to 1
+ *                    yields to the context
+ *   the context is awaken in the middle of __yield. 
+ *   At the end of it, it checks that wannadie == 1, and call xbt_context_stop
+ *   (same than first case afterward)
+ */
+
+
+/* Argument must be stopped first -- runs in maestro context */
+void xbt_context_free(xbt_context_t context)
+{
+  (*(context->free)) (context);
+}
+
+
+void xbt_context_kill(xbt_context_t context)
+{
+  (*(context->kill)) (context);
+}
+
+/** 
+ * \param context the context to start
+ * 
+ * Calling this function prepares \a context to be run. It will 
+   however run effectively only when calling #xbt_context_schedule
+ */
+void xbt_context_start(xbt_context_t context)
+{
+  (*(context->start)) (context);
+}
+
+/** 
+ * Calling this function makes the current context yield. The context
+ * that scheduled it returns from xbt_context_schedule as if nothing
+ * had happened.
+ * 
+ * Only the processes can call this function, giving back the control
+ * to the maestro
+ */
+void xbt_context_yield(void)
+{
+  (*(current_context->yield)) ();
+}
+
+/** 
+ * \param context the winner
+ *
+ * Calling this function blocks the current context and schedule \a context.  
+ * When \a context will call xbt_context_yield, it will return
+ * to this function as if nothing had happened.
+ * 
+ * Only the maestro can call this function to run a given process.
+ */
+void xbt_context_schedule(xbt_context_t context)
+{
+  (*(context->schedule)) (context);
+}
+
+void xbt_context_stop(int exit_code)
+{
+
+  (*(current_context->stop)) (exit_code);
+}
+
+int xbt_context_select_factory(const char *name)
+{
+  /* if a factory is already instantiated (xbt_context_mod_init() was called) */
+  if (NULL != context_factory) {
+    /* if the desired factory is different of the current factory, call xbt_context_mod_exit() */
+    if (strcmp(context_factory->name, name))
+      xbt_context_mod_exit();
+    else
+      /* the same context factory is requested return directly */
+      return 0;
+  }
+
+  /* get the desired factory */
+  xbt_context_init_factory_by_name(&context_factory, name);
+
+  /* maestro context specialisation */
+  (*(context_factory->create_maestro_context)) (&maestro_context);
+
+  /* the current context is the context of the maestro */
+  current_context = maestro_context;
+
+  /* the current context doesn't want to die */
+  current_context->iwannadie = 0;
+
+  /* intantiation of the lists containing the contexts to destroy and the contexts in use */
+  context_to_destroy =
+    xbt_swag_new(xbt_swag_offset(*current_context, hookup));
+  context_living = xbt_swag_new(xbt_swag_offset(*current_context, hookup));
+
+  /* insert the current context in the list of the contexts in use */
+  xbt_swag_insert(current_context, context_living);
+
+  return 0;
+}
+
+void
+xbt_context_init_factory_by_name(xbt_context_factory_t * factory,
+                                 const char *name)
+{
+  if (!strcmp(name, "java"))
+    xbt_ctx_java_factory_init(factory);
+#ifdef CONTEXT_THREADS
+  else if (!strcmp(name, "thread"))
+    xbt_ctx_thread_factory_init(factory);
+#elif !defined(WIN32)
+  else if (!strcmp(name, "sysv"))
+    xbt_ctx_sysv_factory_init(factory);
+#endif
+  else
+    THROW1(not_found_error, 0, "Factory '%s' does not exist", name);
+}
+
+/** Garbage collection
+ *
+ * Should be called some time to time to free the memory allocated for contexts
+ * that have finished executing their main functions.
+ */
+void xbt_context_empty_trash(void)
+{
+  xbt_context_t context = NULL;
+
+  while ((context = xbt_swag_extract(context_to_destroy)))
+    (*(context->free)) (context);
+}