Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Lua: set a task metatable that allows OO-style syntax
[simgrid.git] / src / bindings / lua / simgrid_lua.c
1 /* Copyright (c) 2010. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 /* SimGrid Lua bindings                                                     */
8
9 #include "simgrid_lua.h"
10 #include "lua_state_cloner.h"
11 #include "lua_utils.h"
12
13 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(lua, bindings, "Lua Bindings");
14
15 #define TASK_MODULE_NAME "simgrid.task"
16 #define HOST_MODULE_NAME "simgrid.host"
17 // Surf (bypass XML)
18 #define LINK_MODULE_NAME "simgrid.link"
19 #define ROUTE_MODULE_NAME "simgrid.route"
20 #define PLATF_MODULE_NAME "simgrid.platf"
21
22 static lua_State* sglua_maestro_state;
23
24 int luaopen_simgrid(lua_State *L);
25 static void register_c_functions(lua_State *L);
26 static int run_lua_code(int argc, char **argv);
27
28 /* ********************************************************************************* */
29 /*                                simgrid.task API                                   */
30 /* ********************************************************************************* */
31
32 /**
33  * \brief Ensures that a value in the stack is a valid task and returns it.
34  * \param L a Lua state
35  * \param index an index in the Lua stack
36  * \return the C task corresponding to this Lua task
37  */
38 static m_task_t sglua_checktask(lua_State* L, int index)
39 {
40   sglua_stack_dump("check task: ", L);
41   luaL_checktype(L, index, LUA_TTABLE);
42                                   /* ... task ... */
43   lua_getfield(L, index, "__simgrid_task");
44                                   /* ... task ... ctask */
45   m_task_t task = *((m_task_t*) luaL_checkudata(L, -1, TASK_MODULE_NAME));
46   lua_pop(L, 1);
47                                   /* ... task ... */
48
49   if (task == NULL) {
50     luaL_error(L, "This task was sent to someone else, you cannot access it anymore");
51   }
52
53   return task;
54 }
55
56 /**
57  * \brief Creates a new task and leaves it onto the stack.
58  * \param L a Lua state
59  * \return number of values returned to Lua
60  *
61  * - Argument 1 (string): name of the task
62  * - Argument 2 (number): computation size
63  * - Argument 3 (number): communication size
64  * - Return value (task): the task created
65  *
66  * A Lua task is a regular table with a full userdata inside, and both share
67  * the same metatable. For the regular table, the metatable allows OO-style
68  * writing such as your_task:send(someone).
69  * For the userdata, the metatable is used to check its type.
70  */
71 static int l_task_new(lua_State* L)
72 {
73   XBT_DEBUG("Task new");
74   const char* name = luaL_checkstring(L, 1);
75   int comp_size = luaL_checkint(L, 2);
76   int msg_size = luaL_checkint(L, 3);
77                                   /* name comp comm */
78   lua_settop(L, 0);
79                                   /* -- */
80   m_task_t msg_task = MSG_task_create(name, comp_size, msg_size, NULL);
81
82   lua_newtable(L);
83                                   /* task */
84   luaL_getmetatable(L, TASK_MODULE_NAME);
85                                   /* task mt */
86   lua_setmetatable(L, -2);
87                                   /* task */
88   m_task_t* lua_task = (m_task_t*) lua_newuserdata(L, sizeof(m_task_t));
89                                   /* task ctask */
90   *lua_task = msg_task;
91   luaL_getmetatable(L, TASK_MODULE_NAME);
92                                   /* task ctask mt */
93   lua_setmetatable(L, -2);
94                                   /* task ctask */
95   lua_setfield(L, -2, "__simgrid_task");
96                                   /* task */
97   return 1;
98 }
99
100 /**
101  * \brief Returns the name of a task.
102  * \param L a Lua state
103  * \return number of values returned to Lua
104  *
105  * - Argument 1 (task): a task
106  * - Return value (string): name of the task
107  */
108 static int l_task_get_name(lua_State* L)
109 {
110   m_task_t task = sglua_checktask(L, 1);
111   lua_pushstring(L, MSG_task_get_name(task));
112   return 1;
113 }
114
115 /**
116  * \brief Returns the computation duration of a task.
117  * \param L a Lua state
118  * \return number of values returned to Lua
119  *
120  * - Argument 1 (task): a task
121  * - Return value (number): computation duration of this task
122  */
123 static int l_task_computation_duration(lua_State* L)
124 {
125   m_task_t task = sglua_checktask(L, 1);
126   lua_pushnumber(L, MSG_task_get_compute_duration(task));
127   return 1;
128 }
129
130 /**
131  * \brief Executes a task.
132  * \param L a Lua state
133  * \return number of values returned to Lua
134  *
135  * - Argument 1 (task): the task to execute
136  * - Return value (number): error code
137  */
138 static int l_task_execute(lua_State* L)
139 {
140   m_task_t task = sglua_checktask(L, 1);
141   int res = MSG_task_execute(task);
142   lua_pushnumber(L, res);
143   return 1;
144 }
145
146 /**
147  * \brief Sends a task to a mailbox and waits for its completion.
148  * \param L a Lua state
149  * \return number of values returned to Lua
150  *
151  * - Argument 1 (task): the task to send
152  * - Argument 2 (string): mailbox
153  */
154 static int l_task_send(lua_State* L)
155 {
156   m_task_t task = sglua_checktask(L, 1);
157   const char* mailbox = luaL_checkstring(L, 2);
158                                   /* task mailbox */
159   lua_settop(L, 1);
160                                   /* task */
161   /* copy my stack into the task, so that the receiver can copy the lua task */
162   MSG_task_set_data(task, L);
163   MSG_error_t res = MSG_task_send(task, mailbox);
164   while (MSG_task_get_data(task) != NULL) {
165     /* don't mess up with my stack: the receiver didn't copy the data yet */
166     MSG_process_sleep(0);
167   }
168
169   if (res == MSG_OK) {
170     /* the receiver is the owner of the task and may destroy it:
171      * remove the C task on my side so that I don't garbage collect it */
172     lua_getfield(L, 1, "__simgrid_task");
173                                   /* task ctask */
174     m_task_t* udata = (m_task_t*) luaL_checkudata(L, -1, TASK_MODULE_NAME);
175     *udata = NULL;
176     lua_pop(L, 1);
177                                   /* task */
178   }
179   else {
180     switch (res) {
181     case MSG_TIMEOUT:
182       XBT_DEBUG("MSG_task_send failed : Timeout");
183       break;
184     case MSG_TRANSFER_FAILURE:
185       XBT_DEBUG("MSG_task_send failed : Transfer Failure");
186       break;
187     case MSG_HOST_FAILURE:
188       XBT_DEBUG("MSG_task_send failed : Host Failure ");
189       break;
190     default:
191       XBT_ERROR
192           ("MSG_task_send failed : Unexpected error , please report this bug");
193       break;
194     }
195   }
196   return 0;
197 }
198
199 /**
200  * \brief Receives a task.
201  * \param L a Lua state
202  * \return number of values returned to Lua
203  *
204  * - Argument 1 (string): mailbox
205  * - Argument 2 (number, optional): timeout (default is no timeout)
206  * - Return value (task/nil): the task received or nil if the communication
207  * has failed
208  */
209 static int l_task_recv(lua_State *L)
210 {
211   m_task_t task = NULL;
212   const char* mailbox = luaL_checkstring(L, 1);
213   int timeout;
214   if (lua_gettop(L) >= 2) {
215                                   /* mailbox timeout */
216     timeout = luaL_checknumber(L, 2);
217   }
218   else {
219                                   /* mailbox */
220     timeout = -1;
221     /* no timeout by default */
222   }
223   lua_settop(L, 0);
224                                   /* -- */
225   MSG_error_t res = MSG_task_receive_with_timeout(&task, mailbox, timeout);
226
227   if (res == MSG_OK) {
228     /* copy the data directly from sender's stack */
229     lua_State* sender_stack = MSG_task_get_data(task);
230     sglua_copy_value(sender_stack, L);
231                                   /* task */
232     MSG_task_set_data(task, NULL);
233   }
234   else {
235     switch (res) {
236     case MSG_TIMEOUT:
237       XBT_DEBUG("MSG_task_receive failed : Timeout");
238       break;
239     case MSG_TRANSFER_FAILURE:
240       XBT_DEBUG("MSG_task_receive failed : Transfer Failure");
241       break;
242     case MSG_HOST_FAILURE:
243       XBT_DEBUG("MSG_task_receive failed : Host Failure ");
244       break;
245     default:
246       XBT_ERROR("MSG_task_receive failed : Unexpected error , please report this bug");
247       break;
248     }
249     lua_pushnil(L);
250                                   /* nil */
251   }
252                                   /* task/nil */
253   return 1;
254 }
255
256 static const luaL_reg task_functions[] = {
257   {"new", l_task_new},
258   {"name", l_task_get_name},
259   {"computation_duration", l_task_computation_duration},
260   {"execute", l_task_execute},
261   {"send", l_task_send},
262   {"recv", l_task_recv},
263   {NULL, NULL}
264 };
265
266 /**
267  * \brief Finalizes the userdata of a task.
268  * \param L a Lua state
269  * \return number of values returned to Lua
270  *
271  * - Argument 1 (userdata): a C task, possibly NULL if it was sent to another
272  * Lua state
273  */
274 static int l_task_gc(lua_State* L)
275 {
276                                   /* ctask */
277   m_task_t task = *((m_task_t*) luaL_checkudata(L, 1, TASK_MODULE_NAME));
278   /* the task is NULL if I sent it to someone else */
279   if (task != NULL) {
280     MSG_task_destroy(task);
281   }
282   return 0;
283 }
284
285 /**
286  * \brief Returns a string representation of a C task.
287  * \param L a Lua state
288  * \return number of values returned to Lua
289  *
290  * - Argument 1 (userdata): a task
291  * - Return value (string): a string describing this task
292  */
293 static int l_task_tostring(lua_State* L)
294 {
295   m_task_t task = *((m_task_t*) luaL_checkudata(L, 1, TASK_MODULE_NAME));
296   lua_pushfstring(L, "Task: %p", task);
297   return 1;
298 }
299
300 /**
301  * \brief Metamethods of both a task table and the userdata inside it.
302  */
303 static const luaL_reg task_meta[] = {
304   {"__gc", l_task_gc}, /* will be called only for userdata */
305   {"__tostring", l_task_tostring},
306   {NULL, NULL}
307 };
308
309 /* ********************************************************************************* */
310 /*                                simgrid.host API                                   */
311 /* ********************************************************************************* */
312
313 /**
314  * \brief Ensures that a value in the stack is a host and returns it.
315  * \param L a Lua state
316  * \param index an index in the Lua stack
317  * \return the C host corresponding to this Lua host
318  */
319 static m_host_t sglua_checkhost(lua_State * L, int index)
320 {
321   m_host_t *pi, ht;
322   luaL_checktype(L, index, LUA_TTABLE);
323   lua_getfield(L, index, "__simgrid_host");
324   pi = (m_host_t *) luaL_checkudata(L, lua_gettop(L), HOST_MODULE_NAME);
325   if (pi == NULL)
326     luaL_typerror(L, index, HOST_MODULE_NAME);
327   ht = *pi;
328   if (!ht)
329     luaL_error(L, "null Host");
330   lua_pop(L, 1);
331   return ht;
332 }
333
334 /**
335  * \brief Returns a host given its name.
336  * \param L a Lua state
337  * \return number of values returned to Lua
338  *
339  * - Argument 1 (string): name of a host
340  * - Return value (host): the corresponding host
341  */
342 static int l_host_get_by_name(lua_State * L)
343 {
344   const char *name = luaL_checkstring(L, 1);
345   XBT_DEBUG("Getting Host from name...");
346   m_host_t msg_host = MSG_get_host_by_name(name);
347   if (!msg_host) {
348     luaL_error(L, "null Host : MSG_get_host_by_name failed");
349   }
350   lua_newtable(L);              /* create a table, put the userdata on top of it */
351   m_host_t *lua_host = (m_host_t *) lua_newuserdata(L, sizeof(m_host_t));
352   *lua_host = msg_host;
353   luaL_getmetatable(L, HOST_MODULE_NAME);
354   lua_setmetatable(L, -2);
355   lua_setfield(L, -2, "__simgrid_host");        /* put the userdata as field of the table */
356   /* remove the args from the stack */
357   lua_remove(L, 1);
358   return 1;
359 }
360
361 /**
362  * \brief Returns the name of a host.
363  * \param L a Lua state
364  * \return number of values returned to Lua
365  *
366  * - Argument 1 (host): a host
367  * - Return value (string): name of this host
368  */
369 static int l_host_get_name(lua_State * L)
370 {
371   m_host_t ht = sglua_checkhost(L, 1);
372   lua_pushstring(L, MSG_host_get_name(ht));
373   return 1;
374 }
375
376 /**
377  * \brief Returns the number of existing hosts.
378  * \param L a Lua state
379  * \return number of values returned to Lua
380  *
381  * - Return value (number): number of hosts
382  */
383 static int l_host_number(lua_State * L)
384 {
385   lua_pushnumber(L, MSG_get_host_number());
386   return 1;
387 }
388
389 /**
390  * \brief Returns the host given its index.
391  * \param L a Lua state
392  * \return number of values returned to Lua
393  *
394  * - Argument 1 (number): an index (1 is the first)
395  * - Return value (host): the host at this index
396  */
397 static int l_host_at(lua_State * L)
398 {
399   int index = luaL_checkinteger(L, 1);
400   m_host_t host = MSG_get_host_table()[index - 1];      // lua indexing start by 1 (lua[1] <=> C[0])
401   lua_newtable(L);              /* create a table, put the userdata on top of it */
402   m_host_t *lua_host = (m_host_t *) lua_newuserdata(L, sizeof(m_host_t));
403   *lua_host = host;
404   luaL_getmetatable(L, HOST_MODULE_NAME);
405   lua_setmetatable(L, -2);
406   lua_setfield(L, -2, "__simgrid_host");        /* put the userdata as field of the table */
407   return 1;
408 }
409
410 /**
411  * \brief Returns the host where the current process is located.
412  * \param L a Lua state
413  * \return number of values returned to Lua
414  *
415  * - Return value (host): the current host
416  */
417 static int l_host_self(lua_State * L)
418 {
419                                   /* -- */
420   m_host_t host = MSG_host_self();
421   lua_newtable(L);
422                                   /* table */
423   m_host_t* lua_host = (m_host_t*) lua_newuserdata(L, sizeof(m_host_t));
424                                   /* table ud */
425   *lua_host = host;
426   luaL_getmetatable(L, HOST_MODULE_NAME);
427                                   /* table ud mt */
428   lua_setmetatable(L, -2);
429                                   /* table ud */
430   lua_setfield(L, -2, "__simgrid_host");
431                                   /* table */
432   return 1;
433 }
434
435 /**
436  * \brief Returns the value of a host property.
437  * \param L a Lua state
438  * \return number of values returned to Lua
439  *
440  * - Argument 1 (host): a host
441  * - Argument 2 (string): name of the property to get
442  * - Return value (string): the value of this property
443  */
444 static int l_host_get_property_value(lua_State * L)
445 {
446   m_host_t ht = sglua_checkhost(L, 1);
447   const char *prop = luaL_checkstring(L, 2);
448   lua_pushstring(L,MSG_host_get_property_value(ht,prop));
449   return 1;
450 }
451
452 /**
453  * \brief Makes the current process sleep for a while.
454  * \param L a Lua state
455  * \return number of values returned to Lua
456  *
457  * - Argument 1 (number): duration of the sleep
458  */
459 static int l_host_sleep(lua_State *L)
460 {
461   int time = luaL_checknumber(L, 1);
462   MSG_process_sleep(time);
463   return 0;
464 }
465
466 /**
467  * \brief Destroys a host.
468  * \param L a Lua state
469  * \return number of values returned to Lua
470  *
471  * - Argument 1 (host): the host to destroy
472  */
473 static int l_host_destroy(lua_State *L)
474 {
475   m_host_t ht = sglua_checkhost(L, 1);
476   __MSG_host_destroy(ht);
477   return 0;
478 }
479
480 static const luaL_reg host_functions[] = {
481   {"get_by_name", l_host_get_by_name},
482   {"name", l_host_get_name},
483   {"number", l_host_number},
484   {"at", l_host_at},
485   {"self", l_host_self},
486   {"get_prop_value", l_host_get_property_value},
487   {"sleep", l_host_sleep},
488   {"destroy", l_host_destroy},
489   // Bypass XML Methods
490   {"set_function", console_set_function},
491   {"set_property", console_host_set_property},
492   {NULL, NULL}
493 };
494
495 /**
496  * \brief Returns a string representation of a host.
497  * \param L a Lua state
498  * \return number of values returned to Lua
499  *
500  * - Argument 1 (userdata): a host
501  * - Return value (string): a string describing this host
502  */
503 static int l_host_tostring(lua_State * L)
504 {
505   lua_pushfstring(L, "Host :%p", lua_touserdata(L, 1));
506   return 1;
507 }
508
509 static const luaL_reg host_meta[] = {
510   {"__tostring", l_host_tostring},
511   {0, 0}
512 };
513
514 /* ********************************************************************************* */
515 /*                           lua_stub_generator functions                            */
516 /* ********************************************************************************* */
517
518 xbt_dict_t process_function_set;
519 xbt_dynar_t process_list;
520 xbt_dict_t machine_set;
521 static s_process_t process;
522
523 void s_process_free(void *process)
524 {
525   s_process_t *p = (s_process_t *) process;
526   int i;
527   for (i = 0; i < p->argc; i++)
528     free(p->argv[i]);
529   free(p->argv);
530   free(p->host);
531 }
532
533 static int gras_add_process_function(lua_State * L)
534 {
535   const char *arg;
536   const char *process_host = luaL_checkstring(L, 1);
537   const char *process_function = luaL_checkstring(L, 2);
538
539   if (xbt_dict_is_empty(machine_set)
540       || xbt_dict_is_empty(process_function_set)
541       || xbt_dynar_is_empty(process_list)) {
542     process_function_set = xbt_dict_new();
543     process_list = xbt_dynar_new(sizeof(s_process_t), s_process_free);
544     machine_set = xbt_dict_new();
545   }
546
547   xbt_dict_set(machine_set, process_host, NULL, NULL);
548   xbt_dict_set(process_function_set, process_function, NULL, NULL);
549
550   process.argc = 1;
551   process.argv = xbt_new(char *, 1);
552   process.argv[0] = xbt_strdup(process_function);
553   process.host = strdup(process_host);
554
555   lua_pushnil(L);
556   while (lua_next(L, 3) != 0) {
557     arg = lua_tostring(L, -1);
558     process.argc++;
559     process.argv =
560         xbt_realloc(process.argv, (process.argc) * sizeof(char *));
561     process.argv[(process.argc) - 1] = xbt_strdup(arg);
562
563     XBT_DEBUG("index = %f , arg = %s \n", lua_tonumber(L, -2),
564            lua_tostring(L, -1));
565     lua_pop(L, 1);
566   }
567   lua_pop(L, 1);
568   //add to the process list
569   xbt_dynar_push(process_list, &process);
570   return 0;
571 }
572
573 static int gras_generate(lua_State * L)
574 {
575   const char *project_name = luaL_checkstring(L, 1);
576   generate_sim(project_name);
577   generate_rl(project_name);
578   generate_makefile_local(project_name);
579   return 0;
580 }
581
582 /* ********************************************************************************* */
583 /*                               simgrid.platf API                                   */
584 /* ********************************************************************************* */
585
586 static const luaL_reg platf_functions[] = {
587     {"open", console_open},
588     {"close", console_close},
589     {"AS_open", console_AS_open},
590     {"AS_close", console_AS_close},
591     {"host_new", console_add_host},
592     {"link_new", console_add_link},
593     {"router_new", console_add_router},
594     {"route_new", console_add_route},
595     {NULL, NULL}
596 };
597
598 /* ********************************************************************************* */
599 /*                                  simgrid API                                      */
600 /* ********************************************************************************* */
601
602 /**
603  * \brief Deploys your application.
604  * \param L a Lua state
605  * \return number of values returned to Lua
606  *
607  * - Argument 1 (string): name of the deployment file to load
608  */
609 static int launch_application(lua_State * L)
610 {
611   const char *file = luaL_checkstring(L, 1);
612   MSG_function_register_default(run_lua_code);
613   MSG_launch_application(file);
614   return 0;
615 }
616
617 /**
618  * \brief Creates the platform.
619  * \param L a Lua state
620  * \return number of values returned to Lua
621  *
622  * - Argument 1 (string): name of the platform file to load
623  */
624 static int create_environment(lua_State * L)
625 {
626   const char *file = luaL_checkstring(L, 1);
627   XBT_DEBUG("Loading environment file %s", file);
628   MSG_create_environment(file);
629   return 0;
630 }
631
632 /**
633  * \brief Prints a log string with debug level.
634  * \param L a Lua state
635  * \return number of values returned to Lua
636  *
637  * - Argument 1 (string): the text to print
638  */
639 static int debug(lua_State * L)
640 {
641   const char *str = luaL_checkstring(L, 1);
642   XBT_DEBUG("%s", str);
643   return 0;
644 }
645
646 /**
647  * \brief Prints a log string with info level.
648  * \param L a Lua state
649  * \return number of values returned to Lua
650  *
651  * - Argument 1 (string): the text to print
652  */
653 static int info(lua_State * L)
654 {
655   const char *str = luaL_checkstring(L, 1);
656   XBT_INFO("%s", str);
657   return 0;
658 }
659
660 /**
661  * \brief Runs your application.
662  * \param L a Lua state
663  * \return number of values returned to Lua
664  */
665 static int run(lua_State * L)
666 {
667   MSG_main();
668   return 0;
669 }
670
671 /**
672  * \brief Cleans the simulation.
673  * \param L a Lua state
674  * \return number of values returned to Lua
675  */
676 static int simgrid_gc(lua_State * L)
677 {
678   MSG_clean();
679   return 0;
680 }
681
682 /*
683  * Register platform for MSG
684  */
685 static int msg_register_platform(lua_State * L)
686 {
687   /* Tell Simgrid we dont wanna use its parser */
688   //surf_parse = console_parse_platform;
689   surf_parse_reset_callbacks();
690   MSG_create_environment(NULL);
691   return 0;
692 }
693
694 /*
695  * Register platform for Simdag
696  */
697
698 static int sd_register_platform(lua_State * L)
699 {
700   //surf_parse = console_parse_platform_wsL07;
701   surf_parse_reset_callbacks();
702   SD_create_environment(NULL);
703   return 0;
704 }
705
706 /*
707  * Register platform for gras
708  */
709 static int gras_register_platform(lua_State * L)
710 {
711   //surf_parse = console_parse_platform;
712   surf_parse_reset_callbacks();
713   gras_create_environment(NULL);
714   return 0;
715 }
716
717 /**
718  * Register applicaiton for MSG
719  */
720 static int msg_register_application(lua_State * L)
721 {
722   MSG_function_register_default(run_lua_code);
723   //surf_parse = console_parse_application;
724   MSG_launch_application(NULL);
725   return 0;
726 }
727
728 /*
729  * Register application for gras
730  */
731 static int gras_register_application(lua_State * L)
732 {
733   gras_function_register_default(run_lua_code);
734   //surf_parse = console_parse_application;
735   gras_launch_application(NULL);
736   return 0;
737 }
738
739 static const luaL_Reg simgrid_functions[] = {
740   {"create_environment", create_environment},
741   {"launch_application", launch_application},
742   {"debug", debug},
743   {"info", info},
744   {"run", run},
745   /* short names */
746   {"platform", create_environment},
747   {"application", launch_application},
748   /* methods to bypass XML parser */
749   {"msg_register_platform", msg_register_platform},
750   {"sd_register_platform", sd_register_platform},
751   {"msg_register_application", msg_register_application},
752   {"gras_register_platform", gras_register_platform},
753   {"gras_register_application", gras_register_application},
754   /* gras sub generator method */
755   {"gras_set_process_function", gras_add_process_function},
756   {"gras_generate", gras_generate},
757   {NULL, NULL}
758 };
759
760 /* ********************************************************************************* */
761 /*                           module management functions                             */
762 /* ********************************************************************************* */
763
764 #define LUA_MAX_ARGS_COUNT 10   /* maximum amount of arguments we can get from lua on command line */
765
766 /**
767  * \brief Opens the simgrid Lua module.
768  *
769  * This function is called automatically by the Lua interpreter when some
770  * Lua code requires the "simgrid" module.
771  *
772  * \param L the Lua state
773  */
774 int luaopen_simgrid(lua_State *L)
775 {
776   XBT_DEBUG("luaopen_simgrid *****");
777
778   /* Get the command line arguments from the lua interpreter */
779   char **argv = malloc(sizeof(char *) * LUA_MAX_ARGS_COUNT);
780   int argc = 1;
781   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? */
782
783   lua_getglobal(L, "arg");
784   /* if arg is a null value, it means we use lua only as a script to init platform
785    * else it should be a table and then take arg in consideration
786    */
787   if (lua_istable(L, -1)) {
788     int done = 0;
789     while (!done) {
790       argc++;
791       lua_pushinteger(L, argc - 2);
792       lua_gettable(L, -2);
793       if (lua_isnil(L, -1)) {
794         done = 1;
795       } else {
796         xbt_assert(lua_isstring(L, -1),
797                     "argv[%d] got from lua is no string", argc - 1);
798         xbt_assert(argc < LUA_MAX_ARGS_COUNT,
799                     "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",
800                     __FILE__, LUA_MAX_ARGS_COUNT - 1);
801         argv[argc - 1] = (char *) luaL_checkstring(L, -1);
802         lua_pop(L, 1);
803         XBT_DEBUG("Got command line argument %s from lua", argv[argc - 1]);
804       }
805     }
806     argv[argc--] = NULL;
807
808     /* Initialize the MSG core */
809     MSG_global_init(&argc, argv);
810     XBT_DEBUG("Still %d arguments on command line", argc); // FIXME: update the lua's arg table to reflect the changes from SimGrid
811   }
812
813   /* Keep the context mechanism informed of our lua world today */
814   sglua_maestro_state = L;
815
816   /* initialize access to my tables by children Lua states */
817   lua_newtable(L);
818   lua_setfield(L, LUA_REGISTRYINDEX, "simgrid.maestro_tables");
819
820   register_c_functions(L);
821
822   return 1;
823 }
824
825 /**
826  * \brief Returns whether a Lua state is the maestro state.
827  * \param L a Lua state
828  * \return true if this is maestro
829  */
830 int sglua_is_maestro(lua_State* L) {
831   return L == sglua_maestro_state;
832 }
833
834 /**
835  * \brief Returns the maestro state.
836  * \return the maestro Lua state
837  */
838 lua_State* sglua_get_maestro(void) {
839   return sglua_maestro_state;
840 }
841
842 /**
843  * \brief Registers the task functions into the table simgrid.task.
844  *
845  * Also initialize the metatable of the task userdata type.
846  *
847  * \param L a lua state
848  */
849 static void register_task_functions(lua_State* L)
850 {
851   /* create a table simgrid.task and fill it with task functions */
852   luaL_openlib(L, TASK_MODULE_NAME, task_functions, 0);
853                                   /* simgrid.task */
854
855   /* create the metatable for tasks, add it to the Lua registry */
856   luaL_newmetatable(L, TASK_MODULE_NAME);
857                                   /* simgrid.task mt */
858   /* fill the metatable */
859   luaL_openlib(L, NULL, task_meta, 0);
860                                   /* simgrid.task mt */
861   lua_pushvalue(L, -2);
862                                   /* simgrid.task mt simgrid.task */
863   /* metatable.__index = simgrid.task
864    * we put the task functions inside the task itself:
865    * this allows to write task:method(args) for
866    * simgrid.task.method(task, args) */
867   lua_setfield(L, -2, "__index");
868                                   /* simgrid.task mt */
869   lua_pop(L, 2);
870                                   /* -- */
871 }
872
873 /**
874  * \brief Registers the host functions into the table simgrid.host.
875  *
876  * Also initialize the metatable of the host userdata type.
877  *
878  * \param L a lua state
879  */
880 static void register_host_functions(lua_State* L)
881 {
882   /* create a table simgrid.host and fill it with host functions */
883   luaL_openlib(L, HOST_MODULE_NAME, host_functions, 0);
884                                   /* simgrid.host */
885
886   /* create the metatable for host, add it to the Lua registry */
887   luaL_newmetatable(L, HOST_MODULE_NAME);
888                                   /* simgrid.host mt */
889   /* fill the metatable */
890   luaL_openlib(L, NULL, host_meta, 0);
891                                   /* simgrid.host mt */
892   lua_pushvalue(L, -2);
893                                   /* simgrid.host mt simgrid.host */
894   /* metatable.__index = simgrid.host
895    * we put the host functions inside the host userdata itself:
896    * this allows to write host(args) for
897    * simgrid.host.method(host, args) */
898   // FIXME: cannot work currently, same problem as tasks
899   lua_setfield(L, -2, "__index");
900                                   /* simgrid.host mt */
901   lua_pop(L, 2);
902                                   /* -- */
903 }
904
905 /**
906  * \brief Registers the platform functions into the table simgrid.platf.
907  * \param L a lua state
908  */
909 static void register_platf_functions(lua_State* L)
910 {
911   luaL_openlib(L, PLATF_MODULE_NAME, platf_functions, 0);
912                                   /* simgrid.platf */
913   lua_pop(L, 1);
914 }
915
916 /**
917  * \brief Makes the core functions available to the Lua world.
918  * \param L a Lua world
919  */
920 static void register_core_functions(lua_State *L)
921 {
922   /* register the core C functions to lua */
923   luaL_register(L, "simgrid", simgrid_functions);
924                                   /* simgrid */
925
926   /* set a finalizer that cleans simgrid, by adding to the simgrid module a
927    * dummy userdata whose __gc metamethod calls MSG_clean() */
928   lua_newuserdata(L, sizeof(void*));
929                                   /* simgrid udata */
930   lua_newtable(L);
931                                   /* simgrid udata mt */
932   lua_pushcfunction(L, simgrid_gc);
933                                   /* simgrid udata mt simgrid_gc */
934   lua_setfield(L, -2, "__gc");
935                                   /* simgrid udata mt */
936   lua_setmetatable(L, -2);
937                                   /* simgrid udata */
938   lua_setfield(L, -2, "__simgrid_loaded");
939                                   /* simgrid */
940   lua_pop(L, 1);
941                                   /* -- */
942 }
943
944 /**
945  * \brief Creates the simgrid module and make it available to Lua.
946  * \param L a Lua world
947  */
948 static void register_c_functions(lua_State *L)
949 {
950   register_core_functions(L);
951   register_task_functions(L);
952   register_host_functions(L);
953   register_platf_functions(L);
954 }
955
956 /**
957  * \brief Runs a Lua function as a new simulated process.
958  * \param argc number of arguments of the function
959  * \param argv name of the Lua function and array of its arguments
960  * \return result of the function
961  */
962 static int run_lua_code(int argc, char **argv)
963 {
964   XBT_DEBUG("Run lua code %s", argv[0]);
965
966   /* create a new state, getting globals from maestro */
967   lua_State *L = sglua_clone_maestro();
968   int res = 1;
969
970   /* start the function */
971   lua_getglobal(L, argv[0]);
972   xbt_assert(lua_isfunction(L, -1),
973               "There is no Lua function with name `%s'", argv[0]);
974
975   /* push arguments onto the stack */
976   int i;
977   for (i = 1; i < argc; i++)
978     lua_pushstring(L, argv[i]);
979
980   /* call the function */
981   _XBT_GNUC_UNUSED int err;
982   err = lua_pcall(L, argc - 1, 1, 0);
983   xbt_assert(err == 0, "Error running function `%s': %s", argv[0],
984               lua_tostring(L, -1));
985
986   /* retrieve result */
987   if (lua_isnumber(L, -1)) {
988     res = lua_tonumber(L, -1);
989     lua_pop(L, 1);              /* pop returned value */
990   }
991
992   XBT_DEBUG("Execution of Lua code %s is over", (argv ? argv[0] : "(null)"));
993
994   return res;
995 }