Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
0248f2840b95e34b62c6b92bbd7f004c0554bfc0
[simgrid.git] / src / simix / smx_context_sysv.c
1 /* context_sysv - context switching with ucontextes from System V           */
2
3 /* Copyright (c) 2009, 2010. The SimGrid Team.
4  * All rights reserved.                                                     */
5
6  /* This program is free software; you can redistribute it and/or modify it
7   * under the terms of the license (GNU LGPL) which comes with this package. */
8
9 #include <stdarg.h>
10
11 #include "smx_context_sysv_private.h"
12 #include "xbt/parmap.h"
13 #include "simix/private.h"
14 #include "gras_config.h"
15
16 #ifdef HAVE_VALGRIND_VALGRIND_H
17 #  include <valgrind/valgrind.h>
18 #endif                          /* HAVE_VALGRIND_VALGRIND_H */
19
20 #ifdef _XBT_WIN32
21 #include "win32_ucontext.h"
22 #include "win32_ucontext.c"
23 #else
24 #include "ucontext.h"
25 #endif
26
27 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(simix_context);
28
29 static xbt_parmap_t parmap;
30
31 static smx_context_t
32 smx_ctx_sysv_create_context(xbt_main_func_t code, int argc, char **argv,
33     void_pfn_smxprocess_t cleanup_func, void* data);
34
35 static void smx_ctx_sysv_wrapper(int count, ...);
36
37 void SIMIX_ctx_sysv_factory_init(smx_context_factory_t *factory)
38 {
39   smx_ctx_base_factory_init(factory);
40   VERB0("Activating SYSV context factory");
41
42   (*factory)->finalize = smx_ctx_sysv_factory_finalize;
43   (*factory)->create_context = smx_ctx_sysv_create_context;
44   /* Do not overload that method (*factory)->finalize */
45   (*factory)->free = smx_ctx_sysv_free;
46   (*factory)->stop = smx_ctx_sysv_stop;
47   (*factory)->suspend = smx_ctx_sysv_suspend;
48   (*factory)->name = "smx_sysv_context_factory";
49
50   if (smx_parallel_contexts) {
51 #ifdef CONTEXT_THREADS  /* To use parallel ucontexts a thread pool is needed */
52     parmap = xbt_parmap_new(2);
53     (*factory)->runall = smx_ctx_sysv_runall_parallel;
54     (*factory)->self = smx_ctx_sysv_self_parallel;
55 #else
56     THROW0(arg_error, 0, "No thread support for parallel context execution");
57 #endif
58   }else{
59     (*factory)->runall = smx_ctx_sysv_runall;
60   }    
61 }
62
63 int smx_ctx_sysv_factory_finalize(smx_context_factory_t *factory)
64
65   if(parmap)
66     xbt_parmap_destroy(parmap);
67   return smx_ctx_base_factory_finalize(factory);
68 }
69
70 smx_context_t
71 smx_ctx_sysv_create_context_sized(size_t size, xbt_main_func_t code,
72                                   int argc, char **argv,
73                                   void_pfn_smxprocess_t cleanup_func,
74                                   void *data)
75 {
76   uintptr_t ctx_addr;
77   smx_ctx_sysv_t context =
78       (smx_ctx_sysv_t) smx_ctx_base_factory_create_context_sized(size,
79                                                                  code,
80                                                                  argc,
81                                                                  argv,
82                                                                  cleanup_func,
83                                                                  data);
84
85   /* If the user provided a function for the process then use it
86      otherwise is the context for maestro */
87   if (code) {
88
89     xbt_assert2(getcontext(&(context->uc)) == 0,
90                 "Error in context saving: %d (%s)", errno,
91                 strerror(errno));
92
93     context->uc.uc_link = NULL;
94
95     context->uc.uc_stack.ss_sp =
96         pth_skaddr_makecontext(context->stack, CONTEXT_STACK_SIZE);
97
98     context->uc.uc_stack.ss_size =
99         pth_sksize_makecontext(context->stack, CONTEXT_STACK_SIZE);
100
101 #ifdef HAVE_VALGRIND_VALGRIND_H
102     context->valgrind_stack_id =
103         VALGRIND_STACK_REGISTER(context->uc.uc_stack.ss_sp,
104                                 ((char *) context->uc.uc_stack.ss_sp) +
105                                 context->uc.uc_stack.ss_size);
106 #endif                          /* HAVE_VALGRIND_VALGRIND_H */
107     ctx_addr = (uintptr_t)context;
108     makecontext(&((smx_ctx_sysv_t) context)->uc, (void (*)())smx_ctx_sysv_wrapper,
109                 SIZEOF_VOIDP / SIZEOF_INT + 1, SIZEOF_VOIDP / SIZEOF_INT,
110 #if (SIZEOF_VOIDP == SIZEOF_INT)
111                 (int)ctx_addr
112 #elif (SIZEOF_VOIDP == 2 * SIZEOF_INT)
113                 (int)(ctx_addr >> (8 * sizeof(int))),
114                 (int)(ctx_addr)
115 #else
116 #error Your architecture is not supported yet
117 #endif
118    );
119   }else{
120     maestro_context = context;
121   }
122
123   return (smx_context_t) context;
124
125 }
126
127 static smx_context_t
128 smx_ctx_sysv_create_context(xbt_main_func_t code, int argc, char **argv,
129     void_pfn_smxprocess_t cleanup_func,
130     void *data)
131 {
132
133   return smx_ctx_sysv_create_context_sized(sizeof(s_smx_ctx_sysv_t),
134                                            code, argc, argv, cleanup_func,
135                                            data);
136
137 }
138
139 void smx_ctx_sysv_free(smx_context_t context)
140 {
141
142   if (context) {
143
144 #ifdef HAVE_VALGRIND_VALGRIND_H
145     VALGRIND_STACK_DEREGISTER(((smx_ctx_sysv_t)
146                                context)->valgrind_stack_id);
147 #endif                          /* HAVE_VALGRIND_VALGRIND_H */
148
149   }
150   smx_ctx_base_free(context);
151 }
152
153 void smx_ctx_sysv_stop(smx_context_t context)
154 {
155   smx_ctx_base_stop(context);
156   smx_ctx_sysv_suspend(context);
157 }
158
159 void smx_ctx_sysv_wrapper(int count, ...)
160
161   uintptr_t ctx_addr = 0;
162   va_list ap;
163   smx_ctx_sysv_t context;
164
165   va_start(ap, count);
166 #if (SIZEOF_VOIDP <= SIZEOF_INT)
167   ctx_addr = (uintptr_t)va_arg(ap, int);
168 #else
169   int i;
170   for(i = 0; i < count; i++) {
171      ctx_addr <<= 8*sizeof(int);
172      ctx_addr |= (uintptr_t)va_arg(ap, int);
173   }
174 #endif
175   va_end(ap);
176   context = (smx_ctx_sysv_t)ctx_addr;
177   (context->super.code) (context->super.argc, context->super.argv);
178
179   smx_ctx_sysv_stop((smx_context_t) context);
180 }
181
182 void smx_ctx_sysv_suspend(smx_context_t context)
183 {
184   smx_current_context = (smx_context_t)maestro_context;
185   int rv = swapcontext(&((smx_ctx_sysv_t) context)->uc, &((smx_ctx_sysv_t)context)->old_uc);
186
187   xbt_assert0((rv == 0), "Context swapping failure");
188 }
189
190 void smx_ctx_sysv_resume(smx_context_t context)
191 {
192   smx_current_context = context; 
193   int rv = swapcontext(&((smx_ctx_sysv_t)context)->old_uc, &((smx_ctx_sysv_t) context)->uc);
194
195   xbt_assert0((rv == 0), "Context swapping failure");
196 }
197
198 void smx_ctx_sysv_runall(xbt_dynar_t processes)
199 {
200   smx_process_t process;
201   unsigned int cursor;
202
203   xbt_dynar_foreach(processes, cursor, process) {
204     DEBUG2("Schedule item %u of %lu",cursor,xbt_dynar_length(processes));
205     smx_ctx_sysv_resume(process->context);
206   }
207   xbt_dynar_reset(processes);
208 }
209
210 void smx_ctx_sysv_resume_parallel(smx_process_t process)
211 {
212   smx_context_t context = process->context;
213   xbt_os_thread_set_extra_data(context);
214   int rv = swapcontext(&((smx_ctx_sysv_t)context)->old_uc, &((smx_ctx_sysv_t) context)->uc);
215   xbt_os_thread_set_extra_data(NULL);
216
217   xbt_assert0((rv == 0), "Context swapping failure");
218 }
219
220 void smx_ctx_sysv_runall_parallel(xbt_dynar_t processes)
221 {
222   xbt_parmap_apply(parmap, (void_f_pvoid_t)smx_ctx_sysv_resume_parallel, processes);
223   xbt_dynar_reset(processes);
224 }
225
226 smx_context_t smx_ctx_sysv_self_parallel(void)
227 {
228   smx_context_t self_context = (smx_context_t) xbt_os_thread_get_extra_data();
229   return self_context ? self_context : (smx_context_t) maestro_context;
230 }