Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
6760fa2aebe8855c3bd03a4118c56a8a5b011aab
[simgrid.git] / src / bindings / lua / simgrid_lua.c
1 /* SimGrid Lua bindings                                                     */
2
3 /* Copyright (c) 2010. The SimGrid Team.
4  * All rights reserved.                                                     */
5
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. */
8
9 #include <stdio.h>
10 #include <lauxlib.h>
11 #include <lualib.h>
12
13 #include "msg/msg.h"
14 #include "xbt.h"
15
16 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(lua,bindings,"Lua Bindings");
17
18 #define TASK_MODULE_NAME "simgrid.Task"
19 #define HOST_MODULE_NAME "simgrid.Host"
20
21 /* ********************************************************************************* */
22 /*                            helper functions                                       */
23 /* ********************************************************************************* */
24
25 static void stackDump (const char *msg, lua_State *L) {
26   char buff[2048];
27   char *p=buff;
28   int i;
29   int top = lua_gettop(L);
30
31   fflush(stdout);
32   p+=sprintf(p,"STACK(top=%d): ",top);
33
34   for (i = 1; i <= top; i++) {  /* repeat for each level */
35
36     int t = lua_type(L, i);
37     switch (t) {
38
39     case LUA_TSTRING:  /* strings */
40       p+=sprintf(p,"`%s'", lua_tostring(L, i));
41       break;
42
43     case LUA_TBOOLEAN:  /* booleans */
44       p+=sprintf(p,lua_toboolean(L, i) ? "true" : "false");
45       break;
46
47     case LUA_TNUMBER:  /* numbers */
48       p+=sprintf(p,"%g", lua_tonumber(L, i));
49       break;
50
51     case LUA_TTABLE:
52       p+=sprintf(p, "Table");
53       break;
54
55     default:  /* other values */
56       p+=sprintf(p, "???");
57 /*      if ((ptr = luaL_checkudata(L,i,TASK_MODULE_NAME))) {
58         p+=sprintf(p,"task");
59       } else {
60         p+=printf(p,"%s", lua_typename(L, t));
61       }*/
62       break;
63
64     }
65     p+=sprintf(p,"  ");  /* put a separator */
66   }
67   INFO2("%s%s",msg,buff);
68 }
69
70 /** @brief ensures that a userdata on the stack is a task and returns the pointer inside the userdata */
71 static m_task_t checkTask (lua_State *L,int index) {
72   m_task_t *pi,tk;
73   luaL_checktype(L,index,LUA_TTABLE);
74   lua_getfield(L,index,"__simgrid_task");
75   pi = (m_task_t*)luaL_checkudata(L,-1,TASK_MODULE_NAME);
76   if(pi == NULL)
77          luaL_typerror(L,index,TASK_MODULE_NAME);
78   tk = *pi;
79   if(!tk)
80          luaL_error(L,"null Task");
81   lua_pop(L,1);
82   return  tk;
83 }
84
85 /** @brief leaves a new userdata on top of the stack, sets its metatable, and sets the Task pointer inside the userdata */
86 // NOT USED
87 /*static m_task_t *pushTask (lua_State *L,m_task_t tk) {
88   m_task_t *pi = NULL;
89   pi = (m_task_t*)lua_newuserdata(L,sizeof(m_task_t));
90   *pi=tk;
91   DEBUG1("push lua task with Name : %s \n",MSG_task_get_name(*pi));
92   luaL_getmetatable(L,TASK_MODULE_NAME);
93   lua_setmetatable(L,-2);
94   return pi;
95 }*/
96
97 /* ********************************************************************************* */
98 /*                           wrapper functions                                       */
99 /* ********************************************************************************* */
100
101 /**
102  *  Task
103  */
104
105 static int Task_new(lua_State* L) {
106   const char *name=luaL_checkstring(L,1);
107   int comp_size = luaL_checkint(L,2);
108   int msg_size = luaL_checkint(L,3);
109   INFO0("Creating task");
110   m_task_t msg_task = MSG_task_create(name,comp_size,msg_size,NULL);
111   lua_newtable (L); /* create a table, put the userdata on top of it */
112   m_task_t *lua_task = (m_task_t*)lua_newuserdata(L,sizeof(m_task_t));
113   *lua_task = msg_task;
114   luaL_getmetatable(L,TASK_MODULE_NAME);
115   lua_setmetatable(L,-2);
116   lua_setfield (L, -2, "__simgrid_task"); /* put the userdata as field of the table */
117   /* remove the args from the stack */
118   lua_remove(L,1);
119   lua_remove(L,1);
120   lua_remove(L,1);
121   return 1;
122 }
123
124 static int Task_get_name(lua_State *L) {
125   m_task_t tk = checkTask(L,-1);
126   lua_pushstring(L,MSG_task_get_name(tk));
127   return 1;
128 }
129
130 static int Task_computation_duration(lua_State *L){
131   m_task_t tk = checkTask(L,-1);
132   lua_pushnumber(L,MSG_task_get_compute_duration (tk));
133   return 1;
134 }
135
136 static int Task_execute(lua_State *L){
137   m_task_t tk = checkTask(L,-1);
138   int res = MSG_task_execute(tk);
139   lua_pushnumber(L,res);
140   return 1;
141 }
142
143 static int Task_destroy(lua_State *L) {
144   m_task_t tk = checkTask(L,-1);
145   int res = MSG_task_destroy(tk);
146   lua_pushnumber(L,res);
147   return 1;
148 }
149 static int Task_send(lua_State *L)  {
150   //stackDump("send ",L);
151   m_task_t tk = checkTask(L,-2);
152   const char *mailbox = luaL_checkstring(L,-1);
153   lua_pop(L,1); // remove the string so that the task is on top of it
154   MSG_task_set_data(tk,L); // Copy my stack into the task, so that the receiver can copy the lua task directly
155   MSG_error_t res = MSG_task_send(tk,mailbox);
156   while (MSG_task_get_data(tk)!=NULL) // Don't mess up with my stack: the receiver didn't copy the data yet
157     MSG_process_sleep(0); // yield
158
159   if (res != MSG_OK) switch(res) {
160     case MSG_TIMEOUT :
161       ERROR0("MSG_task_send failed : Timeout");
162       break;
163     case MSG_TRANSFER_FAILURE :
164       ERROR0("MSG_task_send failed : Transfer Failure");
165       break;
166     case MSG_HOST_FAILURE :
167       ERROR0("MSG_task_send failed : Host Failure ");
168       break;
169     default :
170       ERROR0("MSG_task_send failed : Unexpected error , please report this bug");
171       break;
172     }
173   return 0;
174 }
175
176 static int Task_recv(lua_State *L)  {
177   m_task_t tk = NULL;
178   const char *mailbox = luaL_checkstring(L,-1);
179   MSG_error_t res = MSG_task_receive(&tk,mailbox);
180
181   lua_State *sender_stack = MSG_task_get_data(tk);
182   lua_xmove(sender_stack,L,1); // copy the data directly from sender's stack
183   MSG_task_set_data(tk,NULL);
184
185   if(res != MSG_OK) switch(res){
186           case MSG_TIMEOUT :
187                   ERROR0("MSG_task_receive failed : Timeout");
188                   break;
189           case MSG_TRANSFER_FAILURE :
190                   ERROR0("MSG_task_receive failed : Transfer Failure");
191                   break;
192           case MSG_HOST_FAILURE :
193                   ERROR0("MSG_task_receive failed : Host Failure ");
194                   break;
195           default :
196                   ERROR0("MSG_task_receive failed : Unexpected error , please report this bug");
197                   break;
198                   }
199
200   return 1;
201 }
202
203 static const luaL_reg Task_methods[] = {
204     {"new",   Task_new},
205     {"name",  Task_get_name},
206     {"computation_duration",  Task_computation_duration},
207     {"execute", Task_execute},
208     {"destroy", Task_destroy},
209     {"send",    Task_send},
210     {"recv",    Task_recv},
211     {0,0}
212 };
213 static int Task_gc(lua_State *L) {
214   m_task_t tk=checkTask(L,-1);
215   if (tk) MSG_task_destroy(tk);
216   return 0;
217 }
218
219 static int Task_tostring(lua_State *L) {
220   lua_pushfstring(L, "Task :%p",lua_touserdata(L,1));
221   return 1;
222 }
223
224 static const luaL_reg Task_meta[] = {
225     {"__gc",  Task_gc},
226     {"__tostring",  Task_tostring},
227     {0,0}
228 };
229
230 /**
231  * Host
232  */
233 static m_host_t checkHost (lua_State *L,int index) {
234   m_host_t *pi,ht;
235   luaL_checktype(L,index,LUA_TTABLE);
236   lua_getfield(L,index,"__simgrid_host");
237   pi = (m_host_t*)luaL_checkudata(L,-1,HOST_MODULE_NAME);
238   if(pi == NULL)
239          luaL_typerror(L,index,HOST_MODULE_NAME);
240   ht = *pi;
241   if(!ht)
242          luaL_error(L,"null Host");
243   lua_pop(L,1);
244   return  ht;
245 }
246
247
248 static int Host_get_by_name(lua_State *L)
249 {
250         const char *name=luaL_checkstring(L,1);
251         DEBUG0("Getting Host from name...");
252         m_host_t msg_host = MSG_get_host_by_name(name);
253         if (!msg_host)
254                 {
255                 luaL_error(L,"null Host : MSG_get_host_by_name failled");
256                 }
257     lua_newtable (L); /* create a table, put the userdata on top of it */
258         m_host_t *lua_host = (m_host_t*)lua_newuserdata(L,sizeof(m_host_t));
259         *lua_host = msg_host;
260         luaL_getmetatable(L,HOST_MODULE_NAME);
261         lua_setmetatable(L,-2);
262         lua_setfield (L, -2, "__simgrid_host"); /* put the userdata as field of the table */
263         /* remove the args from the stack */
264         lua_remove(L,1);
265         return 1;
266 }
267
268
269 static int Host_get_name(lua_State *L) {
270   m_host_t ht = checkHost(L,-1);
271   lua_pushstring(L,MSG_host_get_name(ht));
272   return 1;
273 }
274
275 static int Host_number(lua_State *L) {
276   lua_pushnumber(L,MSG_get_host_number());
277   return 1;
278 }
279
280
281 static const luaL_reg Host_methods[] = {
282     {"getByName",   Host_get_by_name},
283     {"name",            Host_get_name},
284     {"number",          Host_number},
285     {0,0}
286 };
287
288 static int Host_gc(lua_State *L)
289 {
290   m_host_t ht = checkHost(L,-1);
291   if (ht) ht = NULL;
292   return 0;
293 }
294
295 static int Host_tostring(lua_State *L)
296 {
297   lua_pushfstring(L,"Host :%p",lua_touserdata(L,1));
298   return 1;
299 }
300
301 static const luaL_reg Host_meta[] = {
302     {"__gc",  Host_gc},
303     {"__tostring",  Host_tostring},
304     {0,0}
305 };
306
307 /*
308  * Environment related
309  */
310 extern lua_State *simgrid_lua_state;
311
312 static int run_lua_code(int argc,char **argv) {
313   DEBUG1("Run lua code %s",argv[0]);
314   lua_State *L = lua_newthread(simgrid_lua_state);
315   int ref = luaL_ref(simgrid_lua_state, LUA_REGISTRYINDEX); // protect the thread from being garbage collected
316   int res = 1;
317
318   /* Start the co-routine */
319   lua_getglobal(L,argv[0]);
320   xbt_assert1(lua_isfunction(L,-1),
321       "The lua function %s does not seem to exist",argv[0]);
322
323   // push arguments onto the stack
324   int i;
325   for(i=1;i<argc;i++)
326     lua_pushstring(L,argv[i]);
327
328   // Call the function (in resume)
329   xbt_assert2(lua_pcall(L, argc-1, 1, 0) == 0,
330     "error running function `%s': %s",argv[0], lua_tostring(L, -1));
331
332   /* retrieve result */
333   if (lua_isnumber(L, -1)) {
334     res = lua_tonumber(L, -1);
335     lua_pop(L, 1);  /* pop returned value */
336   }
337
338   // cleanups
339   luaL_unref(simgrid_lua_state,LUA_REGISTRYINDEX,ref );
340   DEBUG1("Execution of lua code %s is over", (argv ? argv[0] : "(null)"));
341   return res;
342 }
343 static int launch_application(lua_State *L) {
344   const char * file = luaL_checkstring(L,1);
345   MSG_function_register_default(run_lua_code);
346   MSG_launch_application(file);
347   return 0;
348 }
349 #include "simix/simix.h" //FIXME: KILLME when debugging on simix internals become useless
350 static int create_environment(lua_State *L) {
351   const char *file = luaL_checkstring(L,1);
352   DEBUG1("Loading environment file %s",file);
353   MSG_create_environment(file);
354   smx_host_t *hosts = SIMIX_host_get_table();
355   int i;
356   for (i=0;i<SIMIX_host_get_number();i++) {
357     DEBUG1("We have an host %s", SIMIX_host_get_name(hosts[i]));
358   }
359
360   return 0;
361 }
362 static int debug(lua_State *L) {
363   const char *str = luaL_checkstring(L,1);
364   DEBUG1("%s",str);
365   return 0;
366 }
367 static int info(lua_State *L) {
368   const char *str = luaL_checkstring(L,1);
369   INFO1("%s",str);
370   return 0;
371 }
372 static int run(lua_State *L) {
373   MSG_main();
374   return 0;
375 }
376 static int clean(lua_State *L) {
377   MSG_clean();
378   return 0;
379 }
380 static const luaL_Reg simgrid_funcs[] = {
381     { "create_environment", create_environment},
382     { "launch_application", launch_application},
383     { "debug", debug},
384     { "info", info},
385     { "run", run},
386     { "clean", clean},
387     /* short names */
388     { "platform", create_environment},
389     { "application", launch_application},
390     { NULL, NULL }
391 };
392
393 /* ********************************************************************************* */
394 /*                       module management functions                                 */
395 /* ********************************************************************************* */
396
397 extern const char*xbt_ctx_factory_to_use; /*Hack: let msg load directly the right factory */
398
399 #define LUA_MAX_ARGS_COUNT 10 /* maximum amount of arguments we can get from lua on command line */
400
401 int luaopen_simgrid(lua_State* L); // Fuck gcc: we don't need that prototype
402 int luaopen_simgrid(lua_State* L) {
403   //xbt_ctx_factory_to_use = "lua";
404
405   char **argv=malloc(sizeof(char*)*LUA_MAX_ARGS_COUNT);
406   int argc=1;
407   argv[0] = (char*)"/usr/bin/lua"; /* Lie on the argv[0] so that the stack dumping facilities find the right binary. FIXME: what if lua is not in that location? */
408   /* Get the command line arguments from the lua interpreter */
409   lua_getglobal(L,"arg");
410   xbt_assert1(lua_istable(L,-1),"arg parameter is not a table but a %s",lua_typename(L,-1));
411   int done=0;
412   while (!done) {
413     argc++;
414     lua_pushinteger(L,argc-2);
415     lua_gettable(L,-2);
416     if (lua_isnil(L,-1)) {
417       done = 1;
418     } else {
419       xbt_assert1(lua_isstring(L,-1),"argv[%d] got from lua is no string",argc-1);
420       xbt_assert2(argc<LUA_MAX_ARGS_COUNT,
421            "Too many arguments, please increase LUA_MAX_ARGS_COUNT in %s before recompiling SimGrid if you insist on having more than %d args on command line",
422            __FILE__,LUA_MAX_ARGS_COUNT-1);
423       argv[argc-1] = (char*)luaL_checkstring(L,-1);
424       lua_pop(L,1);
425       DEBUG1("Got command line argument %s from lua",argv[argc-1]);
426     }
427   }
428   argv[argc--]=NULL;
429
430   /* Initialize the MSG core */
431   MSG_global_init(&argc,argv);
432   DEBUG1("Still %d arguments on command line",argc); // FIXME: update the lua's arg table to reflect the changes from SimGrid
433
434   /* register the core C functions to lua */
435   luaL_register(L, "simgrid", simgrid_funcs);
436   /* register the task methods to lua */
437   luaL_openlib(L,TASK_MODULE_NAME,Task_methods,0); //create methods table,add it to the globals
438   luaL_newmetatable(L,TASK_MODULE_NAME); //create metatable for Task,add it to the Lua registry
439   luaL_openlib(L,0,Task_meta,0);// fill metatable
440   lua_pushliteral(L,"__index");
441   lua_pushvalue(L,-3);  //dup methods table
442   lua_rawset(L,-3); //matatable.__index = methods
443   lua_pushliteral(L,"__metatable");
444   lua_pushvalue(L,-3);  //dup methods table
445   lua_rawset(L,-3); //hide metatable:metatable.__metatable = methods
446   lua_pop(L,1);   //drop metatable
447
448   /* register the hosts methods to lua*/
449   luaL_openlib(L,HOST_MODULE_NAME,Host_methods,0);
450   luaL_newmetatable(L,HOST_MODULE_NAME);
451   luaL_openlib(L,0,Host_meta,0);
452   lua_pushliteral(L,"__index");
453   lua_pushvalue(L,-3);
454   lua_rawset(L,-3);
455   lua_pushliteral(L,"__metatable");
456   lua_pushvalue(L,-3);
457   lua_rawset(L,-3);
458   lua_pop(L,1);
459
460   /* Keep the context mechanism informed of our lua world today */
461   simgrid_lua_state = L;
462
463   return 1;
464 }