Logo AND Algorithmique Numérique Distribuée

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