Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
bf0558853e94dcb56305a76dcad05e10a230b792
[simgrid.git] / src / xbt / xbt_context_sysv.c
1
2 #include "xbt/ex_interface.h"
3 #include "xbt/xbt_context_private.h"
4
5 #include "context_sysv_config.h"        /* loads context system definitions                             */
6 #include "portable.h"
7 #include <ucontext.h>           /* context relative declarations                                */
8 #define STACK_SIZE 128*1024     /* lower this if you want to reduce the memory consumption      */
9
10 typedef struct s_xbt_ctx_sysv {
11   XBT_CTX_BASE_T;
12   ucontext_t uc;                /* the thread that execute the code                             */
13   char stack[STACK_SIZE];       /* the thread stack size                                        */
14   struct s_xbt_ctx_sysv *prev;  /* the previous thread                                              */
15 } s_xbt_ctx_sysv_t, *xbt_ctx_sysv_t;
16
17
18 /* callback: context fetching */
19 static ex_ctx_t *xbt_jcontext_ex_ctx(void);
20
21 /* callback: termination */
22 static void xbt_jcontext_ex_terminate(xbt_ex_t * e);
23
24 static xbt_context_t
25 xbt_ctx_sysv_factory_create_context(const char *name, xbt_main_func_t code,
26                                     void_f_pvoid_t startup_func,
27                                     void *startup_arg,
28                                     void_f_pvoid_t cleanup_func,
29                                     void *cleanup_arg, int argc, char **argv);
30
31 static int xbt_ctx_sysv_factory_finalize(xbt_context_factory_t * factory);
32
33 static int
34 xbt_ctx_sysv_factory_create_maestro_context(xbt_context_t * maestro);
35
36 static void xbt_ctx_sysv_free(xbt_context_t context);
37
38 static void xbt_ctx_sysv_kill(xbt_context_t context);
39
40 static void xbt_ctx_sysv_schedule(xbt_context_t context);
41
42 static void xbt_ctx_sysv_yield(void);
43
44 static void xbt_ctx_sysv_start(xbt_context_t context);
45
46 static void xbt_ctx_sysv_stop(int exit_code);
47
48 static void xbt_ctx_sysv_swap(xbt_context_t context);
49
50 static void xbt_ctx_sysv_schedule(xbt_context_t context);
51
52 static void xbt_ctx_sysv_yield(void);
53
54 static void xbt_ctx_sysv_suspend(xbt_context_t context);
55
56 static void xbt_ctx_sysv_resume(xbt_context_t context);
57
58 static void xbt_ctx_sysv_wrapper(void);
59
60 /* callback: context fetching */
61 static ex_ctx_t *xbt_ctx_sysv_ex_ctx(void)
62 {
63   return current_context->exception;
64 }
65
66 /* callback: termination */
67 static void xbt_ctx_sysv_ex_terminate(xbt_ex_t * e)
68 {
69   xbt_ex_display(e);
70   abort();
71 }
72
73
74 void xbt_ctx_sysv_factory_init(xbt_context_factory_t * factory)
75 {
76   /* context exception */
77   *factory = xbt_new0(s_xbt_context_factory_t, 1);
78
79   (*factory)->create_context = xbt_ctx_sysv_factory_create_context;
80   (*factory)->finalize = xbt_ctx_sysv_factory_finalize;
81   (*factory)->create_maestro_context =
82     xbt_ctx_sysv_factory_create_maestro_context;
83   (*factory)->name = "ctx_sysv_context_factory";
84
85   /* context exception handlers */
86   __xbt_ex_ctx = xbt_ctx_sysv_ex_ctx;
87   __xbt_ex_terminate = xbt_ctx_sysv_ex_terminate;
88 }
89
90 static int
91 xbt_ctx_sysv_factory_create_maestro_context(xbt_context_t * maestro)
92 {
93
94   xbt_ctx_sysv_t context = xbt_new0(s_xbt_ctx_sysv_t, 1);
95
96   context->exception = xbt_new(ex_ctx_t, 1);
97   XBT_CTX_INITIALIZE(context->exception);
98
99   *maestro = (xbt_context_t) context;
100
101   return 0;
102
103 }
104
105
106 static int xbt_ctx_sysv_factory_finalize(xbt_context_factory_t * factory)
107 {
108   free(maestro_context->exception);
109   free(*factory);
110   *factory = NULL;
111   return 0;
112 }
113
114 static xbt_context_t
115 xbt_ctx_sysv_factory_create_context(const char *name, xbt_main_func_t code,
116                                     void_f_pvoid_t startup_func,
117                                     void *startup_arg,
118                                     void_f_pvoid_t cleanup_func,
119                                     void *cleanup_arg, int argc, char **argv)
120 {
121   xbt_ctx_sysv_t context = xbt_new0(s_xbt_ctx_sysv_t, 1);
122
123   context->code = code;
124   context->name = xbt_strdup(name);
125
126   xbt_assert2(getcontext(&(context->uc)) == 0,
127               "Error in context saving: %d (%s)", errno, strerror(errno));
128   context->uc.uc_link = NULL;
129   context->uc.uc_stack.ss_sp =
130     pth_skaddr_makecontext(context->stack, STACK_SIZE);
131   context->uc.uc_stack.ss_size =
132     pth_sksize_makecontext(context->stack, STACK_SIZE);
133
134   context->exception = xbt_new(ex_ctx_t, 1);
135   XBT_CTX_INITIALIZE(context->exception);
136   context->iwannadie = 0;       /* useless but makes valgrind happy */
137   context->argc = argc;
138   context->argv = argv;
139   context->startup_func = startup_func;
140   context->startup_arg = startup_arg;
141   context->cleanup_func = cleanup_func;
142   context->cleanup_arg = cleanup_arg;
143
144
145   context->free = xbt_ctx_sysv_free;
146   context->kill = xbt_ctx_sysv_kill;
147   context->schedule = xbt_ctx_sysv_schedule;
148   context->yield = xbt_ctx_sysv_yield;
149   context->start = xbt_ctx_sysv_start;
150   context->stop = xbt_ctx_sysv_stop;
151
152   return (xbt_context_t) context;
153 }
154
155 static void xbt_ctx_sysv_free(xbt_context_t context)
156 {
157   if (context) {
158     free(context->name);
159
160     if (context->argv) {
161       int i;
162
163       for (i = 0; i < context->argc; i++)
164         if (context->argv[i])
165           free(context->argv[i]);
166
167       free(context->argv);
168     }
169
170     if (context->exception)
171       free(context->exception);
172
173     /* finally destroy the context */
174     free(context);
175   }
176 }
177
178 static void xbt_ctx_sysv_kill(xbt_context_t context)
179 {
180   context->iwannadie = 1;
181   xbt_ctx_sysv_swap(context);
182 }
183
184 /** 
185  * \param context the winner
186  *
187  * Calling this function blocks the current context and schedule \a context.  
188  * When \a context will call xbt_context_yield, it will return
189  * to this function as if nothing had happened.
190  * 
191  * Only the maestro can call this function to run a given process.
192  */
193 static void xbt_ctx_sysv_schedule(xbt_context_t context)
194 {
195   xbt_assert0((current_context == maestro_context),
196               "You are not supposed to run this function here!");
197   xbt_ctx_sysv_swap(context);
198 }
199
200 /** 
201  * Calling this function makes the current context yield. The context
202  * that scheduled it returns from xbt_context_schedule as if nothing
203  * had happened.
204  * 
205  * Only the processes can call this function, giving back the control
206  * to the maestro
207  */
208 static void xbt_ctx_sysv_yield(void)
209 {
210   xbt_assert0((current_context != maestro_context),
211               "You are not supposed to run this function here!");
212   xbt_ctx_sysv_swap(current_context);
213 }
214
215 static void xbt_ctx_sysv_start(xbt_context_t context)
216 {
217   makecontext(&(((xbt_ctx_sysv_t) context)->uc), xbt_ctx_sysv_wrapper, 0);
218 }
219
220 static void xbt_ctx_sysv_stop(int exit_code)
221 {
222   if (current_context->cleanup_func)
223     ((*current_context->cleanup_func)) (current_context->cleanup_arg);
224
225   xbt_swag_remove(current_context, context_living);
226   xbt_swag_insert(current_context, context_to_destroy);
227
228   xbt_ctx_sysv_swap(current_context);
229 }
230
231 static void xbt_ctx_sysv_swap(xbt_context_t context)
232 {
233   xbt_assert0(current_context, "You have to call context_init() first.");
234   xbt_assert0(context, "Invalid argument");
235
236   if (((xbt_ctx_sysv_t) context)->prev == NULL)
237     xbt_ctx_sysv_resume(context);
238   else
239     xbt_ctx_sysv_suspend(context);
240
241   if (current_context->iwannadie)
242     xbt_ctx_sysv_stop(1);
243 }
244
245 static void xbt_ctx_sysv_wrapper(void)
246 {
247   if (current_context->startup_func)
248     (*current_context->startup_func) (current_context->startup_arg);
249
250   xbt_ctx_sysv_stop((*(current_context->code))
251                     (current_context->argc, current_context->argv));
252 }
253
254 static void xbt_ctx_sysv_suspend(xbt_context_t context)
255 {
256   int rv;
257
258   xbt_ctx_sysv_t prev_context = ((xbt_ctx_sysv_t) context)->prev;
259
260   current_context = (xbt_context_t) (((xbt_ctx_sysv_t) context)->prev);
261
262   ((xbt_ctx_sysv_t) context)->prev = NULL;
263
264   rv = swapcontext(&(((xbt_ctx_sysv_t) context)->uc), &(prev_context->uc));
265
266   xbt_assert0((rv == 0), "Context swapping failure");
267 }
268
269 static void xbt_ctx_sysv_resume(xbt_context_t context)
270 {
271   int rv;
272
273   ((xbt_ctx_sysv_t) context)->prev = (xbt_ctx_sysv_t) current_context;
274
275   current_context = context;
276
277   rv =
278     swapcontext(&(((xbt_ctx_sysv_t) context)->prev->uc),
279                 &(((xbt_ctx_sysv_t) context)->uc));
280
281   xbt_assert0((rv == 0), "Context swapping failure");
282 }