Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
3baf8f2f8a011b7593e602511f070caabe78383f
[simgrid.git] / src / simix / smx_context_sysv.c
1 /* $Id$ */
2
3 /* context_sysv - implementation of context switching with ucontextes from Sys V */
4
5 /* Copyright (c) 2004-2008 the SimGrid team. All right reserved */
6
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. */
9
10 #include "xbt/ex_interface.h"
11 #include "private.h"
12 #include "context_sysv_config.h"        /* loads context system definitions */
13 #include "portable.h"
14 #include <ucontext.h>           /* context relative declarations */
15
16 /* lower this if you want to reduce the memory consumption  */
17 #define STACK_SIZE 128*1024
18
19 #ifdef HAVE_VALGRIND_VALGRIND_H
20 #  include <valgrind/valgrind.h>
21 #endif /* HAVE_VALGRIND_VALGRIND_H */
22
23 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(simix_context);
24
25 typedef struct s_smx_ctx_sysv {
26   SMX_CTX_BASE_T;
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 */
32 #endif                          
33 } s_smx_ctx_sysv_t, *smx_ctx_sysv_t;
34
35
36 /* callback: context fetching */
37 static ex_ctx_t *xbt_jcontext_ex_ctx(void);
38
39 /* callback: termination */
40 static void xbt_jcontext_ex_terminate(xbt_ex_t *e);
41
42 static smx_context_t 
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);
45
46 static int smx_ctx_sysv_factory_finalize(smx_context_factory_t *factory);
47
48 static void smx_ctx_sysv_free(smx_context_t context);
49
50 static void smx_ctx_sysv_start(smx_context_t context);
51
52 static void smx_ctx_sysv_stop(smx_context_t context);
53
54 static void smx_ctx_sysv_suspend(smx_context_t context);
55
56 static void 
57   smx_ctx_sysv_resume(smx_context_t old_context, smx_context_t new_context);
58
59 static void smx_ctx_sysv_wrapper(void);
60
61 /* callback: context fetching */
62 static ex_ctx_t *xbt_ctx_sysv_ex_ctx(void)
63 {
64   /*FIXME: the factory should access simix level datastructures! */
65   return simix_global->current_process->context->exception;
66 }
67
68 /* callback: termination */
69 static void xbt_ctx_sysv_ex_terminate(xbt_ex_t * e)
70 {
71   xbt_ex_display(e);
72   abort();
73 }
74
75 void SIMIX_ctx_sysv_factory_init(smx_context_factory_t *factory)
76 {
77   *factory = xbt_new0(s_smx_context_factory_t, 1);
78
79   (*factory)->create_context = smx_ctx_sysv_factory_create_context;
80   (*factory)->finalize = smx_ctx_sysv_factory_finalize;
81   (*factory)->free = smx_ctx_sysv_free;
82   (*factory)->start = smx_ctx_sysv_start;
83   (*factory)->stop = smx_ctx_sysv_stop;
84   (*factory)->suspend = smx_ctx_sysv_suspend;
85   (*factory)->resume = smx_ctx_sysv_resume;
86   (*factory)->name = "smx_sysv_context_factory";
87
88   /* context exception handlers */
89   __xbt_ex_ctx = xbt_ctx_sysv_ex_ctx;
90   __xbt_ex_terminate = xbt_ctx_sysv_ex_terminate;
91 }
92
93 static int smx_ctx_sysv_factory_finalize(smx_context_factory_t * factory)
94 {
95   free(*factory);
96   *factory = NULL;
97
98   /* Restore the default exception setup */
99   __xbt_ex_ctx = &__xbt_ex_ctx_default;
100   __xbt_ex_terminate = &__xbt_ex_terminate_default;
101
102   return 0;
103 }
104
105 static smx_context_t 
106 smx_ctx_sysv_factory_create_context(xbt_main_func_t code, int argc, char** argv, 
107                                     void_f_pvoid_t cleanup_func, void* cleanup_arg)
108 {
109   smx_ctx_sysv_t context = xbt_new0(s_smx_ctx_sysv_t, 1);
110
111   context->exception = xbt_new(ex_ctx_t, 1);
112   XBT_CTX_INITIALIZE(context->exception);
113   
114   /* If the user provided a function for the process then use it
115      otherwise is the context for maestro */
116   if(code){
117     context->code = code;
118
119     xbt_assert2(getcontext(&(context->uc)) == 0,
120                 "Error in context saving: %d (%s)", errno, strerror(errno));
121
122     context->uc.uc_link = NULL;
123
124     context->uc.uc_stack.ss_sp =
125       pth_skaddr_makecontext(context->stack, STACK_SIZE);
126
127     context->uc.uc_stack.ss_size =
128       pth_sksize_makecontext(context->stack, STACK_SIZE);
129
130 #ifdef HAVE_VALGRIND_VALGRIND_H
131     context->valgrind_stack_id =
132       VALGRIND_STACK_REGISTER(context->uc.uc_stack.ss_sp,
133                               ((char *) context->uc.uc_stack.ss_sp) +
134                               context->uc.uc_stack.ss_size);
135 #endif /* HAVE_VALGRIND_VALGRIND_H */
136
137     context->argc = argc;
138     context->argv = argv;
139     context->cleanup_func = cleanup_func;
140     context->cleanup_arg = cleanup_arg;
141   }
142   
143   return (smx_context_t)context;
144 }
145
146 static void smx_ctx_sysv_free(smx_context_t pcontext)
147 {
148   int i;
149   smx_ctx_sysv_t context = (smx_ctx_sysv_t)pcontext;   
150   if (context){
151
152     if (context->exception)
153       free(context->exception);
154
155 #ifdef HAVE_VALGRIND_VALGRIND_H
156     VALGRIND_STACK_DEREGISTER(((smx_ctx_sysv_t) context)->valgrind_stack_id);
157 #endif /* HAVE_VALGRIND_VALGRIND_H */
158
159     /* free argv */
160     if (context->argv) {
161       for (i = 0; i < context->argc; i++)
162         if (context->argv[i])
163           free(context->argv[i]);
164
165       free(context->argv);
166     }
167     
168     /* destroy the context */
169     free(context);
170   }
171 }
172
173 static void smx_ctx_sysv_start(smx_context_t context)
174 {  
175   makecontext(&((smx_ctx_sysv_t)context)->uc, smx_ctx_sysv_wrapper, 0);
176 }
177
178 static void smx_ctx_sysv_stop(smx_context_t pcontext)
179 {
180   smx_ctx_sysv_t context = (smx_ctx_sysv_t)pcontext;
181   
182   if (context->cleanup_func)
183     (*context->cleanup_func) (context->cleanup_arg);
184
185   smx_ctx_sysv_suspend((smx_context_t)context);
186 }
187
188 static void smx_ctx_sysv_wrapper()
189 {
190   /*FIXME: I would like to avoid accesing simix_global to get the current
191     context by passing it as an argument of the wrapper function. The problem
192     is that this function is called from smx_ctx_sysv_start, and uses
193     makecontext for calling it, and the stupid posix specification states that
194     all the arguments of the function should be int(32 bits), making it useless
195     in 64-bit architectures where pointers are 64 bit long.
196    */
197   smx_ctx_sysv_t context = 
198     (smx_ctx_sysv_t)simix_global->current_process->context;
199   
200   (context->code) (context->argc, context->argv);
201   
202   smx_ctx_sysv_stop((smx_context_t)context);
203 }
204
205 static void smx_ctx_sysv_suspend(smx_context_t context)
206 {
207   int rv;
208
209   smx_ctx_sysv_t prev_context = ((smx_ctx_sysv_t) context)->prev;
210
211   ((smx_ctx_sysv_t) context)->prev = NULL;
212
213   rv = swapcontext(&((smx_ctx_sysv_t) context)->uc, &prev_context->uc);
214
215   xbt_assert0((rv == 0), "Context swapping failure");
216 }
217
218 static void 
219 smx_ctx_sysv_resume(smx_context_t old_context, smx_context_t new_context)
220 {
221   int rv;
222
223   ((smx_ctx_sysv_t) new_context)->prev = (smx_ctx_sysv_t)old_context;
224
225   rv = swapcontext(&((smx_ctx_sysv_t)old_context)->uc,
226                    &((smx_ctx_sysv_t)new_context)->uc);
227
228   xbt_assert0((rv == 0), "Context swapping failure");
229 }