Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
fixes to make dist
[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 "private.h"
11 #include "context_sysv_config.h"        /* loads context system definitions */
12 #include "portable.h"
13 #include <ucontext.h>           /* context relative declarations */
14
15 /* lower this if you want to reduce the memory consumption  */
16 #define STACK_SIZE 128*1024
17
18 #ifdef HAVE_VALGRIND_VALGRIND_H
19 #  include <valgrind/valgrind.h>
20 #endif /* HAVE_VALGRIND_VALGRIND_H */
21
22 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(simix_context);
23
24 typedef struct s_smx_ctx_sysv {
25   SMX_CTX_BASE_T;
26   ucontext_t uc;                /* the thread that execute the code */
27   char stack[STACK_SIZE];       /* the thread stack size */
28 #ifdef HAVE_VALGRIND_VALGRIND_H
29   unsigned int valgrind_stack_id;       /* the valgrind stack id */
30 #endif                          
31 } s_smx_ctx_sysv_t, *smx_ctx_sysv_t;
32
33 static smx_context_t 
34 smx_ctx_sysv_factory_create_context(xbt_main_func_t code, int argc, char** argv, 
35     void_f_pvoid_t cleanup_func, void* cleanup_arg);
36
37 static int smx_ctx_sysv_factory_finalize(smx_context_factory_t *factory);
38
39 static void smx_ctx_sysv_free(smx_context_t context);
40 static void smx_ctx_sysv_stop(smx_context_t context);
41 static void smx_ctx_sysv_suspend(smx_context_t context);
42 static void smx_ctx_sysv_resume(smx_context_t new_context);
43
44 static void smx_ctx_sysv_wrapper(void);
45
46 void SIMIX_ctx_sysv_factory_init(smx_context_factory_t *factory)
47 {
48   *factory = xbt_new0(s_smx_context_factory_t, 1);
49
50   (*factory)->create_context = smx_ctx_sysv_factory_create_context;
51   (*factory)->finalize = smx_ctx_sysv_factory_finalize;
52   (*factory)->free = smx_ctx_sysv_free;
53   (*factory)->stop = smx_ctx_sysv_stop;
54   (*factory)->suspend = smx_ctx_sysv_suspend;
55   (*factory)->resume = smx_ctx_sysv_resume;
56   (*factory)->name = "smx_sysv_context_factory";
57 }
58
59 static int smx_ctx_sysv_factory_finalize(smx_context_factory_t * factory)
60 {
61   free(*factory);
62   *factory = NULL;
63   return 0;
64 }
65
66 static smx_context_t 
67 smx_ctx_sysv_factory_create_context(xbt_main_func_t code, int argc, char** argv, 
68     void_f_pvoid_t cleanup_func, void* cleanup_arg)
69 {
70   smx_ctx_sysv_t context = xbt_new0(s_smx_ctx_sysv_t, 1);
71
72   /* If the user provided a function for the process then use it
73      otherwise is the context for maestro */
74   if(code){
75     context->code = code;
76
77     xbt_assert2(getcontext(&(context->uc)) == 0,
78         "Error in context saving: %d (%s)", errno, strerror(errno));
79
80     context->uc.uc_link = NULL;
81
82     context->uc.uc_stack.ss_sp =
83         pth_skaddr_makecontext(context->stack, STACK_SIZE);
84
85     context->uc.uc_stack.ss_size =
86         pth_sksize_makecontext(context->stack, STACK_SIZE);
87
88 #ifdef HAVE_VALGRIND_VALGRIND_H
89     context->valgrind_stack_id =
90         VALGRIND_STACK_REGISTER(context->uc.uc_stack.ss_sp,
91             ((char *) context->uc.uc_stack.ss_sp) +
92             context->uc.uc_stack.ss_size);
93 #endif /* HAVE_VALGRIND_VALGRIND_H */
94
95     context->argc = argc;
96     context->argv = argv;
97     context->cleanup_func = cleanup_func;
98     context->cleanup_arg = cleanup_arg;
99
100     makecontext(&((smx_ctx_sysv_t)context)->uc, smx_ctx_sysv_wrapper, 0);
101   }
102
103   return (smx_context_t)context;
104 }
105
106 static void smx_ctx_sysv_free(smx_context_t pcontext)
107 {
108   int i;
109   smx_ctx_sysv_t context = (smx_ctx_sysv_t)pcontext;   
110   if (context){
111
112 #ifdef HAVE_VALGRIND_VALGRIND_H
113     VALGRIND_STACK_DEREGISTER(((smx_ctx_sysv_t) context)->valgrind_stack_id);
114 #endif /* HAVE_VALGRIND_VALGRIND_H */
115
116     /* free argv */
117     if (context->argv) {
118       for (i = 0; i < context->argc; i++)
119         if (context->argv[i])
120           free(context->argv[i]);
121
122       free(context->argv);
123     }
124
125     /* destroy the context */
126     free(context);
127   }
128 }
129
130 static void smx_ctx_sysv_stop(smx_context_t pcontext)
131 {
132   smx_ctx_sysv_t context = (smx_ctx_sysv_t)pcontext;
133
134   if (context->cleanup_func)
135     (*context->cleanup_func) (context->cleanup_arg);
136
137   smx_ctx_sysv_suspend(pcontext);
138 }
139
140 static void smx_ctx_sysv_wrapper()
141 {
142   /*FIXME: I would like to avoid accessing simix_global to get the current
143     context by passing it as an argument of the wrapper function. The problem
144     is that this function is called from smx_ctx_sysv_start, and uses
145     makecontext for calling it, and the stupid posix specification states that
146     all the arguments of the function should be int(32 bits), making it useless
147     in 64-bit architectures where pointers are 64 bit long.
148    */
149   smx_ctx_sysv_t context = 
150       (smx_ctx_sysv_t)simix_global->current_process->context;
151
152   (context->code) (context->argc, context->argv);
153
154   smx_ctx_sysv_stop((smx_context_t)context);
155 }
156
157 static void smx_ctx_sysv_suspend(smx_context_t context) {
158   int rv;
159   ucontext_t maestro_ctx = ((smx_ctx_sysv_t)simix_global->maestro_process->context)->uc;
160
161   rv = swapcontext(&((smx_ctx_sysv_t) context)->uc, &maestro_ctx);
162
163   xbt_assert0((rv == 0), "Context swapping failure");
164 }
165
166 static void 
167 smx_ctx_sysv_resume(smx_context_t new_context) {
168   int rv;
169   smx_ctx_sysv_t maestro = (smx_ctx_sysv_t)simix_global->maestro_process->context;
170
171   rv = swapcontext(&(maestro->uc), &((smx_ctx_sysv_t)new_context)->uc);
172
173   xbt_assert0((rv == 0), "Context swapping failure");
174 }