Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
5834354e0bff9cc8fd38556b63c75b79796ab53f
[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 smx_context_t smx_ctx_sysv_factory_create_maestro_context(void);
49
50 static void smx_ctx_sysv_free(smx_context_t context);
51
52 static void smx_ctx_sysv_start(smx_context_t context);
53
54 static void smx_ctx_sysv_stop(smx_context_t context);
55
56 static void smx_ctx_sysv_suspend(smx_context_t context);
57
58 static void 
59   smx_ctx_sysv_resume(smx_context_t old_context, smx_context_t new_context);
60
61 static void smx_ctx_sysv_wrapper(void);
62
63 /* callback: context fetching */
64 static ex_ctx_t *xbt_ctx_sysv_ex_ctx(void)
65 {
66   /*FIXME: the factory should access simix level datastructures! */
67   return simix_global->current_process->context->exception;
68 }
69
70 /* callback: termination */
71 static void xbt_ctx_sysv_ex_terminate(xbt_ex_t * e)
72 {
73   xbt_ex_display(e);
74   abort();
75 }
76
77 void SIMIX_ctx_sysv_factory_init(smx_context_factory_t *factory)
78 {
79   *factory = xbt_new0(s_smx_context_factory_t, 1);
80
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";
90
91   /* context exception handlers */
92   __xbt_ex_ctx = xbt_ctx_sysv_ex_ctx;
93   __xbt_ex_terminate = xbt_ctx_sysv_ex_terminate;
94 }
95
96 static smx_context_t smx_ctx_sysv_factory_create_maestro_context()
97 {
98   smx_ctx_sysv_t context = xbt_new0(s_smx_ctx_sysv_t, 1);
99
100   context->exception = xbt_new(ex_ctx_t, 1);  
101   XBT_CTX_INITIALIZE(context->exception);
102
103   return (smx_context_t)context;
104 }
105
106 static int smx_ctx_sysv_factory_finalize(smx_context_factory_t * factory)
107 {
108   /*FIXME free(maestro_context->exception);*/
109   free(*factory);
110   *factory = NULL;
111   return 0;
112 }
113
114 static smx_context_t 
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)
117 {
118   smx_ctx_sysv_t context = xbt_new0(s_smx_ctx_sysv_t, 1);
119
120   context->code = code;
121
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 */
135
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;
143 }
144
145 static void smx_ctx_sysv_free(smx_context_t pcontext)
146 {
147   int i;
148   smx_ctx_sysv_t context = (smx_ctx_sysv_t)pcontext;   
149   if (context){
150
151     if (context->exception)
152       free(context->exception);
153
154 #ifdef HAVE_VALGRIND_VALGRIND_H
155     VALGRIND_STACK_DEREGISTER(((smx_ctx_sysv_t) context)->valgrind_stack_id);
156 #endif /* HAVE_VALGRIND_VALGRIND_H */
157
158     /* free argv */
159     if (context->argv) {
160       for (i = 0; i < context->argc; i++)
161         if (context->argv[i])
162           free(context->argv[i]);
163
164       free(context->argv);
165     }
166     
167     /* destroy the context */
168     free(context);
169   }
170 }
171
172 static void smx_ctx_sysv_start(smx_context_t context)
173 {  
174   makecontext(&((smx_ctx_sysv_t)context)->uc, smx_ctx_sysv_wrapper, 0);
175 }
176
177 static void smx_ctx_sysv_stop(smx_context_t pcontext)
178 {
179   smx_ctx_sysv_t context = (smx_ctx_sysv_t)pcontext;
180   
181   if (context->cleanup_func)
182     (*context->cleanup_func) (context->cleanup_arg);
183
184   smx_ctx_sysv_suspend((smx_context_t)context);
185 }
186
187 static void smx_ctx_sysv_wrapper()
188 {
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.
195    */
196   smx_ctx_sysv_t context = 
197     (smx_ctx_sysv_t)simix_global->current_process->context;
198   
199   (context->code) (context->argc, context->argv);
200   
201   smx_ctx_sysv_stop((smx_context_t)context);
202 }
203
204 static void smx_ctx_sysv_suspend(smx_context_t context)
205 {
206   int rv;
207
208   smx_ctx_sysv_t prev_context = ((smx_ctx_sysv_t) context)->prev;
209
210   ((smx_ctx_sysv_t) context)->prev = NULL;
211
212   rv = swapcontext(&((smx_ctx_sysv_t) context)->uc, &prev_context->uc);
213
214   xbt_assert0((rv == 0), "Context swapping failure");
215 }
216
217 static void 
218 smx_ctx_sysv_resume(smx_context_t old_context, smx_context_t new_context)
219 {
220   int rv;
221
222   ((smx_ctx_sysv_t) new_context)->prev = (smx_ctx_sysv_t)old_context;
223
224   rv = swapcontext(&((smx_ctx_sysv_t)old_context)->uc,
225                    &((smx_ctx_sysv_t)new_context)->uc);
226
227   xbt_assert0((rv == 0), "Context swapping failure");
228 }