Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
d47c1b11030edf678119caf8a3fb81360801afd5
[simgrid.git] / src / simix / smx_context_lua.c
1 /* $Id$ */
2
3 /* context_lua - implementation of context switching with lua coroutines */
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 #include <lua5.1/lauxlib.h>
15 #include <lua5.1/lualib.h>
16
17 /* lower this if you want to reduce the memory consumption  */
18 #define STACK_SIZE 128*1024
19
20 #ifdef HAVE_VALGRIND_VALGRIND_H
21 #  include <valgrind/valgrind.h>
22 #endif /* HAVE_VALGRIND_VALGRIND_H */
23
24
25 // FIXME: better location for that
26 extern void MSG_register(lua_State *L);
27
28 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(lua);
29
30 typedef struct s_smx_ctx_sysv {
31   SMX_CTX_BASE_T;
32
33   /* Ucontext info */
34   ucontext_t uc;                /* the thread that execute the code */
35   char stack[STACK_SIZE];       /* the thread stack size */
36   struct s_smx_ctx_sysv *prev;           /* the previous process */
37 #ifdef HAVE_VALGRIND_VALGRIND_H
38   unsigned int valgrind_stack_id;       /* the valgrind stack id */
39 #endif
40
41   /* lua state info */
42   lua_State *state;
43   int ref; /* to prevent the lua GC from collecting my threads, I ref them explicitely */
44   int nargs; /* argument to lua_resume. First time: argc-1, afterward: 0 */
45 } s_smx_ctx_lua_t, *smx_ctx_lua_t;
46
47 static lua_State *lua_state;
48
49 static smx_context_t 
50 smx_ctx_lua_create_context(xbt_main_func_t code, int argc, char** argv, 
51     void_f_pvoid_t cleanup_func, void* cleanup_arg);
52
53 static int smx_ctx_lua_factory_finalize(smx_context_factory_t *factory);
54
55 static void smx_ctx_lua_free(smx_context_t context);
56
57 static void smx_ctx_lua_start(smx_context_t context);
58
59 static void smx_ctx_lua_stop(smx_context_t context);
60
61 static void smx_ctx_lua_suspend(smx_context_t context);
62
63 static void 
64 smx_ctx_lua_resume(smx_context_t old_context, smx_context_t new_context);
65
66 static void smx_ctx_sysv_wrapper(void);
67
68 void SIMIX_ctx_lua_factory_loadfile(const char *file) {
69   if (luaL_loadfile(lua_state, file) || lua_pcall(lua_state, 0, 0, 0))
70     THROW2(unknown_error,0,"error while parsing %s: %s", file, lua_tostring(lua_state, -1));
71   INFO1("File %s loaded",file);
72 }
73 void SIMIX_ctx_lua_factory_init(smx_context_factory_t *factory) {
74
75   *factory = xbt_new0(s_smx_context_factory_t, 1);
76
77   (*factory)->create_context = smx_ctx_lua_create_context;
78   (*factory)->finalize = smx_ctx_lua_factory_finalize;
79   (*factory)->free = smx_ctx_lua_free;
80   (*factory)->start = smx_ctx_lua_start;
81   (*factory)->stop = smx_ctx_lua_stop;
82   (*factory)->suspend = smx_ctx_lua_suspend;
83   (*factory)->resume = smx_ctx_lua_resume;
84   (*factory)->name = "smx_lua_context_factory";
85
86   lua_state = lua_open();
87   luaL_openlibs(lua_state);
88   MSG_register(lua_state);
89   INFO0("Lua Factory created");
90 }
91
92 static int smx_ctx_lua_factory_finalize(smx_context_factory_t * factory)
93 {
94   lua_close(lua_state);
95
96   free(*factory);
97   *factory = NULL;
98   return 0;
99 }
100
101 static smx_context_t 
102 smx_ctx_lua_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_lua_t context = xbt_new0(s_smx_ctx_lua_t, 1);
106
107   /* If the user provided a function for the process then use it
108      otherwise is the context for maestro */
109   if(code){
110     context->code = code;
111
112     xbt_assert2(getcontext(&(context->uc)) == 0,
113         "Error in context saving: %d (%s)", errno, strerror(errno));
114
115     context->uc.uc_link = NULL;
116
117     context->uc.uc_stack.ss_sp =
118         pth_skaddr_makecontext(context->stack, STACK_SIZE);
119
120     context->uc.uc_stack.ss_size =
121         pth_sksize_makecontext(context->stack, STACK_SIZE);
122
123 #ifdef HAVE_VALGRIND_VALGRIND_H
124     context->valgrind_stack_id =
125         VALGRIND_STACK_REGISTER(context->uc.uc_stack.ss_sp,
126             ((char *) context->uc.uc_stack.ss_sp) +
127             context->uc.uc_stack.ss_size);
128 #endif /* HAVE_VALGRIND_VALGRIND_H */
129
130
131     context->state = lua_newthread(lua_state);
132
133     context->ref = luaL_ref(lua_state, LUA_REGISTRYINDEX);
134     //lua_pop(lua_state,1);
135
136     context->argc = argc;
137     context->argv = argv;
138     context->cleanup_func = cleanup_func;
139     context->cleanup_arg = cleanup_arg;
140     INFO1("Created context for function %s",argv[0]);
141   } else {
142     INFO0("Created context for maestro");
143   }
144
145   return (smx_context_t)context;
146 }
147
148 static void smx_ctx_lua_free(smx_context_t pcontext)
149 {
150   int i;
151   smx_ctx_lua_t context = (smx_ctx_lua_t)pcontext;
152   if (context){
153 #ifdef HAVE_VALGRIND_VALGRIND_H
154     VALGRIND_STACK_DEREGISTER(((smx_ctx_lua_t) context)->valgrind_stack_id);
155 #endif /* HAVE_VALGRIND_VALGRIND_H */
156
157     /* free argv */
158     if (context->argv) {
159       for (i = 0; i < context->argc; i++)
160         if (context->argv[i])
161           free(context->argv[i]);
162
163       free(context->argv);
164     }
165
166
167     /* destroy the context */
168     luaL_unref(lua_state,LUA_REGISTRYINDEX,context->ref );
169     free(context);
170   }
171 }
172
173 static void smx_ctx_lua_start(smx_context_t pcontext) {
174   smx_ctx_lua_t context = (smx_ctx_lua_t)pcontext;
175
176   makecontext(&context->uc, smx_ctx_sysv_wrapper, 0);
177
178   INFO1("Starting '%s'",context->argv[0]);
179
180   lua_getglobal(context->state,context->argv[0]);
181   if(!lua_isfunction(context->state,-1)) {
182     lua_pop(context->state,1);
183     THROW1(arg_error,0,"The lua function %s does not seem to exist",context->argv[0]);
184   }
185
186   // push arguments onto the stack
187   int i;
188   for(i=1;i<context->argc;i++)
189     lua_pushstring(context->state,context->argv[i]);
190
191   // Call the function
192   context->nargs = context->argc-1;
193 }
194
195 static void smx_ctx_lua_stop(smx_context_t pcontext) {
196   smx_ctx_lua_t context = (smx_ctx_lua_t)pcontext;
197
198   if (context->cleanup_func)
199     (*context->cleanup_func) (context->cleanup_arg);
200
201   smx_ctx_lua_suspend(pcontext);
202 }
203
204 static void smx_ctx_sysv_wrapper()
205 {
206   /*FIXME: I would like to avoid accesing simix_global to get the current
207     context by passing it as an argument of the wrapper function. The problem
208     is that this function is called from smx_ctx_sysv_start, and uses
209     makecontext for calling it, and the stupid posix specification states that
210     all the arguments of the function should be int(32 bits), making it useless
211     in 64-bit architectures where pointers are 64 bit long.
212    */
213   smx_ctx_lua_t context =
214       (smx_ctx_lua_t)simix_global->current_process->context;
215
216   (context->code) (context->argc, context->argv);
217
218   smx_ctx_lua_stop((smx_context_t)context);
219 }
220
221
222 static void smx_ctx_lua_suspend(smx_context_t context)
223 {
224   int rv;
225   INFO1("Suspending %s",context->argv[0]);
226   lua_yield(((smx_ctx_lua_t)context)->state,0); // Should be the last line of the function
227   smx_ctx_lua_t prev_context = ((smx_ctx_lua_t) context)->prev;
228
229   ((smx_ctx_lua_t) context)->prev = NULL;
230
231   rv = swapcontext(&((smx_ctx_lua_t) context)->uc, &prev_context->uc);
232
233   xbt_assert0((rv == 0), "Context swapping failure");
234   //  INFO1("Suspended %s",context->argv[0]);
235 }
236
237 static void 
238 smx_ctx_lua_resume(smx_context_t old_context, smx_context_t new_context) {
239   int rv;
240   smx_ctx_lua_t context = (smx_ctx_lua_t)new_context;
241
242   INFO1("Resuming %s",context->argv[0]);
243   lua_resume(context->state,context->nargs);
244   context->nargs = 0;
245   INFO1("Resumed %s",context->argv[0]);
246
247   ((smx_ctx_lua_t) new_context)->prev = (smx_ctx_lua_t)old_context;
248
249   rv = swapcontext(&((smx_ctx_lua_t)old_context)->uc,
250       &((smx_ctx_lua_t)new_context)->uc);
251
252   xbt_assert0((rv == 0), "Context swapping failure");
253
254   //  INFO1("Process %s done ?",context->argv[0]);
255   //  lua_resume(((smx_ctx_lua_t)new_context)->state,0);
256 }