Logo AND Algorithmique Numérique Distribuée

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