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. */
11 #include "context_sysv_config.h" /* loads context system definitions */
13 #include <ucontext.h> /* context relative declarations */
15 /* lower this if you want to reduce the memory consumption */
16 #define STACK_SIZE 128*1024
18 #ifdef HAVE_VALGRIND_VALGRIND_H
19 # include <valgrind/valgrind.h>
20 #endif /* HAVE_VALGRIND_VALGRIND_H */
22 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(simix_context);
24 typedef struct s_smx_ctx_sysv {
26 ucontext_t uc; /* the thread that execute the code */
27 char stack[STACK_SIZE]; /* the thread stack size */
28 struct s_smx_ctx_sysv *prev; /* the previous process */
29 #ifdef HAVE_VALGRIND_VALGRIND_H
30 unsigned int valgrind_stack_id; /* the valgrind stack id */
32 } s_smx_ctx_sysv_t, *smx_ctx_sysv_t;
35 smx_ctx_sysv_factory_create_context(xbt_main_func_t code, int argc, char** argv,
36 void_f_pvoid_t cleanup_func, void* cleanup_arg);
38 static int smx_ctx_sysv_factory_finalize(smx_context_factory_t *factory);
40 static void smx_ctx_sysv_free(smx_context_t context);
42 static void smx_ctx_sysv_start(smx_context_t context);
44 static void smx_ctx_sysv_stop(smx_context_t context);
46 static void smx_ctx_sysv_suspend(smx_context_t context);
49 smx_ctx_sysv_resume(smx_context_t old_context, smx_context_t new_context);
51 static void smx_ctx_sysv_wrapper(void);
53 void SIMIX_ctx_sysv_factory_init(smx_context_factory_t *factory)
55 *factory = xbt_new0(s_smx_context_factory_t, 1);
57 (*factory)->create_context = smx_ctx_sysv_factory_create_context;
58 (*factory)->finalize = smx_ctx_sysv_factory_finalize;
59 (*factory)->free = smx_ctx_sysv_free;
60 (*factory)->start = smx_ctx_sysv_start;
61 (*factory)->stop = smx_ctx_sysv_stop;
62 (*factory)->suspend = smx_ctx_sysv_suspend;
63 (*factory)->resume = smx_ctx_sysv_resume;
64 (*factory)->name = "smx_sysv_context_factory";
67 static int smx_ctx_sysv_factory_finalize(smx_context_factory_t * factory)
75 smx_ctx_sysv_factory_create_context(xbt_main_func_t code, int argc, char** argv,
76 void_f_pvoid_t cleanup_func, void* cleanup_arg)
78 smx_ctx_sysv_t context = xbt_new0(s_smx_ctx_sysv_t, 1);
80 /* If the user provided a function for the process then use it
81 otherwise is the context for maestro */
85 xbt_assert2(getcontext(&(context->uc)) == 0,
86 "Error in context saving: %d (%s)", errno, strerror(errno));
88 context->uc.uc_link = NULL;
90 context->uc.uc_stack.ss_sp =
91 pth_skaddr_makecontext(context->stack, STACK_SIZE);
93 context->uc.uc_stack.ss_size =
94 pth_sksize_makecontext(context->stack, STACK_SIZE);
96 #ifdef HAVE_VALGRIND_VALGRIND_H
97 context->valgrind_stack_id =
98 VALGRIND_STACK_REGISTER(context->uc.uc_stack.ss_sp,
99 ((char *) context->uc.uc_stack.ss_sp) +
100 context->uc.uc_stack.ss_size);
101 #endif /* HAVE_VALGRIND_VALGRIND_H */
103 context->argc = argc;
104 context->argv = argv;
105 context->cleanup_func = cleanup_func;
106 context->cleanup_arg = cleanup_arg;
109 return (smx_context_t)context;
112 static void smx_ctx_sysv_free(smx_context_t pcontext)
115 smx_ctx_sysv_t context = (smx_ctx_sysv_t)pcontext;
118 #ifdef HAVE_VALGRIND_VALGRIND_H
119 VALGRIND_STACK_DEREGISTER(((smx_ctx_sysv_t) context)->valgrind_stack_id);
120 #endif /* HAVE_VALGRIND_VALGRIND_H */
124 for (i = 0; i < context->argc; i++)
125 if (context->argv[i])
126 free(context->argv[i]);
131 /* destroy the context */
136 static void smx_ctx_sysv_start(smx_context_t context)
138 makecontext(&((smx_ctx_sysv_t)context)->uc, smx_ctx_sysv_wrapper, 0);
141 static void smx_ctx_sysv_stop(smx_context_t pcontext)
143 smx_ctx_sysv_t context = (smx_ctx_sysv_t)pcontext;
145 if (context->cleanup_func)
146 (*context->cleanup_func) (context->cleanup_arg);
148 smx_ctx_sysv_suspend(pcontext);
151 static void smx_ctx_sysv_wrapper()
153 /*FIXME: I would like to avoid accesing simix_global to get the current
154 context by passing it as an argument of the wrapper function. The problem
155 is that this function is called from smx_ctx_sysv_start, and uses
156 makecontext for calling it, and the stupid posix specification states that
157 all the arguments of the function should be int(32 bits), making it useless
158 in 64-bit architectures where pointers are 64 bit long.
160 smx_ctx_sysv_t context =
161 (smx_ctx_sysv_t)simix_global->current_process->context;
163 (context->code) (context->argc, context->argv);
165 smx_ctx_sysv_stop((smx_context_t)context);
168 static void smx_ctx_sysv_suspend(smx_context_t context)
172 smx_ctx_sysv_t prev_context = ((smx_ctx_sysv_t) context)->prev;
174 ((smx_ctx_sysv_t) context)->prev = NULL;
176 rv = swapcontext(&((smx_ctx_sysv_t) context)->uc, &prev_context->uc);
178 xbt_assert0((rv == 0), "Context swapping failure");
182 smx_ctx_sysv_resume(smx_context_t old_context, smx_context_t new_context)
186 ((smx_ctx_sysv_t) new_context)->prev = (smx_ctx_sysv_t)old_context;
188 rv = swapcontext(&((smx_ctx_sysv_t)old_context)->uc,
189 &((smx_ctx_sysv_t)new_context)->uc);
191 xbt_assert0((rv == 0), "Context swapping failure");