1 /* context_sysv - context switching with ucontextes from System V */
3 /* Copyright (c) 2009, 2010. The SimGrid Team.
4 * All rights reserved. */
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. */
10 #include "smx_context_sysv_private.h"
11 #include "xbt/parmap.h"
12 #include "simix/private.h"
14 #ifdef HAVE_VALGRIND_VALGRIND_H
15 # include <valgrind/valgrind.h>
16 #endif /* HAVE_VALGRIND_VALGRIND_H */
19 #include "win32_ucontext.h"
20 #include "win32_ucontext.c"
25 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(simix_context);
27 static xbt_parmap_t parmap;
30 smx_ctx_sysv_create_context(xbt_main_func_t code, int argc, char **argv,
31 void_pfn_smxprocess_t cleanup_func, void* data);
33 static void smx_ctx_sysv_wrapper(int count, ...);
35 void SIMIX_ctx_sysv_factory_init(smx_context_factory_t *factory)
37 smx_ctx_base_factory_init(factory);
38 VERB0("Activating SYSV context factory");
40 (*factory)->finalize = smx_ctx_sysv_factory_finalize;
41 (*factory)->create_context = smx_ctx_sysv_create_context;
42 /* Do not overload that method (*factory)->finalize */
43 (*factory)->free = smx_ctx_sysv_free;
44 (*factory)->stop = smx_ctx_sysv_stop;
45 (*factory)->suspend = smx_ctx_sysv_suspend;
46 (*factory)->name = "smx_sysv_context_factory";
48 if (smx_parallel_contexts) {
49 #ifdef CONTEXT_THREADS /* To use parallel ucontexts a thread pool is needed */
50 parmap = xbt_parmap_new(2);
51 (*factory)->runall = smx_ctx_sysv_runall_parallel;
52 (*factory)->self = smx_ctx_sysv_self_parallel;
54 THROW0(arg_error, 0, "No thread support for parallel context execution");
57 (*factory)->runall = smx_ctx_sysv_runall;
61 int smx_ctx_sysv_factory_finalize(smx_context_factory_t *factory)
64 xbt_parmap_destroy(parmap);
65 return smx_ctx_base_factory_finalize(factory);
69 smx_ctx_sysv_create_context_sized(size_t size, xbt_main_func_t code,
70 int argc, char **argv,
71 void_pfn_smxprocess_t cleanup_func,
75 smx_ctx_sysv_t context =
76 (smx_ctx_sysv_t) smx_ctx_base_factory_create_context_sized(size,
83 /* If the user provided a function for the process then use it
84 otherwise is the context for maestro */
87 xbt_assert2(getcontext(&(context->uc)) == 0,
88 "Error in context saving: %d (%s)", errno,
91 context->uc.uc_link = NULL;
93 context->uc.uc_stack.ss_sp =
94 pth_skaddr_makecontext(context->stack, CONTEXT_STACK_SIZE);
96 context->uc.uc_stack.ss_size =
97 pth_sksize_makecontext(context->stack, CONTEXT_STACK_SIZE);
99 #ifdef HAVE_VALGRIND_VALGRIND_H
100 context->valgrind_stack_id =
101 VALGRIND_STACK_REGISTER(context->uc.uc_stack.ss_sp,
102 ((char *) context->uc.uc_stack.ss_sp) +
103 context->uc.uc_stack.ss_size);
104 #endif /* HAVE_VALGRIND_VALGRIND_H */
105 ctx_addr = (uintptr_t)context;
106 /* This switch select a case base on a static value: the compiler optimizes it out */
107 /* It could be replaced by a set of #ifdef/#else/#endif blocks */
108 switch(sizeof(uintptr_t) / sizeof(int)) {
110 makecontext(&((smx_ctx_sysv_t) context)->uc, (void (*)())smx_ctx_sysv_wrapper,
111 2, 1, (int)ctx_addr);
114 makecontext(&((smx_ctx_sysv_t) context)->uc, (void (*)())smx_ctx_sysv_wrapper,
115 3, 2, (int)(ctx_addr >> (8 * sizeof(int))), (int)(ctx_addr));
121 maestro_context = context;
124 return (smx_context_t) context;
129 smx_ctx_sysv_create_context(xbt_main_func_t code, int argc, char **argv,
130 void_pfn_smxprocess_t cleanup_func,
134 return smx_ctx_sysv_create_context_sized(sizeof(s_smx_ctx_sysv_t),
135 code, argc, argv, cleanup_func,
140 void smx_ctx_sysv_free(smx_context_t context)
145 #ifdef HAVE_VALGRIND_VALGRIND_H
146 VALGRIND_STACK_DEREGISTER(((smx_ctx_sysv_t)
147 context)->valgrind_stack_id);
148 #endif /* HAVE_VALGRIND_VALGRIND_H */
151 smx_ctx_base_free(context);
154 void smx_ctx_sysv_stop(smx_context_t context)
156 smx_ctx_base_stop(context);
157 smx_ctx_sysv_suspend(context);
160 void smx_ctx_sysv_wrapper(int count, ...)
162 uintptr_t ctx_addr = 0;
164 smx_ctx_sysv_t context;
168 for(i = 0; i < count; i++) {
169 ctx_addr <<= 8*sizeof(int);
170 ctx_addr |= (uintptr_t)va_arg(ap, int);
173 context = (smx_ctx_sysv_t)ctx_addr;
174 (context->super.code) (context->super.argc, context->super.argv);
176 smx_ctx_sysv_stop((smx_context_t) context);
179 void smx_ctx_sysv_suspend(smx_context_t context)
181 smx_current_context = (smx_context_t)maestro_context;
182 int rv = swapcontext(&((smx_ctx_sysv_t) context)->uc, &((smx_ctx_sysv_t)context)->old_uc);
184 xbt_assert0((rv == 0), "Context swapping failure");
187 void smx_ctx_sysv_resume(smx_context_t context)
189 smx_current_context = context;
190 int rv = swapcontext(&((smx_ctx_sysv_t)context)->old_uc, &((smx_ctx_sysv_t) context)->uc);
192 xbt_assert0((rv == 0), "Context swapping failure");
195 void smx_ctx_sysv_runall(xbt_dynar_t processes)
197 smx_process_t process;
200 xbt_dynar_foreach(processes, cursor, process) {
201 DEBUG2("Schedule item %u of %lu",cursor,xbt_dynar_length(processes));
202 smx_ctx_sysv_resume(process->context);
204 xbt_dynar_reset(processes);
207 void smx_ctx_sysv_resume_parallel(smx_process_t process)
209 smx_context_t context = process->context;
210 xbt_os_thread_set_extra_data(context);
211 int rv = swapcontext(&((smx_ctx_sysv_t)context)->old_uc, &((smx_ctx_sysv_t) context)->uc);
212 xbt_os_thread_set_extra_data(NULL);
214 xbt_assert0((rv == 0), "Context swapping failure");
217 void smx_ctx_sysv_runall_parallel(xbt_dynar_t processes)
219 xbt_parmap_apply(parmap, (void_f_pvoid_t)smx_ctx_sysv_resume_parallel, processes);
220 xbt_dynar_reset(processes);
223 smx_context_t smx_ctx_sysv_self_parallel(void)
225 smx_context_t self_context = (smx_context_t) xbt_os_thread_get_extra_data();
226 return self_context ? self_context : (smx_context_t) maestro_context;