From 8be93beba0c7547303f5a102c2cb528b8c586066 Mon Sep 17 00:00:00 2001 From: cherierm Date: Thu, 15 Nov 2007 18:23:30 +0000 Subject: [PATCH] The file containing the new implementation of the switch context mechanism. git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/simgrid/simgrid/trunk@5043 48e7efb5-ca39-0410-a469-dd3cf9ba447f --- include/xbt/xbt_context.h | 39 ++++ src/xbt/xbt_context.c | 333 ++++++++++++++++++++++++++++++++++ src/xbt/xbt_context_factory.h | 56 ++++++ src/xbt/xbt_context_private.h | 57 ++++++ src/xbt/xbt_jcontext.c | 279 ++++++++++++++++++++++++++++ src/xbt/xbt_jcontext.h | 35 ++++ src/xbt/xbt_thread_context.c | 298 ++++++++++++++++++++++++++++++ src/xbt/xbt_thread_context.h | 34 ++++ src/xbt/xbt_ucontext.c | 288 +++++++++++++++++++++++++++++ src/xbt/xbt_ucontext.h | 27 +++ 10 files changed, 1446 insertions(+) create mode 100644 include/xbt/xbt_context.h create mode 100644 src/xbt/xbt_context.c create mode 100644 src/xbt/xbt_context_factory.h create mode 100644 src/xbt/xbt_context_private.h create mode 100644 src/xbt/xbt_jcontext.c create mode 100644 src/xbt/xbt_jcontext.h create mode 100644 src/xbt/xbt_thread_context.c create mode 100644 src/xbt/xbt_thread_context.h create mode 100644 src/xbt/xbt_ucontext.c create mode 100644 src/xbt/xbt_ucontext.h diff --git a/include/xbt/xbt_context.h b/include/xbt/xbt_context.h new file mode 100644 index 0000000000..9190d583b1 --- /dev/null +++ b/include/xbt/xbt_context.h @@ -0,0 +1,39 @@ +#ifndef XBT_CONTEXT_H +#define XBT_CONTEXT_H + +#include "xbt/misc.h" /* XBT_PUBLIC(), SG_BEGIN_DECL() and SG_END_DECL() definitions */ +#include "xbt/function_types.h" /* function pointer types declarations */ +#include "xbt_modinter.h" /* xbt_context_init() and xbt_context_exit() declarations */ + +SG_BEGIN_DECL() + +typedef struct s_xbt_context* xbt_context_t; + +XBT_PUBLIC(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[]); + +XBT_PUBLIC(void) +xbt_context_kill(xbt_context_t context); + +XBT_PUBLIC(void) +xbt_context_start(xbt_context_t context); + +XBT_PUBLIC(void) +xbt_context_yield(void); + +XBT_PUBLIC(void) +xbt_context_schedule(xbt_context_t context); + +void +xbt_context_empty_trash(void); + +void +xbt_context_stop(int exit_code); + +void +xbt_context_free(xbt_context_t context); + + +SG_END_DECL() + +#endif /* !XBT_CONTEXT_H */ diff --git a/src/xbt/xbt_context.c b/src/xbt/xbt_context.c new file mode 100644 index 0000000000..418b125820 --- /dev/null +++ b/src/xbt/xbt_context.c @@ -0,0 +1,333 @@ +/* a fast and simple context switching library */ + +/* Copyright (c) 2004 Arnaud Legrand. */ +/* Copyright (c) 2004, 2005 Martin Quinson. */ +/* 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_factory.h" + +/* the context associated with the current process */ +static xbt_context_t +current_context = NULL; + +/* the context associated with the maestro */ +static xbt_context_t +maestro_context = NULL; + + +/* this list contains the contexts to destroy */ +static xbt_swag_t +context_to_destroy = NULL; + +/* this list contains the contexts in use */ +static 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; + +/* java implementation of the context */ +#include "xbt_jcontext.c" + +#ifdef CONTEXT_THREADS +/* use the native thread implementation of the context */ +#include "xbt_thread_context.c" +#elif !defined(WIN32) +/* use the ucontext based context */ +# include "xbt_ucontext.c" +#endif + + +/** + * 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_thread_context_factory_init(&context_factory); + #elif !defined(WIN32) + /* context switch based ucontext */ + xbt_ucontext_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); + + free(maestro_context); + maestro_context = current_context = NULL; + + /* + * 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(); + + /* 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; +} + +int +xbt_context_init_factory_by_name(xbt_context_factory_t* factory, const char* name) +{ + if(!strcmp(name,"jcontext_factory")) + { + return xbt_jcontext_factory_init(factory); + } + #ifdef CONTEXT_THREADS + else if(!strcmp(name,"thread_context_factory")) + { + return xbt_thread_context_factory_init(factory); + } + #elif !defined(WIN32) + else if(!strcmp(name,"ucontext_context_factory")) + { + return xbt_ucontext_factory_init(factory); + } + #endif + + return EINVAL; +} + +/** 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); +} + + + diff --git a/src/xbt/xbt_context_factory.h b/src/xbt/xbt_context_factory.h new file mode 100644 index 0000000000..b6f1a99ffc --- /dev/null +++ b/src/xbt/xbt_context_factory.h @@ -0,0 +1,56 @@ +#ifndef _XBT_CONTEXT_FACTORY_H +#define _XBT_CONTEXT_FACTORY_H + +#include "portable.h" +#include "xbt/function_types.h" +#include "xbt_context_private.h" + +SG_BEGIN_DECL() + +/* forward declaration */ +struct s_xbt_context_factory; + +/* this function describes the interface that all context factory must implement */ +typedef xbt_context_t (*xbt_pfn_context_factory_create_context_t)(const char*, xbt_main_func_t, void_f_pvoid_t, void*, void_f_pvoid_t, void*, int, char**); +typedef int (*xbt_pfn_context_factory_create_maestro_context_t)(xbt_context_t*); + +/* this function finalize the specified context factory */ +typedef int (*xbt_pfn_context_factory_finalize_t)(struct s_xbt_context_factory**); + +/* this interface is used by the xbt context module to create the appropriate concept */ +typedef struct s_xbt_context_factory +{ + xbt_pfn_context_factory_create_maestro_context_t create_maestro_context; /* create the context of the maestro */ + xbt_pfn_context_factory_create_context_t create_context; /* create a new context */ + xbt_pfn_context_factory_finalize_t finalize; /* finalize the context factory */ + const char* name; /* the name of the context factory */ + +}s_xbt_context_factory_t; + +#ifndef _XBT_CONTEXT_FACTORY_T_DEFINED +typedef struct s_xbt_context_factory* xbt_context_factory_t; +#define _XBT_CONTEXT_FACTORY_T_DEFINED +#endif /* !_XBT_CONTEXT_FACTORY_T_DEFINED */ + +/** + * This function select a context factory associated with the name specified by + * the parameter name. + * If successful the function returns 0. Otherwise the function returns the error + * code. + */ +int +xbt_context_select_factory(const char* name); + +/** + * This function initialize a context factory from the name specified by the parameter + * name. + * If successful the factory specified by the parameter factory is initialized and the + * function returns 0. Otherwise the function returns the error code. + */ +int +xbt_context_init_factory_by_name(xbt_context_factory_t* factory, const char* name); + + +SG_END_DECL() + +#endif /* !_XBT_CONTEXT_FACTORY_H */ diff --git a/src/xbt/xbt_context_private.h b/src/xbt/xbt_context_private.h new file mode 100644 index 0000000000..5e061e4b5a --- /dev/null +++ b/src/xbt/xbt_context_private.h @@ -0,0 +1,57 @@ +#ifndef _XBT_CONTEXT_PRIVATE_H +#define _XBT_CONTEXT_PRIVATE_H + +#include "xbt/sysdep.h" +#include "xbt/xbt_context.h" + +SG_BEGIN_DECL() + +/* the following function pointers describe the interface that all context concepts must implement */ + +typedef void (*xbt_pfn_context_free_t)(xbt_context_t); /* pointer type to the function used to destroy the specified context */ +typedef void (*xbt_pfn_context_kill_t)(xbt_context_t); /* pointer type to the function used to kill the specified context */ +typedef void (*xbt_pfn_context_schedule_t)(xbt_context_t); /* pointer type to the function used to resume the specified context */ +typedef void (*xbt_pfn_context_yield_t)(void); /* pointer type to the function used to yield the specified context */ +typedef void (*xbt_pfn_context_start_t)(xbt_context_t); /* pointer type to the function used to start the specified context */ +typedef void (*xbt_pfn_context_stop_t)(int); /* pointer type to the function used to stop the current context */ + +/* each context concept must use this macro in its declaration */ +#define XBT_CTX_BASE_T \ + s_xbt_swag_hookup_t hookup; \ + char *name; \ + void_f_pvoid_t cleanup_func; \ + void *cleanup_arg; \ + ex_ctx_t *exception; \ + int iwannadie; \ + xbt_main_func_t code; \ + int argc; \ + char **argv; \ + void_f_pvoid_t startup_func; \ + void *startup_arg; \ + xbt_pfn_context_free_t free; \ + xbt_pfn_context_kill_t kill; \ + xbt_pfn_context_schedule_t schedule; \ + xbt_pfn_context_yield_t yield; \ + xbt_pfn_context_start_t start; \ + xbt_pfn_context_stop_t stop + +/* all other contexts derive from this structure */ +typedef struct s_xbt_context +{ + XBT_CTX_BASE_T; +}s_xbt_context_t; + +SG_END_DECL() + + +#ifdef CONTEXT_THREADS +#include "xbt_thread_context.h" /* thread based context declarations */ +#elif !defined(WIN32) +#include "xbt_ucontext.h" /* ucontext based context declarations */ +#else +#error ERROR [__FILE__, line __LINE__]: no context based implementation specified. +#endif + +#include "xbt_jcontext.h" /* java thread based context declarations */ + +#endif /* !_XBT_CONTEXT_PRIVATE_H */ diff --git a/src/xbt/xbt_jcontext.c b/src/xbt/xbt_jcontext.c new file mode 100644 index 0000000000..b6e92d72af --- /dev/null +++ b/src/xbt/xbt_jcontext.c @@ -0,0 +1,279 @@ + + +#include "xbt/function_types.h" +#include "xbt/ex_interface.h" + +XBT_LOG_NEW_DEFAULT_CATEGORY(jmsg,"MSG for Java(TM)"); + +#include "java/jmsg.c" +#include "java/jmsg_channel.c" +#include "java/jmsg_host.c" +#include "java/jmsg_parallel_task.c" +#include "java/jmsg_task.c" +#include "java/jxbt_utilities.c" +#include "java/jmsg_process.c" + + +/* callback: context fetching */ +static ex_ctx_t* +xbt_jcontext_ex_ctx(void); + +/* callback: termination */ +static void +xbt_jcontext_ex_terminate(xbt_ex_t *e); + +static xbt_context_t +xbt_jcontext_factory_create_context(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); + +static int +xbt_jcontext_factory_create_maestro_context(xbt_context_t* maestro); + +static int +xbt_jcontext_factory_finalize(xbt_context_factory_t* factory); + +static void +xbt_jcontext_free(xbt_context_t context); + +static void +xbt_jcontext_kill(xbt_context_t context); + +static void +xbt_jcontext_schedule(xbt_context_t context); + +static void +xbt_jcontext_yield(void); + +static void +xbt_jcontext_start(xbt_context_t context); + +static void +xbt_jcontext_stop(int exit_code); + +static void +xbt_jcontext_swap(xbt_context_t context); + +static void +xbt_jcontext_schedule(xbt_context_t context); + +static void +xbt_jcontext_yield(void); + +static void +xbt_jcontext_suspend(xbt_context_t context); + +static void +xbt_jcontext_resume(xbt_context_t context); + + +/* callback: context fetching */ +static ex_ctx_t* +xbt_jcontext_ex_ctx(void) +{ + return current_context->exception; +} + +/* callback: termination */ +static void +xbt_jcontext_ex_terminate(xbt_ex_t *e) +{ + xbt_ex_display(e); + abort(); +} + +int +xbt_jcontext_factory_init(xbt_context_factory_t* factory) +{ + /* context exception handlers */ + __xbt_ex_ctx = xbt_jcontext_ex_ctx; + __xbt_ex_terminate = xbt_jcontext_ex_terminate; + + /* instantiate the context factory */ + *factory = xbt_new0(s_xbt_context_factory_t,1); + + (*factory)->create_context = xbt_jcontext_factory_create_context; + (*factory)->finalize = xbt_jcontext_factory_finalize; + (*factory)->create_maestro_context = xbt_jcontext_factory_create_maestro_context; + (*factory)->name = "jcontext_factory"; + + return 0; +} + +static int +xbt_jcontext_factory_create_maestro_context(xbt_context_t* maestro) +{ + xbt_jcontext_t context = xbt_new0(s_xbt_jcontext_t, 1); + + context->exception = xbt_new(ex_ctx_t,1); + XBT_CTX_INITIALIZE(context->exception); + + *maestro = (xbt_context_t)context; + + return 0; +} + +static int +xbt_jcontext_factory_finalize(xbt_context_factory_t* factory) +{ + free(maestro_context->exception); + free(*factory); + *factory = NULL; + + return 0; +} + +static xbt_context_t +xbt_jcontext_factory_create_context(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) +{ + xbt_jcontext_t context = xbt_new0(s_xbt_jcontext_t,1); + + context->name = xbt_strdup(name); + + context->cleanup_func = cleanup_func; + context->cleanup_arg = cleanup_arg; + + context->exception = xbt_new(ex_ctx_t,1); + XBT_CTX_INITIALIZE(context->exception); + + context->free = xbt_jcontext_free; + context->kill = xbt_jcontext_kill; + context->schedule = xbt_jcontext_schedule; + context->yield = xbt_jcontext_yield; + context->start = xbt_jcontext_start; + context->stop = xbt_jcontext_stop; + context->jprocess = (jobject)startup_arg; + context->jenv = get_current_thread_env(); + + return (xbt_context_t)context; +} + +static void +xbt_jcontext_free(xbt_context_t context) +{ + if(context) + { + xbt_jcontext_t jcontext = (xbt_jcontext_t)context; + + free(jcontext->name); + + if(jcontext->jprocess) + { + jobject jprocess = jcontext->jprocess; + jcontext->jprocess = NULL; + + /* if the java process is alive join it */ + if(jprocess_is_alive(jprocess,get_current_thread_env())) + jprocess_join(jprocess,get_current_thread_env()); + } + + if(jcontext->exception) + free(jcontext->exception); + + free(context); + context = NULL; + } +} + +static void +xbt_jcontext_kill(xbt_context_t context) +{ + context->iwannadie = 1; + xbt_jcontext_swap(context); +} + +/** + * \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. + */ +static void +xbt_jcontext_schedule(xbt_context_t context) +{ + xbt_assert0((current_context == maestro_context),"You are not supposed to run this function here!"); + xbt_jcontext_swap(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 + */ +static void +xbt_jcontext_yield(void) +{ + xbt_assert0((current_context != maestro_context),"You are not supposed to run this function here!"); + jprocess_unschedule(current_context); +} + +static void +xbt_jcontext_start(xbt_context_t context) +{ + jprocess_start(((xbt_jcontext_t)context)->jprocess,get_current_thread_env()); +} + +static void +xbt_jcontext_stop(int exit_code) +{ + jobject jprocess = NULL; + xbt_jcontext_t jcontext; + + if(current_context->cleanup_func) + (*(current_context->cleanup_func))(current_context->cleanup_arg); + + xbt_swag_remove(current_context, context_living); + xbt_swag_insert(current_context, context_to_destroy); + + jcontext = (xbt_jcontext_t)current_context; + + if(jcontext->iwannadie) + { + /* The maestro call xbt_context_stop() with an exit code set to one */ + if(jcontext->jprocess) + { + /* if the java process is alive schedule it */ + if(jprocess_is_alive(jcontext->jprocess,get_current_thread_env())) + { + jprocess_schedule(current_context); + jprocess = jcontext->jprocess; + jcontext->jprocess = NULL; + + /* interrupt the java process */ + jprocess_exit(jprocess,get_current_thread_env()); + + } + } + } + else + { + /* the java process exits */ + jprocess = jcontext->jprocess; + jcontext->jprocess = NULL; + } + + /* delete the global reference associated with the java process */ + jprocess_delete_global_ref(jprocess,get_current_thread_env()); +} + +static void +xbt_jcontext_swap(xbt_context_t context) +{ + if(context) + { + xbt_context_t self = current_context; + + current_context = context; + + jprocess_schedule(context); + + current_context = self; + } + + if(current_context->iwannadie) + xbt_jcontext_stop(1); +} diff --git a/src/xbt/xbt_jcontext.h b/src/xbt/xbt_jcontext.h new file mode 100644 index 0000000000..f3c1042e0e --- /dev/null +++ b/src/xbt/xbt_jcontext.h @@ -0,0 +1,35 @@ +#ifndef _XBT_JCONTEXT_H +#define _XBT_JCONTEXT_H + +#include /* use java native interface to bind the msg structures to the java instances */ +#include "portable.h" +#include "xbt/misc.h" + +#ifndef _XBT_CONTEXT_PRIVATE_H +#include "xbt_context_private.h" +#endif /* _XBT_CONTEXT_PRIVATE_H */ + +SG_BEGIN_DECL() + +#ifndef _XBT_CONTEXT_FACTORY_T_DEFINED +typedef struct s_xbt_context_factory* xbt_context_factory_t; +#define _XBT_CONTEXT_FACTORY_T_DEFINED +#endif /* !_XBT_CONTEXT_FACTORY_T_DEFINED */ + +typedef struct s_xbt_jcontext +{ + XBT_CTX_BASE_T; + jobject jprocess; /* the java process instance binded with the msg process structure */ + JNIEnv* jenv; /* jni interface pointer associated to this thread */ +}s_xbt_jcontext_t,* xbt_jcontext_t; + +int +xbt_jcontext_factory_init(xbt_context_factory_t* factory); + + +SG_END_DECL() + + + + +#endif /* !_XBT_JCONTEXT_H */ diff --git a/src/xbt/xbt_thread_context.c b/src/xbt/xbt_thread_context.c new file mode 100644 index 0000000000..fb8307b89e --- /dev/null +++ b/src/xbt/xbt_thread_context.c @@ -0,0 +1,298 @@ + +#include "xbt/function_types.h" + +static xbt_context_t +xbt_thread_context_factory_create_context(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); + + +static int +xbt_thread_context_factory_create_master_context(xbt_context_t* maestro); + +static int +xbt_thread_context_factory_finalize(xbt_context_factory_t* factory); + +static void +xbt_thread_context_free(xbt_context_t context); + +static void +xbt_thread_context_kill(xbt_context_t context); + +static void +xbt_thread_context_schedule(xbt_context_t context); + +static void +xbt_thread_context_yield(void); + +static void +xbt_thread_context_start(xbt_context_t context); + +static void +xbt_thread_context_stop(int exit_code); + +static void +xbt_thread_context_swap(xbt_context_t context); + +static void +xbt_thread_context_schedule(xbt_context_t context); + +static void +xbt_thread_context_yield(void); + +static void +xbt_thread_context_suspend(xbt_context_t context); + +static void +xbt_thread_context_resume(xbt_context_t context); + +static void* +xbt_thread_context_wrapper(void* param); + +int +xbt_thread_context_factory_init(xbt_context_factory_t* factory) +{ + *factory = xbt_new0(s_xbt_context_factory_t,1); + + (*factory)->create_context = xbt_thread_context_factory_create_context; + (*factory)->finalize = xbt_thread_context_factory_finalize; + (*factory)->create_maestro_context = xbt_thread_context_factory_create_master_context; + (*factory)->name = "thread_context_factory"; + + return 0; +} + +static int +xbt_thread_context_factory_create_master_context(xbt_context_t* maestro) +{ + *maestro = (xbt_context_t)xbt_new0(s_xbt_thread_context_t, 1); + return 0; +} + +static int +xbt_thread_context_factory_finalize(xbt_context_factory_t* factory) +{ + free(*factory); + *factory = NULL; + return 0; +} + +static xbt_context_t +xbt_thread_context_factory_create_context(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) +{ + xbt_thread_context_t context = xbt_new0(s_xbt_thread_context_t, 1); + + context->code = code; + context->name = xbt_strdup(name); + context->begin = xbt_os_sem_init(0); + context->end = xbt_os_sem_init(0); + context->iwannadie = 0; /* useless but makes valgrind happy */ + context->argc = argc; + context->argv = argv; + context->startup_func = startup_func; + context->startup_arg = startup_arg; + context->cleanup_func = cleanup_func; + context->cleanup_arg = cleanup_arg; + + context->free = xbt_thread_context_free; + context->kill = xbt_thread_context_kill; + context->schedule = xbt_thread_context_schedule; + context->yield = xbt_thread_context_yield; + context->start = xbt_thread_context_start; + context->stop = xbt_thread_context_stop; + + return (xbt_context_t)context; +} + +static void +xbt_thread_context_free(xbt_context_t context) +{ + if(context) + { + xbt_thread_context_t thread_context = (xbt_thread_context_t)context; + + free(thread_context->name); + + if(thread_context->argv) + { + int i; + + for(i = 0; i < thread_context->argc; i++) + if(thread_context->argv[i]) + free(thread_context->argv[i]); + + free(thread_context->argv); + } + + /* wait about the thread terminason */ + xbt_os_thread_join(thread_context->thread, NULL); + + /* destroy the synchronisation objects */ + xbt_os_sem_destroy(thread_context->begin); + xbt_os_sem_destroy(thread_context->end); + + /* finally destroy the context */ + free(context); + } +} + +static void +xbt_thread_context_kill(xbt_context_t context) +{ + context->iwannadie = 1; + xbt_thread_context_swap(context); +} + +/** + * \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. + */ +static void +xbt_thread_context_schedule(xbt_context_t context) +{ + xbt_assert0((current_context == maestro_context),"You are not supposed to run this function here!"); + xbt_thread_context_swap(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 + */ +static void +xbt_thread_context_yield(void) +{ + xbt_assert0((current_context != maestro_context),"You are not supposed to run this function here!"); + xbt_thread_context_swap(current_context); +} + +static void +xbt_thread_context_start(xbt_context_t context) +{ + xbt_thread_context_t thread_context = (xbt_thread_context_t)context; + + /* create and start the process */ + thread_context->thread = xbt_os_thread_create(thread_context->name,xbt_thread_context_wrapper,thread_context); + + /* wait the starting of the newly created process */ + xbt_os_sem_acquire(thread_context->end); +} + +static void +xbt_thread_context_stop(int exit_code) +{ + if(current_context->cleanup_func) + ((*current_context->cleanup_func))(current_context->cleanup_arg); + + xbt_swag_remove(current_context, context_living); + xbt_swag_insert(current_context, context_to_destroy); + + /* signal to the maestro that it has finished */ + xbt_os_sem_release(((xbt_thread_context_t)current_context)->end); + + /* exit*/ + xbt_os_thread_exit(NULL); /* We should provide return value in case other wants it */ +} + +static void +xbt_thread_context_swap(xbt_context_t context) +{ + if((current_context != maestro_context) && !context->iwannadie) + { + /* (0) it's not the scheduler and the process doesn't want to die, it just wants to yield */ + + /* yield itself, resume the maestro */ + xbt_thread_context_suspend(context); + } + else + { + /* (1) the current process is the scheduler and the process doesn't want to die + * <-> the maestro wants to schedule the process + * -> the maestro schedules the process and waits + * + * (2) the current process is the scheduler and the process wants to die + * <-> the maestro wants to kill the process (has called the function xbt_context_kill()) + * -> the maestro schedule the process and waits (xbt_os_sem_acquire(context->end)) + * -> if the process stops (xbt_context_stop()) + * -> the process resumes the maestro (xbt_os_sem_release(current_context->end)) and exit (xbt_os_thread_exit()) + * -> else the process call xbt_context_yield() + * -> goto (3.1) + * + * (3) the current process is not the scheduler and the process wants to die + * -> (3.1) if the current process is the process who wants to die + * -> (resume not need) goto (4) + * -> (3.2) else the current process is not the process who wants to die + * <-> the current process wants to kill an other process + * -> the current process resumes the process to die and waits + * -> if the process to kill stops + * -> it resumes the process who kill it and exit + * -> else if the process to kill calls to xbt_context_yield() + * -> goto (3.1) + */ + /* schedule the process associated with this context */ + xbt_thread_context_resume(context); + + } + + /* (4) the current process wants to die */ + if(current_context->iwannadie) + xbt_thread_context_stop(1); +} + +static void* +xbt_thread_context_wrapper(void* param) +{ + xbt_thread_context_t context = (xbt_thread_context_t)param; + + /* signal its starting to the maestro and wait to start its job*/ + xbt_os_sem_release(context->end); + xbt_os_sem_acquire(context->begin); + + if (context->startup_func) + (*(context->startup_func))(context->startup_arg); + + + xbt_thread_context_stop((context->code) (context->argc, context->argv)); + return NULL; +} + +static void +xbt_thread_context_suspend(xbt_context_t context) +{ + /* save the current context */ + xbt_context_t self = current_context; + + /* update the current context to this context */ + current_context = context; + + xbt_os_sem_release(((xbt_thread_context_t)context)->end); + xbt_os_sem_acquire(((xbt_thread_context_t)context)->begin); + + /* restore the current context to the previously saved context */ + current_context = self; +} + +static void +xbt_thread_context_resume(xbt_context_t context) +{ + /* save the current context */ + xbt_context_t self = current_context; + + /* update the current context */ + current_context = context; + + xbt_os_sem_release(((xbt_thread_context_t)context)->begin); + xbt_os_sem_acquire(((xbt_thread_context_t)context)->end); + + /* restore the current context to the previously saved context */ + current_context = self; +} + + + diff --git a/src/xbt/xbt_thread_context.h b/src/xbt/xbt_thread_context.h new file mode 100644 index 0000000000..fa08f1738f --- /dev/null +++ b/src/xbt/xbt_thread_context.h @@ -0,0 +1,34 @@ +#ifndef _XBT_THREAD_CONTEXT_H +#define _XBT_THREAD_CONTEXT_H + +#include "portable.h" /* loads context system definitions */ +#include "xbt/xbt_os_thread.h" /* declaration of the xbt native semaphore and native thread */ +#include "xbt/swag.h" + + +#ifndef _XBT_CONTEXT_PRIVATE_H +/*#include "xbt_context_private.h"*/ +#endif /* _XBT_CONTEXT_PRIVATE_H */ + +SG_BEGIN_DECL() + +#ifndef _XBT_CONTEXT_FACTORY_T_DEFINED +typedef struct s_xbt_context_factory* xbt_context_factory_t; +#define _XBT_CONTEXT_FACTORY_T_DEFINED +#endif /* !_XBT_CONTEXT_FACTORY_T_DEFINED */ + + +typedef struct s_xbt_thread_context +{ + XBT_CTX_BASE_T; + xbt_os_thread_t thread; /* a plain dumb thread (portable to posix or windows) */ + xbt_os_sem_t begin; /* this semaphore is used to schedule/yield the process */ + xbt_os_sem_t end; /* this semaphore is used to schedule/unschedule the process */ +}s_xbt_thread_context_t,* xbt_thread_context_t; + +int +xbt_thread_context_factory_init(xbt_context_factory_t* factory); + +SG_END_DECL() + +#endif /* !_XBT_THREAD_CONTEXT_H */ diff --git a/src/xbt/xbt_ucontext.c b/src/xbt/xbt_ucontext.c new file mode 100644 index 0000000000..bdfa8300dc --- /dev/null +++ b/src/xbt/xbt_ucontext.c @@ -0,0 +1,288 @@ + +#include "ucontext_stack.h" + +/* callback: context fetching */ +static ex_ctx_t* +xbt_jcontext_ex_ctx(void); + +/* callback: termination */ +static void +xbt_jcontext_ex_terminate(xbt_ex_t *e); + +static xbt_context_t +xbt_ucontext_factory_create_context(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); + +static int +xbt_ucontext_factory_finalize(xbt_context_factory_t* factory); + +static int +xbt_ucontext_factory_create_maestro_context(xbt_context_t* maestro); + +static void +xbt_ucontext_free(xbt_context_t context); + +static void +xbt_ucontext_kill(xbt_context_t context); + +static void +xbt_ucontext_schedule(xbt_context_t context); + +static void +xbt_ucontext_yield(void); + +static void +xbt_ucontext_start(xbt_context_t context); + +static void +xbt_ucontext_stop(int exit_code); + +static void +xbt_ucontext_swap(xbt_context_t context); + +static void +xbt_ucontext_schedule(xbt_context_t context); + +static void +xbt_ucontext_yield(void); + +static void +xbt_ucontext_suspend(xbt_context_t context); + +static void +xbt_ucontext_resume(xbt_context_t context); + +static void* +xbt_ucontext_wrapper(void* param); + +/* callback: context fetching */ +static ex_ctx_t* +xbt_ucontext_ex_ctx(void) +{ + return current_context->exception; +} + +/* callback: termination */ +static void +xbt_ucontext_ex_terminate(xbt_ex_t *e) +{ + xbt_ex_display(e); + abort(); +} + + +int +xbt_ucontext_factory_init(xbt_context_factory_t* factory) +{ + /* context exception */ + *factory = xbt_new0(s_xbt_context_factory_t,1); + + (*factory)->create_context = xbt_ucontext_factory_create_context; + (*factory)->finalize = xbt_ucontext_factory_finalize; + (*factory)->create_maestro_context = xbt_ucontext_factory_create_maestro_context; + (*factory)->name = "ucontext_context_factory"; + + /* context exception handlers */ + __xbt_ex_ctx = xbt_ucontext_ex_ctx; + __xbt_ex_terminate = xbt_ucontext_ex_terminate; + + return 0; +} + +static int +xbt_ucontext_factory_create_maestro_context(xbt_context_t* maestro) +{ + + xbt_ucontext_t context = xbt_new0(s_xbt_ucontext_t, 1); + + context->exception = xbt_new(ex_ctx_t,1); + XBT_CTX_INITIALIZE(context->exception); + + *maestro = (xbt_context_t)context; + + return 0; + +} + + +static int +xbt_ucontext_factory_finalize(xbt_context_factory_t* factory) +{ + free(maestro_context->exception); + free(*factory); + *factory = NULL; + return 0; +} + +static xbt_context_t +xbt_ucontext_factory_create_context(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) +{ + xbt_ucontext_t context = xbt_new0(s_xbt_ucontext_t, 1); + + context->code = code; + context->name = xbt_strdup(name); + + xbt_assert2(getcontext(&(context->uc)) == 0,"Error in context saving: %d (%s)", errno, strerror(errno)); + context->uc.uc_link = NULL; + context->uc.uc_stack.ss_sp = pth_skaddr_makecontext(context->stack, STACK_SIZE); + context->uc.uc_stack.ss_size = pth_sksize_makecontext(context->stack, STACK_SIZE); + + context->exception = xbt_new(ex_ctx_t, 1); + XBT_CTX_INITIALIZE(context->exception); + context->iwannadie = 0; /* useless but makes valgrind happy */ + context->argc = argc; + context->argv = argv; + context->startup_func = startup_func; + context->startup_arg = startup_arg; + context->cleanup_func = cleanup_func; + context->cleanup_arg = cleanup_arg; + + + context->free = xbt_ucontext_free; + context->kill = xbt_ucontext_kill; + context->schedule = xbt_ucontext_schedule; + context->yield = xbt_ucontext_yield; + context->start = xbt_ucontext_start; + context->stop = xbt_ucontext_stop; + + return (xbt_context_t)context; +} + +static void +xbt_ucontext_free(xbt_context_t context) +{ + if(context) + { + free(context->name); + + if(context->argv) + { + int i; + + for(i = 0; i < context->argc; i++) + if(context->argv[i]) + free(context->argv[i]); + + free(context->argv); + } + + if(context->exception) + free(context->exception); + + /* finally destroy the context */ + free(context); + } +} + +static void +xbt_ucontext_kill(xbt_context_t context) +{ + context->iwannadie = 1; + xbt_ucontext_swap(context); +} + +/** + * \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. + */ +static void +xbt_ucontext_schedule(xbt_context_t context) +{ + xbt_assert0((current_context == maestro_context),"You are not supposed to run this function here!"); + xbt_ucontext_swap(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 + */ +static void +xbt_ucontext_yield(void) +{ + xbt_assert0((current_context != maestro_context),"You are not supposed to run this function here!"); + xbt_ucontext_swap(current_context); +} + +static void +xbt_ucontext_start(xbt_context_t context) +{ + makecontext(&(((xbt_ucontext_t)context)->uc), (void (*)(void)) xbt_ucontext_wrapper, 1, context); +} + +static void +xbt_ucontext_stop(int exit_code) +{ + if(current_context->cleanup_func) + ((*current_context->cleanup_func))(current_context->cleanup_arg); + + xbt_swag_remove(current_context, context_living); + xbt_swag_insert(current_context, context_to_destroy); + + xbt_ucontext_swap(current_context); +} + +static void +xbt_ucontext_swap(xbt_context_t context) +{ + xbt_assert0(current_context, "You have to call context_init() first."); + xbt_assert0(context, "Invalid argument"); + + if(((xbt_ucontext_t)context)->prev == NULL) + xbt_ucontext_resume(context); + else + xbt_ucontext_suspend(context); + + if(current_context->iwannadie) + xbt_ucontext_stop(1); +} + +static void* +xbt_ucontext_wrapper(void* param) +{ + if (current_context->startup_func) + (*current_context->startup_func)(current_context->startup_arg); + + xbt_ucontext_stop((*(current_context->code))(current_context->argc, current_context->argv)); + return NULL; +} + +static void +xbt_ucontext_suspend(xbt_context_t context) +{ + int rv; + + xbt_ucontext_t prev_context = ((xbt_ucontext_t)context)->prev; + + current_context = (xbt_context_t)(((xbt_ucontext_t)context)->prev); + + ((xbt_ucontext_t)context)->prev = NULL; + + rv = swapcontext(&(((xbt_ucontext_t)context)->uc), &(prev_context->uc)); + + xbt_assert0((rv == 0), "Context swapping failure"); +} + +static void +xbt_ucontext_resume(xbt_context_t context) +{ + int rv; + + ((xbt_ucontext_t)context)->prev = (xbt_ucontext_t)current_context; + + current_context = context; + + rv = swapcontext(&(((xbt_ucontext_t)context)->prev->uc), &(((xbt_ucontext_t)context)->uc)); + + xbt_assert0((rv == 0), "Context swapping failure"); +} + + + diff --git a/src/xbt/xbt_ucontext.h b/src/xbt/xbt_ucontext.h new file mode 100644 index 0000000000..b2ce72fa59 --- /dev/null +++ b/src/xbt/xbt_ucontext.h @@ -0,0 +1,27 @@ +#ifndef _XBT_UCONTEXT_H +#define _XBT_UCONTEXT_H + +#include "ucontext_stack.h" /* loads context system definitions */ +#include /* context relative declarations */ +#define STACK_SIZE 128*1024 /* lower this if you want to reduce the memory consumption */ + +#ifndef _XBT_CONTEXT_FACTORY_T_DEFINED +typedef struct s_xbt_context_factory* xbt_context_factory_t; +#define _XBT_CONTEXT_FACTORY_T_DEFINED +#endif /* !_XBT_CONTEXT_FACTORY_T_DEFINED */ + +typedef struct s_xbt_ucontext +{ + XBT_CTX_BASE_T; + ucontext_t uc; /* the thread that execute the code */ + char stack[STACK_SIZE]; /* the thread stack size */ + struct s_xbt_ucontext* prev; /* the previous thread */ +}s_xbt_ucontext_t,* xbt_ucontext_t; + + +int +xbt_ucontext_factory_init(xbt_context_factory_t* factory); + +SG_END_DECL() + +#endif /* !_XBT_UCONTEXT_H */ -- 2.20.1