Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Add a missing file to the archive
[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   /*FIXME free(maestro_context->exception);*/
96   free(*factory);
97   *factory = NULL;
98   return 0;
99 }
100
101 static smx_context_t 
102 smx_ctx_sysv_factory_create_context(xbt_main_func_t code, int argc, char** argv, 
103                                     void_f_pvoid_t cleanup_func, void* cleanup_arg)
104 {
105   smx_ctx_sysv_t context = xbt_new0(s_smx_ctx_sysv_t, 1);
106
107   context->exception = xbt_new(ex_ctx_t, 1);
108   XBT_CTX_INITIALIZE(context->exception);
109   
110   /* If the user provided a function for the process then use it
111      otherwise is the context for maestro */
112   if(code){
113     context->code = code;
114
115     xbt_assert2(getcontext(&(context->uc)) == 0,
116                 "Error in context saving: %d (%s)", errno, strerror(errno));
117
118     context->uc.uc_link = NULL;
119
120     context->uc.uc_stack.ss_sp =
121       pth_skaddr_makecontext(context->stack, STACK_SIZE);
122
123     context->uc.uc_stack.ss_size =
124       pth_sksize_makecontext(context->stack, STACK_SIZE);
125
126 #ifdef HAVE_VALGRIND_VALGRIND_H
127     context->valgrind_stack_id =
128       VALGRIND_STACK_REGISTER(context->uc.uc_stack.ss_sp,
129                               ((char *) context->uc.uc_stack.ss_sp) +
130                               context->uc.uc_stack.ss_size);
131 #endif /* HAVE_VALGRIND_VALGRIND_H */
132
133     context->argc = argc;
134     context->argv = argv;
135     context->cleanup_func = cleanup_func;
136     context->cleanup_arg = cleanup_arg;
137   }
138   
139   return (smx_context_t)context;
140 }
141
142 static void smx_ctx_sysv_free(smx_context_t pcontext)
143 {
144   int i;
145   smx_ctx_sysv_t context = (smx_ctx_sysv_t)pcontext;   
146   if (context){
147
148     if (context->exception)
149       free(context->exception);
150
151 #ifdef HAVE_VALGRIND_VALGRIND_H
152     VALGRIND_STACK_DEREGISTER(((smx_ctx_sysv_t) context)->valgrind_stack_id);
153 #endif /* HAVE_VALGRIND_VALGRIND_H */
154
155     /* free argv */
156     if (context->argv) {
157       for (i = 0; i < context->argc; i++)
158         if (context->argv[i])
159           free(context->argv[i]);
160
161       free(context->argv);
162     }
163     
164     /* destroy the context */
165     free(context);
166   }
167 }
168
169 static void smx_ctx_sysv_start(smx_context_t context)
170 {  
171   makecontext(&((smx_ctx_sysv_t)context)->uc, smx_ctx_sysv_wrapper, 0);
172 }
173
174 static void smx_ctx_sysv_stop(smx_context_t pcontext)
175 {
176   smx_ctx_sysv_t context = (smx_ctx_sysv_t)pcontext;
177   
178   if (context->cleanup_func)
179     (*context->cleanup_func) (context->cleanup_arg);
180
181   smx_ctx_sysv_suspend((smx_context_t)context);
182 }
183
184 static void smx_ctx_sysv_wrapper()
185 {
186   /*FIXME: I would like to avoid accesing simix_global to get the current
187     context by passing it as an argument of the wrapper function. The problem
188     is that this function is called from smx_ctx_sysv_start, and uses
189     makecontext for calling it, and the stupid posix specification states that
190     all the arguments of the function should be int(32 bits), making it useless
191     in 64-bit architectures where pointers are 64 bit long.
192    */
193   smx_ctx_sysv_t context = 
194     (smx_ctx_sysv_t)simix_global->current_process->context;
195   
196   (context->code) (context->argc, context->argv);
197   
198   smx_ctx_sysv_stop((smx_context_t)context);
199 }
200
201 static void smx_ctx_sysv_suspend(smx_context_t context)
202 {
203   int rv;
204
205   smx_ctx_sysv_t prev_context = ((smx_ctx_sysv_t) context)->prev;
206
207   ((smx_ctx_sysv_t) context)->prev = NULL;
208
209   rv = swapcontext(&((smx_ctx_sysv_t) context)->uc, &prev_context->uc);
210
211   xbt_assert0((rv == 0), "Context swapping failure");
212 }
213
214 static void 
215 smx_ctx_sysv_resume(smx_context_t old_context, smx_context_t new_context)
216 {
217   int rv;
218
219   ((smx_ctx_sysv_t) new_context)->prev = (smx_ctx_sysv_t)old_context;
220
221   rv = swapcontext(&((smx_ctx_sysv_t)old_context)->uc,
222                    &((smx_ctx_sysv_t)new_context)->uc);
223
224   xbt_assert0((rv == 0), "Context swapping failure");
225 }