From: alegrand Date: Tue, 14 Dec 2004 19:04:58 +0000 (+0000) Subject: Adding a context library to xbt. X-Git-Tag: v3.3~4727 X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/commitdiff_plain/f7f21dcaaa2d53d3cd4b709b95cda97330aeca0b?hp=1c0662ce683e29ed5498a7ed4f961d152a1e1ba5 Adding a context library to xbt. git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/simgrid/simgrid/trunk@623 48e7efb5-ca39-0410-a469-dd3cf9ba447f --- diff --git a/configure.ac b/configure.ac index b7d6631009..d164ed9275 100644 --- a/configure.ac +++ b/configure.ac @@ -92,6 +92,11 @@ AM_CONDITIONAL(HAVE_SG,test x$HAVE_SimGrid = xyes) dnl A C_CHECK_LIB(pthread, pthread_mutex_lock, LIBS="$LIBS -lpthread") AC_CHECK_LIB(nsl, gethostbyname, [LIBS="$LIBS -lnsl"]) AC_CHECK_LIB(socket, connect, [LIBS="$LIBS -lsocket"]) + +AC_CHECK_LIB(c,swapcontext, + [AC_DEFINE([USE_CONTEXT],1,[Define if GNU contexts available and you wish to use them])], + [AC_MSG_ERROR([[Cannot find context in your libc, go away !]])]) + dnl ####[ maint mode ]####################################################### AM_MAINTAINER_MODE diff --git a/include/Makefile.am b/include/Makefile.am index 66af137434..154bba3f08 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -9,6 +9,7 @@ nobase_include_HEADERS = \ xbt/fifo.h \ xbt/swag.h \ xbt/config.h \ + xbt/context.h \ \ surf/maxmin.h \ surf/trace_mgr.h \ diff --git a/include/xbt/context.h b/include/xbt/context.h new file mode 100644 index 0000000000..044325ee8e --- /dev/null +++ b/include/xbt/context.h @@ -0,0 +1,21 @@ +/* $Id$ */ + +/* Copyright (c) 2004 Arnaud Legrand. 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. */ + +#ifndef _XBT_CONTEXT_H +#define _XBT_CONTEXT_H + +typedef struct s_context *context_t; +typedef int(*context_function_t)(int argc, char *argv[]); + +void context_init(void); +void context_empty_trash(void); +context_t context_create(context_function_t code, int argc, char *argv[]); +void context_start(context_t context); +void context_yield(context_t context); +int context_get_id(context_t context); + +#endif /* _XBT_CONTEXT_H */ diff --git a/src/Makefile.am b/src/Makefile.am index 3adaa72524..15225a0461 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -22,6 +22,7 @@ EXTRA_DIST= \ xbt/dict_private.h \ xbt/heap_private.h \ xbt/fifo_private.h \ + xbt/context_private.h \ \ surf/maxmin_private.h \ surf/trace_mgr_private.h \ @@ -98,6 +99,7 @@ COMMON_S=\ xbt/set.c \ xbt/module.c \ xbt/config.c \ + xbt/context.c \ \ surf/maxmin.c \ surf/trace_mgr.c \ diff --git a/src/xbt/context.c b/src/xbt/context.c new file mode 100644 index 0000000000..b6124ce9bb --- /dev/null +++ b/src/xbt/context.c @@ -0,0 +1,250 @@ +/* $Id$ */ + +/* a fast and simple context switching library */ + +/* Copyright (c) 2004 Arnaud Legrand. 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 "context_private.h" +#include "xbt/error.h" +#include "xbt/dynar.h" +#include "gras_config.h" +XBT_LOG_NEW_DEFAULT_SUBCATEGORY(context, xbt, "Context"); + + +/************************ GNU LIBC CONTEXTS **************************/ +#if USE_CONTEXT==1 + +static context_t current_context = NULL; +static xbt_dynar_t context_to_destroy = NULL; + +void context_init(void) +{ + if(!current_context) { + current_context = xbt_new0(s_context_t,1); + context_to_destroy = xbt_dynar_new(sizeof(context_t),xbt_free); + } +} + +void context_empty_trash(void) +{ + xbt_dynar_reset(context_to_destroy); +} + +static void *__context_wrapper(void *c) +{ + context_t context = c; + int i; + +/* msg_global->current_process = process; */ + + /* WARNING("Calling the main function"); */ + (context->code) (context->argc,context->argv); + + for(i=0;iargc; i++) + if(context->argv[i]) xbt_free(context->argv[i]); + if(context->argv) xbt_free(context->argv); + + xbt_dynar_push(context_to_destroy, &context); + + context_yield(context); + + return NULL; +} + +void context_start(context_t context) +{ + +/* TBX_FIFO_insert(msg_global->process, process); */ +/* TBX_FIFO_insert(msg_global->process_to_run, process); */ + + /* WARNING("Assigning __MSG_process_launcher to context (%p)",context); */ + makecontext (&(context->uc), (void (*) (void)) __context_wrapper, + 1, context); + + return; +} + +context_t context_create(context_function_t code, + int argc, char *argv[]) +{ + context_t res = NULL; + + res = xbt_new0(s_context_t,1); + + /* WARNING("Initializing context (%p)",res); */ + + xbt_assert0(getcontext(&(res->uc))==0,"Error in context saving."); + + /* VOIRP(res->uc); */ + res->code = code; + res->uc.uc_link = &(current_context->uc); /* FIXME LATER */ + /* WARNING : when this context is over, the current_context (i.e. the + father), is awaken... May result in bugs later.*/ + res->uc.uc_stack.ss_sp = res->stack; + res->uc.uc_stack.ss_size = STACK_SIZE; + return res; +} + +static void context_destroy(context_t context) +{ + xbt_free(context); + + return; +} + +void context_yield(context_t context) +{ + + xbt_assert0(current_context,"You have to call context_init() first."); + + /* __MSG_context_init(); */ + /* fprintf(stderr,"\n"); */ + /* WARNING("--------- current_context (%p) is yielding to context(%p) ---------",current_context,context); */ + /* VOIRP(current_context); */ + /* if(current_context) VOIRP(current_context->save); */ + /* VOIRP(context); */ + /* if(context) VOIRP(context->save); */ + + if (context) { +/* m_process_t self = msg_global->current_process; */ + if(context->save==NULL) { + /* WARNING("**** Yielding to somebody else ****"); */ + /* WARNING("Saving current_context value (%p) to context(%p)->save",current_context,context); */ + context->save = current_context ; + context->uc.uc_link = &(current_context->uc); + /* WARNING("current_context becomes context(%p) ",context); */ + current_context = context ; + /* WARNING("Current position memorized (context->save). Jumping to context (%p)",context); */ + if(!swapcontext (&(context->save->uc), &(context->uc))) + xbt_assert0(0,"Context swapping failure"); + /* WARNING("I am (%p). Coming back\n",context); */ + } else { + context_t old_context = context->save ; + /* WARNING("**** Back ! ****"); */ + /* WARNING("Setting current_context (%p) to context(%p)->save",current_context,context); */ + current_context = context->save ; + /* WARNING("Setting context(%p)->save to NULL",current_context,context); */ + context->save = NULL ; + /* WARNING("Current position memorized (%p). Jumping to context (%p)",context,old_context); */ + if(!swapcontext (&(context->uc), &(old_context->uc)) ) + xbt_assert0(0,"Context swapping failure"); + /* WARNING("I am (%p). Coming back\n",context); */ + } +/* msg_global->current_process = self; */ + } + + return; +} +#else + +/****************************** PTHREADS ***************************/ +/* #if HAVE_LIBPTHREAD==1 */ +#ifdef HAVE_LIBPTHREAD /* Nevermind, let's use pthreads... */ + +static void *__MSG_process_launcher(void *p) +{ + m_process_t process = (m_process_t) p; + sim_data_process_t sim_data = process->simdata; + context_t context = NULL; + int i; + msg_global->current_process = process; + TBX_FIFO_insert(msg_global->process, process); + + TBX_FIFO_insert(msg_global->process_to_run, process); +/* pthread_mutex_lock(&(sim_data->context->mutex)); */ + __MSG_context_yield(sim_data->context); + + (*sim_data->context->code) (sim_data->argc,sim_data->argv); + + TBX_FIFO_remove(msg_global->process, process); + TBX_FIFO_remove(msg_global->process_to_run, process); + + /* Free blocked process if any */ +/* pthread_mutex_lock(&(sim_data->context->mutex)); */ +/* pthread_cond_signal(&(sim_data->context->cond)); */ +/* pthread_mutex_unlock(&(sim_data->context->mutex)); */ + + context = sim_data->context; + + for(i=0;iargc; i++) + if(sim_data->argv[i]) FREE(sim_data->argv[i]); + if(sim_data->argv) FREE(sim_data->argv); + if(process->name) FREE(process->name); + FREE(sim_data); + FREE(process); + + TBX_FIFO_insert(msg_global->context_to_destroy,context); + __MSG_context_yield(context); +/* __MSG_context_destroy(&context); */ + + return NULL; +} + +MSG_error_t __MSG_context_start(m_process_t process) +{ + sim_data_process_t sim_data = NULL; + + sim_data = process->simdata; + + pthread_mutex_lock(&(sim_data->context->mutex)); + + /* Launch the thread */ + if (pthread_create(sim_data->context->thread, NULL, __MSG_process_launcher, + process) != 0) { + WARNING("Unable to create a thread."); + return MSG_FATAL; + } + pthread_cond_wait(&(sim_data->context->cond), &(sim_data->context->mutex)); + pthread_mutex_unlock(&(sim_data->context->mutex)); +/* __MSG_context_yield(sim_data->context); */ + + return MSG_OK; +} + +context_t __MSG_context_create(m_process_code_t code) +{ + context_t res = NULL; + + res = CALLOC(1, sizeof(struct s_context)); + + res->code = code; + res->thread = CALLOC(1, sizeof(pthread_t)); + if (pthread_mutex_init(&(res->mutex), NULL) != 0) + FAILURE("Mutex initialization error"); + if (pthread_cond_init(&(res->cond), NULL) != 0) + FAILURE("Condition initialization error"); + + return res; +} + +MSG_error_t __MSG_context_destroy(context_t * context) +{ + ASSERT(((context != NULL) && (*context != NULL)), "Invalid parameters"); + + FREE((*context)->thread); + pthread_mutex_destroy(&((*context)->mutex)); + pthread_cond_destroy(&((*context)->cond)); + + FREE(*context); + *context = NULL; + + return MSG_OK; +} + +MSG_error_t __MSG_context_yield(context_t context) +{ + if (context) { + m_process_t self = msg_global->current_process; + pthread_mutex_lock(&(context->mutex)); + pthread_cond_signal(&context->cond); + pthread_cond_wait(&context->cond, &context->mutex); + pthread_mutex_unlock(&(context->mutex)); + msg_global->current_process = self; + } + return MSG_OK; +} +#endif /* HAVE_LIBPTHREAD */ +#endif /* USE_CONTEXT */ diff --git a/src/xbt/context_private.h b/src/xbt/context_private.h new file mode 100644 index 0000000000..52540ad69b --- /dev/null +++ b/src/xbt/context_private.h @@ -0,0 +1,42 @@ +/* $Id$ */ + +/* Copyright (c) 2004 Arnaud Legrand. 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. */ + +#ifndef _XBT_CONTEXT_PRIVATE_H +#define _XBT_CONTEXT_PRIVATE_H + +#define HAVE_CONTEXT 1 + +#include "xbt/sysdep.h" +#include "xbt/context.h" + +#ifdef HAVE_LIBPTHREAD +#include +typedef struct s_context { + pthread_cond_t cond; + pthread_mutex_t mutex; + pthread_t *thread; /* the thread that execute the code */ + context_function_t code; /* the scheduler fonction */ + int argc; + char *argv[]; +} s_context_t; +#endif + +#if HAVE_CONTEXT==1 +#include +#include +#define STACK_SIZE 524288 +typedef struct s_context { + ucontext_t uc; /* the thread that execute the code */ + char stack[STACK_SIZE]; + context_function_t code; /* the scheduler fonction */ + int argc; + char **argv; + struct s_context *save; +} s_context_t; +#endif + +#endif /* _XBT_CONTEXT_PRIVATE_H */