3 /* context_lua - implementation of context switching with lua coroutines */
5 /* Copyright (c) 2004-2008 the SimGrid team. All right reserved */
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. */
11 #include "context_sysv_config.h" /* loads context system definitions */
13 #include <ucontext.h> /* context relative declarations */
14 #include <lua5.1/lauxlib.h>
15 #include <lua5.1/lualib.h>
17 /* lower this if you want to reduce the memory consumption */
18 #define STACK_SIZE 128*1024
20 #ifdef HAVE_VALGRIND_VALGRIND_H
21 # include <valgrind/valgrind.h>
22 #endif /* HAVE_VALGRIND_VALGRIND_H */
25 // FIXME: better location for that
26 extern void MSG_register(lua_State *L);
28 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(lua);
30 typedef struct s_smx_ctx_sysv {
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 */
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;
47 static lua_State *lua_state;
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);
53 static int smx_ctx_lua_factory_finalize(smx_context_factory_t *factory);
55 static void smx_ctx_lua_free(smx_context_t context);
57 static void smx_ctx_lua_start(smx_context_t context);
59 static void smx_ctx_lua_stop(smx_context_t context);
61 static void smx_ctx_lua_suspend(smx_context_t context);
64 smx_ctx_lua_resume(smx_context_t old_context, smx_context_t new_context);
66 static void smx_ctx_sysv_wrapper(void);
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);
73 void SIMIX_ctx_lua_factory_init(smx_context_factory_t *factory) {
75 *factory = xbt_new0(s_smx_context_factory_t, 1);
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";
86 lua_state = lua_open();
87 luaL_openlibs(lua_state);
88 MSG_register(lua_state);
89 INFO0("Lua Factory created");
92 static int smx_ctx_lua_factory_finalize(smx_context_factory_t * factory)
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)
105 smx_ctx_lua_t context = xbt_new0(s_smx_ctx_lua_t, 1);
107 /* If the user provided a function for the process then use it
108 otherwise is the context for maestro */
110 context->code = code;
112 xbt_assert2(getcontext(&(context->uc)) == 0,
113 "Error in context saving: %d (%s)", errno, strerror(errno));
115 context->uc.uc_link = NULL;
117 context->uc.uc_stack.ss_sp =
118 pth_skaddr_makecontext(context->stack, STACK_SIZE);
120 context->uc.uc_stack.ss_size =
121 pth_sksize_makecontext(context->stack, STACK_SIZE);
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 */
131 context->state = lua_newthread(lua_state);
133 context->ref = luaL_ref(lua_state, LUA_REGISTRYINDEX);
134 //lua_pop(lua_state,1);
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]);
142 INFO0("Created context for maestro");
145 return (smx_context_t)context;
148 static void smx_ctx_lua_free(smx_context_t pcontext)
151 smx_ctx_lua_t context = (smx_ctx_lua_t)pcontext;
153 #ifdef HAVE_VALGRIND_VALGRIND_H
154 VALGRIND_STACK_DEREGISTER(((smx_ctx_lua_t) context)->valgrind_stack_id);
155 #endif /* HAVE_VALGRIND_VALGRIND_H */
159 for (i = 0; i < context->argc; i++)
160 if (context->argv[i])
161 free(context->argv[i]);
167 /* destroy the context */
168 luaL_unref(lua_state,LUA_REGISTRYINDEX,context->ref );
173 static void smx_ctx_lua_start(smx_context_t pcontext) {
174 smx_ctx_lua_t context = (smx_ctx_lua_t)pcontext;
176 makecontext(&context->uc, smx_ctx_sysv_wrapper, 0);
178 INFO1("Starting '%s'",context->argv[0]);
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]);
186 // push arguments onto the stack
188 for(i=1;i<context->argc;i++)
189 lua_pushstring(context->state,context->argv[i]);
192 context->nargs = context->argc-1;
195 static void smx_ctx_lua_stop(smx_context_t pcontext) {
196 smx_ctx_lua_t context = (smx_ctx_lua_t)pcontext;
198 if (context->cleanup_func)
199 (*context->cleanup_func) (context->cleanup_arg);
201 smx_ctx_lua_suspend(pcontext);
204 static void smx_ctx_sysv_wrapper()
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.
213 smx_ctx_lua_t context =
214 (smx_ctx_lua_t)simix_global->current_process->context;
216 (context->code) (context->argc, context->argv);
218 smx_ctx_lua_stop((smx_context_t)context);
222 static void smx_ctx_lua_suspend(smx_context_t context)
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;
229 ((smx_ctx_lua_t) context)->prev = NULL;
231 rv = swapcontext(&((smx_ctx_lua_t) context)->uc, &prev_context->uc);
233 xbt_assert0((rv == 0), "Context swapping failure");
234 // INFO1("Suspended %s",context->argv[0]);
238 smx_ctx_lua_resume(smx_context_t old_context, smx_context_t new_context) {
240 smx_ctx_lua_t context = (smx_ctx_lua_t)new_context;
242 INFO1("Resuming %s",context->argv[0]);
243 lua_resume(context->state,context->nargs);
245 INFO1("Resumed %s",context->argv[0]);
247 ((smx_ctx_lua_t) new_context)->prev = (smx_ctx_lua_t)old_context;
249 rv = swapcontext(&((smx_ctx_lua_t)old_context)->uc,
250 &((smx_ctx_lua_t)new_context)->uc);
252 xbt_assert0((rv == 0), "Context swapping failure");
254 // INFO1("Process %s done ?",context->argv[0]);
255 // lua_resume(((smx_ctx_lua_t)new_context)->state,0);