3 /* context_sysv - implementation of context switching with ucontextes from Sys V */
5 /* Copyright (c) 2004-2008 the SimGrid team. All right reserved */
7 /* This program is free software; you can redistribute it and/or modify it
8 * under the terms of the license (GNU LGPL) which comes with this package. */
10 #include "xbt/ex_interface.h"
12 #include "context_sysv_config.h" /* loads context system definitions */
14 #include <ucontext.h> /* context relative declarations */
16 /* lower this if you want to reduce the memory consumption */
17 #define STACK_SIZE 128*1024
19 #ifdef HAVE_VALGRIND_VALGRIND_H
20 # include <valgrind/valgrind.h>
21 #endif /* HAVE_VALGRIND_VALGRIND_H */
23 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(simix_context);
25 typedef struct s_smx_ctx_sysv {
27 ucontext_t uc; /* the thread that execute the code */
28 char stack[STACK_SIZE]; /* the thread stack size */
29 struct s_smx_ctx_sysv *prev; /* the previous process */
30 #ifdef HAVE_VALGRIND_VALGRIND_H
31 unsigned int valgrind_stack_id; /* the valgrind stack id */
33 } s_smx_ctx_sysv_t, *smx_ctx_sysv_t;
36 /* callback: context fetching */
37 static ex_ctx_t *xbt_jcontext_ex_ctx(void);
39 /* callback: termination */
40 static void xbt_jcontext_ex_terminate(xbt_ex_t *e);
43 smx_ctx_sysv_factory_create_context(xbt_main_func_t code, int argc, char** argv,
44 void_f_pvoid_t cleanup_func, void* cleanup_arg);
46 static int smx_ctx_sysv_factory_finalize(smx_context_factory_t *factory);
48 static smx_context_t smx_ctx_sysv_factory_create_maestro_context(void);
50 static void smx_ctx_sysv_free(smx_context_t context);
52 static void smx_ctx_sysv_start(smx_context_t context);
54 static void smx_ctx_sysv_stop(smx_context_t context);
56 static void smx_ctx_sysv_suspend(smx_context_t context);
59 smx_ctx_sysv_resume(smx_context_t old_context, smx_context_t new_context);
61 static void smx_ctx_sysv_wrapper(void);
63 /* callback: context fetching */
64 static ex_ctx_t *xbt_ctx_sysv_ex_ctx(void)
66 /*FIXME: the factory should access simix level datastructures! */
67 return simix_global->current_process->context->exception;
70 /* callback: termination */
71 static void xbt_ctx_sysv_ex_terminate(xbt_ex_t * e)
77 void SIMIX_ctx_sysv_factory_init(smx_context_factory_t *factory)
79 *factory = xbt_new0(s_smx_context_factory_t, 1);
81 (*factory)->create_context = smx_ctx_sysv_factory_create_context;
82 (*factory)->finalize = smx_ctx_sysv_factory_finalize;
83 (*factory)->create_maestro_context = smx_ctx_sysv_factory_create_maestro_context;
84 (*factory)->free = smx_ctx_sysv_free;
85 (*factory)->start = smx_ctx_sysv_start;
86 (*factory)->stop = smx_ctx_sysv_stop;
87 (*factory)->suspend = smx_ctx_sysv_suspend;
88 (*factory)->resume = smx_ctx_sysv_resume;
89 (*factory)->name = "smx_sysv_context_factory";
91 /* context exception handlers */
92 __xbt_ex_ctx = xbt_ctx_sysv_ex_ctx;
93 __xbt_ex_terminate = xbt_ctx_sysv_ex_terminate;
96 static smx_context_t smx_ctx_sysv_factory_create_maestro_context()
98 smx_ctx_sysv_t context = xbt_new0(s_smx_ctx_sysv_t, 1);
100 context->exception = xbt_new(ex_ctx_t, 1);
101 XBT_CTX_INITIALIZE(context->exception);
103 return (smx_context_t)context;
106 static int smx_ctx_sysv_factory_finalize(smx_context_factory_t * factory)
108 /*FIXME free(maestro_context->exception);*/
115 smx_ctx_sysv_factory_create_context(xbt_main_func_t code, int argc, char** argv,
116 void_f_pvoid_t cleanup_func, void* cleanup_arg)
118 smx_ctx_sysv_t context = xbt_new0(s_smx_ctx_sysv_t, 1);
120 context->code = code;
122 xbt_assert2(getcontext(&(context->uc)) == 0,
123 "Error in context saving: %d (%s)", errno, strerror(errno));
124 context->uc.uc_link = NULL;
125 context->uc.uc_stack.ss_sp =
126 pth_skaddr_makecontext(context->stack, STACK_SIZE);
127 context->uc.uc_stack.ss_size =
128 pth_sksize_makecontext(context->stack, STACK_SIZE);
129 #ifdef HAVE_VALGRIND_VALGRIND_H
130 context->valgrind_stack_id =
131 VALGRIND_STACK_REGISTER(context->uc.uc_stack.ss_sp,
132 ((char *) context->uc.uc_stack.ss_sp) +
133 context->uc.uc_stack.ss_size);
134 #endif /* HAVE_VALGRIND_VALGRIND_H */
136 context->exception = xbt_new(ex_ctx_t, 1);
137 XBT_CTX_INITIALIZE(context->exception);
138 context->argc = argc;
139 context->argv = argv;
140 context->cleanup_func = cleanup_func;
141 context->cleanup_arg = cleanup_arg;
142 return (smx_context_t)context;
145 static void smx_ctx_sysv_free(smx_context_t pcontext)
148 smx_ctx_sysv_t context = (smx_ctx_sysv_t)pcontext;
151 if (context->exception)
152 free(context->exception);
154 #ifdef HAVE_VALGRIND_VALGRIND_H
155 VALGRIND_STACK_DEREGISTER(((smx_ctx_sysv_t) context)->valgrind_stack_id);
156 #endif /* HAVE_VALGRIND_VALGRIND_H */
160 for (i = 0; i < context->argc; i++)
161 if (context->argv[i])
162 free(context->argv[i]);
167 /* destroy the context */
172 static void smx_ctx_sysv_start(smx_context_t context)
174 makecontext(&((smx_ctx_sysv_t)context)->uc, smx_ctx_sysv_wrapper, 0);
177 static void smx_ctx_sysv_stop(smx_context_t pcontext)
179 smx_ctx_sysv_t context = (smx_ctx_sysv_t)pcontext;
181 if (context->cleanup_func)
182 (*context->cleanup_func) (context->cleanup_arg);
184 smx_ctx_sysv_suspend((smx_context_t)context);
187 static void smx_ctx_sysv_wrapper()
189 /*FIXME: I would like to avoid accesing simix_global to get the current
190 context by passing it as an argument of the wrapper function. The problem
191 is that this function is called from smx_ctx_sysv_start, and uses
192 makecontext for calling it, and the stupid posix specification states that
193 all the arguments of the function should be int(32 bits), making it useless
194 in 64-bit architectures where pointers are 64 bit long.
196 smx_ctx_sysv_t context =
197 (smx_ctx_sysv_t)simix_global->current_process->context;
199 (context->code) (context->argc, context->argv);
201 smx_ctx_sysv_stop((smx_context_t)context);
204 static void smx_ctx_sysv_suspend(smx_context_t context)
208 smx_ctx_sysv_t prev_context = ((smx_ctx_sysv_t) context)->prev;
210 ((smx_ctx_sysv_t) context)->prev = NULL;
212 rv = swapcontext(&((smx_ctx_sysv_t) context)->uc, &prev_context->uc);
214 xbt_assert0((rv == 0), "Context swapping failure");
218 smx_ctx_sysv_resume(smx_context_t old_context, smx_context_t new_context)
222 ((smx_ctx_sysv_t) new_context)->prev = (smx_ctx_sysv_t)old_context;
224 rv = swapcontext(&((smx_ctx_sysv_t)old_context)->uc,
225 &((smx_ctx_sysv_t)new_context)->uc);
227 xbt_assert0((rv == 0), "Context swapping failure");