Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
The file containing the new implementation of the switch context mechanism.
[simgrid.git] / src / xbt / xbt_context.c
diff --git a/src/xbt/xbt_context.c b/src/xbt/xbt_context.c
new file mode 100644 (file)
index 0000000..418b125
--- /dev/null
@@ -0,0 +1,333 @@
+/* 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_factory.h"\r
+\r
+/* the context associated with the current process                             */\r
+static xbt_context_t \r
+current_context = NULL;\r
+\r
+/* the context associated with the maestro                                             */\r
+static xbt_context_t \r
+maestro_context = NULL;\r
+\r
+\r
+/* this list contains the contexts to destroy                                  */\r
+static xbt_swag_t \r
+context_to_destroy = NULL;\r
+\r
+/* this list contains the contexts in use                                              */\r
+static xbt_swag_t \r
+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
+/* java implementation of the context */\r
+#include "xbt_jcontext.c"\r
+\r
+#ifdef CONTEXT_THREADS\r
+/* use the native thread implementation of the context */\r
+#include "xbt_thread_context.c"\r
+#elif !defined(WIN32)\r
+/* use the ucontext    based context           */\r
+#  include "xbt_ucontext.c" \r
+#endif \r
+\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_thread_context_factory_init(&context_factory);\r
+               #elif !defined(WIN32)\r
+                       /* context switch based ucontext */\r
+                       xbt_ucontext_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
+               free(maestro_context);\r
+               maestro_context = current_context = NULL;\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
+               /* 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,"jcontext_factory"))\r
+       {\r
+               return xbt_jcontext_factory_init(factory);      \r
+       }\r
+       #ifdef CONTEXT_THREADS\r
+       else if(!strcmp(name,"thread_context_factory")) \r
+       {\r
+               return xbt_thread_context_factory_init(factory);        \r
+       }\r
+       #elif !defined(WIN32)\r
+       else if(!strcmp(name,"ucontext_context_factory"))       \r
+       {\r
+               return xbt_ucontext_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