Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Lua: implementing asynchronous comms (wait, test, isend, dsend, irecv)
[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 COMM_MODULE_NAME "simgrid.comm"
17 #define HOST_MODULE_NAME "simgrid.host"
18 #define PROCESS_MODULE_NAME "simgrid.process"
19 // Surf (bypass XML)
20 #define LINK_MODULE_NAME "simgrid.link"
21 #define ROUTE_MODULE_NAME "simgrid.route"
22 #define PLATF_MODULE_NAME "simgrid.platf"
23
24 static lua_State* sglua_maestro_state;
25
26 static const char* msg_errors[] = {
27     NULL,
28     "timeout",
29     "transfer failure",
30     "host failure",
31     "task canceled"
32 };
33
34 int luaopen_simgrid(lua_State *L);
35 static void register_c_functions(lua_State *L);
36 static int run_lua_code(int argc, char **argv);
37
38 /* ********************************************************************************* */
39 /*                                simgrid.task API                                   */
40 /* ********************************************************************************* */
41
42 /**
43  * \brief Ensures that a value in the stack is a valid task and returns it.
44  * \param L a Lua state
45  * \param index an index in the Lua stack
46  * \return the C task corresponding to this Lua task
47  */
48 static m_task_t sglua_checktask(lua_State* L, int index)
49 {
50   sglua_stack_dump("check task: ", L);
51   luaL_checktype(L, index, LUA_TTABLE);
52                                   /* ... task ... */
53   lua_getfield(L, index, "__simgrid_task");
54                                   /* ... task ... ctask */
55   m_task_t task = *((m_task_t*) luaL_checkudata(L, -1, TASK_MODULE_NAME));
56   lua_pop(L, 1);
57                                   /* ... task ... */
58
59   if (task == NULL) {
60     luaL_error(L, "This task was sent to someone else, you cannot access it anymore");
61   }
62
63   return task;
64 }
65
66 /**
67  * \brief Creates a new task and leaves it onto the stack.
68  * \param L a Lua state
69  * \return number of values returned to Lua
70  *
71  * - Argument 1 (string): name of the task
72  * - Argument 2 (number): computation size
73  * - Argument 3 (number): communication size
74  * - Return value (task): the task created
75  *
76  * A Lua task is a regular table with a full userdata inside, and both share
77  * the same metatable. For the regular table, the metatable allows OO-style
78  * writing such as your_task:send(someone).
79  * For the userdata, the metatable is used to check its type.
80  */
81 static int l_task_new(lua_State* L)
82 {
83   XBT_DEBUG("Task new");
84   const char* name = luaL_checkstring(L, 1);
85   int comp_size = luaL_checkint(L, 2);
86   int msg_size = luaL_checkint(L, 3);
87                                   /* name comp comm */
88   lua_settop(L, 0);
89                                   /* -- */
90   m_task_t msg_task = MSG_task_create(name, comp_size, msg_size, NULL);
91
92   lua_newtable(L);
93                                   /* task */
94   luaL_getmetatable(L, TASK_MODULE_NAME);
95                                   /* task mt */
96   lua_setmetatable(L, -2);
97                                   /* task */
98   m_task_t* lua_task = (m_task_t*) lua_newuserdata(L, sizeof(m_task_t));
99                                   /* task ctask */
100   *lua_task = msg_task;
101   luaL_getmetatable(L, TASK_MODULE_NAME);
102                                   /* task ctask mt */
103   lua_setmetatable(L, -2);
104                                   /* task ctask */
105   lua_setfield(L, -2, "__simgrid_task");
106                                   /* task */
107   return 1;
108 }
109
110 /**
111  * \brief Returns the name of a task.
112  * \param L a Lua state
113  * \return number of values returned to Lua
114  *
115  * - Argument 1 (task): a task
116  * - Return value (string): name of the task
117  */
118 static int l_task_get_name(lua_State* L)
119 {
120   m_task_t task = sglua_checktask(L, 1);
121   lua_pushstring(L, MSG_task_get_name(task));
122   return 1;
123 }
124
125 /**
126  * \brief Returns the computation duration of a task.
127  * \param L a Lua state
128  * \return number of values returned to Lua
129  *
130  * - Argument 1 (task): a task
131  * - Return value (number): computation duration of this task
132  */
133 static int l_task_get_computation_duration(lua_State* L)
134 {
135   m_task_t task = sglua_checktask(L, 1);
136   lua_pushnumber(L, MSG_task_get_compute_duration(task));
137   return 1;
138 }
139
140 /**
141  * \brief Executes a task.
142  * \param L a Lua state
143  * \return number of values returned to Lua
144  *
145  * - Argument 1 (task): the task to execute
146  * - Return value (nil or string): nil if the task was successfully executed,
147  * or an error string in case of failure, which may be "task canceled" or
148  * "host failure"
149  */
150 static int l_task_execute(lua_State* L)
151 {
152   m_task_t task = sglua_checktask(L, 1);
153   MSG_error_t res = MSG_task_execute(task);
154
155   if (res == MSG_OK) {
156     return 0;
157   }
158   else {
159     lua_pushstring(L, msg_errors[res]);
160     return 1;
161   }
162 }
163
164 /**
165  * \brief Sends a task to a mailbox and waits for its completion.
166  * \param L a Lua state
167  * \return number of values returned to Lua
168  *
169  * - Argument 1 (task): the task to send
170  * - Argument 2 (string or compatible): mailbox name, as a real string or any
171  * type convertible to string (numbers always are)
172  * - Return values (nil or string): nil if the communication was successful,
173  * or an error string in case of failure, which may be "timeout",
174  * "host failure" or "transfer failure"
175  */
176 static int l_task_send(lua_State* L)
177 {
178   m_task_t task = sglua_checktask(L, 1);
179   const char* mailbox = luaL_checkstring(L, 2);
180                                   /* task mailbox */
181   lua_settop(L, 1);
182                                   /* task */
183   /* copy my stack into the task, so that the receiver can copy the lua task */
184   MSG_task_set_data(task, L);
185   MSG_error_t res = MSG_task_send(task, mailbox);
186   while (MSG_task_get_data(task) != NULL) {
187     /* don't mess up with my stack: the receiver didn't copy the data yet */
188     MSG_process_sleep(0);
189   }
190
191   if (res == 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   else {
201     lua_settop(L, 0);
202     lua_pushstring(L, msg_errors[res]);
203     return 1;
204   }
205 }
206
207 static int l_task_isend(lua_State* L)
208 {
209   // TODO
210   return 0;
211 }
212
213 static int l_task_dsend(lua_State* L)
214 {
215   // TODO
216   return 0;
217 }
218
219 /**
220  * \brief Receives a task.
221  * \param L a Lua state
222  * \return number of values returned to Lua
223  *
224  * - Argument 1 (string or compatible): mailbox name, as a real string or any
225  * type convertible to string (numbers always are)
226  * - Argument 2 (number, optional): timeout (default is no timeout)
227  * - Return values (task or nil + string): the task received, or nil plus an
228  * error message if the communication has failed
229  */
230 static int l_task_recv(lua_State* L)
231 {
232   m_task_t task = NULL;
233   const char* mailbox = luaL_checkstring(L, 1);
234   int timeout;
235   if (lua_gettop(L) >= 2) {
236                                   /* mailbox timeout */
237     timeout = luaL_checknumber(L, 2);
238   }
239   else {
240                                   /* mailbox */
241     timeout = -1;
242     /* no timeout by default */
243   }
244   lua_settop(L, 0);
245                                   /* -- */
246   MSG_error_t res = MSG_task_receive_with_timeout(&task, mailbox, timeout);
247
248   if (res == MSG_OK) {
249     /* copy the data directly from sender's stack */
250     lua_State* sender_stack = MSG_task_get_data(task);
251     sglua_copy_value(sender_stack, L);
252                                   /* task */
253     MSG_task_set_data(task, NULL);
254     return 1;
255   }
256   else {
257     lua_pushnil(L);
258     lua_pushstring(L, msg_errors[res]);
259     return 2;
260   }
261 }
262
263 static int l_task_irecv(lua_State* L)
264 {
265   // TODO
266   return 0;
267 }
268
269 static const luaL_reg task_functions[] = {
270   {"new", l_task_new},
271   {"get_name", l_task_get_name},
272   {"get_computation_duration", l_task_get_computation_duration},
273   {"execute", l_task_execute},
274   {"send", l_task_send},
275   {"isend", l_task_isend},
276   {"dsend", l_task_dsend},
277   {"recv", l_task_recv},
278   {"irecv", l_task_irecv},
279   {NULL, NULL}
280 };
281
282 /**
283  * \brief Finalizes the userdata of a task.
284  * \param L a Lua state
285  * \return number of values returned to Lua
286  *
287  * - Argument 1 (userdata): a C task, possibly NULL if it was sent to another
288  * Lua state
289  */
290 static int l_task_gc(lua_State* L)
291 {
292                                   /* ctask */
293   m_task_t task = *((m_task_t*) luaL_checkudata(L, 1, TASK_MODULE_NAME));
294   /* the task is NULL if I sent it to someone else */
295   if (task != NULL) {
296     MSG_task_destroy(task);
297   }
298   return 0;
299 }
300
301 /**
302  * \brief Returns a string representation of a C task.
303  * \param L a Lua state
304  * \return number of values returned to Lua
305  *
306  * - Argument 1 (userdata): a task
307  * - Return value (string): a string describing this task
308  */
309 static int l_task_tostring(lua_State* L)
310 {
311   m_task_t task = *((m_task_t*) luaL_checkudata(L, 1, TASK_MODULE_NAME));
312   lua_pushfstring(L, "Task: %p", task);
313   return 1;
314 }
315
316 /**
317  * \brief Metamethods of both a task table and the userdata inside it.
318  */
319 static const luaL_reg task_meta[] = {
320   {"__gc", l_task_gc}, /* will be called only for userdata */
321   {"__tostring", l_task_tostring},
322   {NULL, NULL}
323 };
324
325 /* ********************************************************************************* */
326 /*                                simgrid.comm API                                   */
327 /* ********************************************************************************* */
328
329 /**
330  * \brief Ensures that a value in the stack is a comm and returns it.
331  * \param L a Lua state
332  * \param index an index in the Lua stack
333  * \return the C comm
334  */
335 static msg_comm_t sglua_checkcomm(lua_State* L, int index)
336 {
337   msg_comm_t comm = *((msg_comm_t*) luaL_checkudata(L, index, COMM_MODULE_NAME));
338   lua_pop(L, 1);
339   return comm;
340 }
341
342 /**
343  * \brief Blocks the current process until a communication is finished.
344  * \param L a Lua state
345  * \return number of values returned to Lua
346  *
347  * This function performs a waitany operation: you can specify an
348  * individual communication or a list of communications.
349  * If you provide a list, the function returns whenever one communication of
350  * the list is finished, and this communication will be removed from you list.
351  * This means you can make a waitall operation with successive calls to this
352  * function.
353  *
354  * - Argument 1 (comm or table): a comm or an array of comms
355  * - Argument 2 (number, optional): timeout (supported only when there is only
356  * one comm)
357  * - Return values (comm + string): the first comm of your list that finishes,
358  * plus an error string if this comm was unsuccessful.
359  */
360 static int l_comm_wait(lua_State* L) {
361
362   if (lua_istable(L, 1)) {
363     // TODO implement waitany
364     THROW_UNIMPLEMENTED;
365   }
366   else {
367     /* only one comm */
368     msg_comm_t comm = sglua_checkcomm(L, 1);
369     double timeout = -1;
370     if (lua_gettop(L) >= 2) {
371       timeout = luaL_checknumber(L, 2);
372     }
373                                   /* comm ... */
374     MSG_error_t res = MSG_comm_wait(comm, timeout);
375     lua_settop(L, 1);
376                                   /* comm */
377     if (res == MSG_OK) {
378       return 1;
379     }
380     else {
381       lua_pushstring(L, msg_errors[res]);
382                                   /* comm error */
383       return 2;
384     }
385   }
386   return 0;
387 }
388
389 /**
390  * @brief Returns whether a communication is finished.
391  *
392  * This function always returns immediately.
393  * It performs a testany operation: you can provide an individual
394  * communication or a list of communications.
395  *
396  * - Argument 1 (comm or table): a comm or an array of comms
397  * - Return values (nil or comm + string): if no comm from your list is finished
398  * yet, returns nil. If a comm is finished, removes it from your list and
399  * returns it, plus an error string if it was unsuccessful.
400  */
401 static int l_comm_test(lua_State* L) {
402
403   if (lua_istable(L, 1)) {
404     /* TODO implement testany */
405     THROW_UNIMPLEMENTED;
406   }
407   else {
408     /* only one comm */
409     msg_comm_t comm = sglua_checkcomm(L, 1);
410                                   /* comm ... */
411     if (!MSG_comm_test(comm)) {
412       return 0;
413     }
414     else {
415       lua_settop(L, 1);
416                                   /* comm */
417       MSG_error_t res = MSG_comm_get_status(comm);
418       if (res == MSG_OK) {
419         return 1;
420       }
421       else {
422         lua_pushstring(L, msg_errors[res]);
423                                   /* comm error */
424         return 2;
425       }
426     }
427   }
428 }
429
430 static const luaL_reg comm_functions[] = {
431   {"wait", l_comm_wait},
432   {"test", l_comm_test},
433   {NULL, NULL}
434 };
435
436 /**
437  * \brief Finalizes a comm userdata.
438  * \param L a Lua state
439  * \return number of values returned to Lua
440  *
441  * - Argument 1 (userdata): a comm
442  */
443 static int l_comm_gc(lua_State* L)
444 {
445                                   /* ctask */
446   msg_comm_t comm = *((msg_comm_t*) luaL_checkudata(L, 1, COMM_MODULE_NAME));
447   MSG_comm_destroy(comm);
448   return 0;
449 }
450
451 /**
452  * \brief Metamethods of the comm userdata.
453  */
454 static const luaL_reg comm_meta[] = {
455   {"__gc", l_comm_gc},
456   {NULL, NULL}
457 };
458
459 /* ********************************************************************************* */
460 /*                                simgrid.host API                                   */
461 /* ********************************************************************************* */
462
463 /**
464  * \brief Ensures that a value in the stack is a host and returns it.
465  * \param L a Lua state
466  * \param index an index in the Lua stack
467  * \return the C host corresponding to this Lua host
468  */
469 static m_host_t sglua_checkhost(lua_State * L, int index)
470 {
471   m_host_t *pi, ht;
472   luaL_checktype(L, index, LUA_TTABLE);
473   lua_getfield(L, index, "__simgrid_host");
474   pi = (m_host_t *) luaL_checkudata(L, lua_gettop(L), HOST_MODULE_NAME);
475   if (pi == NULL)
476     luaL_typerror(L, index, HOST_MODULE_NAME);
477   ht = *pi;
478   if (!ht)
479     luaL_error(L, "null Host");
480   lua_pop(L, 1);
481   return ht;
482 }
483
484 /**
485  * \brief Returns a host given its name.
486  * \param L a Lua state
487  * \return number of values returned to Lua
488  *
489  * - Argument 1 (string): name of a host
490  * - Return value (host): the corresponding host
491  */
492 static int l_host_get_by_name(lua_State * L)
493 {
494   const char *name = luaL_checkstring(L, 1);
495   XBT_DEBUG("Getting Host from name...");
496   m_host_t msg_host = MSG_get_host_by_name(name);
497   if (!msg_host) {
498     luaL_error(L, "null Host : MSG_get_host_by_name failed");
499   }
500   lua_newtable(L);              /* create a table, put the userdata on top of it */
501   m_host_t *lua_host = (m_host_t *) lua_newuserdata(L, sizeof(m_host_t));
502   *lua_host = msg_host;
503   luaL_getmetatable(L, HOST_MODULE_NAME);
504   lua_setmetatable(L, -2);
505   lua_setfield(L, -2, "__simgrid_host");        /* put the userdata as field of the table */
506   /* remove the args from the stack */
507   lua_remove(L, 1);
508   return 1;
509 }
510
511 /**
512  * \brief Returns the name of a host.
513  * \param L a Lua state
514  * \return number of values returned to Lua
515  *
516  * - Argument 1 (host): a host
517  * - Return value (string): name of this host
518  */
519 static int l_host_get_name(lua_State * L)
520 {
521   m_host_t ht = sglua_checkhost(L, 1);
522   lua_pushstring(L, MSG_host_get_name(ht));
523   return 1;
524 }
525
526 /**
527  * \brief Returns the number of existing hosts.
528  * \param L a Lua state
529  * \return number of values returned to Lua
530  *
531  * - Return value (number): number of hosts
532  */
533 static int l_host_number(lua_State * L)
534 {
535   lua_pushnumber(L, MSG_get_host_number());
536   return 1;
537 }
538
539 /**
540  * \brief Returns the host given its index.
541  * \param L a Lua state
542  * \return number of values returned to Lua
543  *
544  * - Argument 1 (number): an index (1 is the first)
545  * - Return value (host): the host at this index
546  */
547 static int l_host_at(lua_State * L)
548 {
549   int index = luaL_checkinteger(L, 1);
550   m_host_t host = MSG_get_host_table()[index - 1];      // lua indexing start by 1 (lua[1] <=> C[0])
551   lua_newtable(L);              /* create a table, put the userdata on top of it */
552   m_host_t *lua_host = (m_host_t *) lua_newuserdata(L, sizeof(m_host_t));
553   *lua_host = host;
554   luaL_getmetatable(L, HOST_MODULE_NAME);
555   lua_setmetatable(L, -2);
556   lua_setfield(L, -2, "__simgrid_host");        /* put the userdata as field of the table */
557   return 1;
558 }
559
560 /**
561  * \brief Returns the host where the current process is located.
562  * \param L a Lua state
563  * \return number of values returned to Lua
564  *
565  * - Return value (host): the current host
566  */
567 static int l_host_self(lua_State * L)
568 {
569                                   /* -- */
570   m_host_t host = MSG_host_self();
571   lua_newtable(L);
572                                   /* table */
573   m_host_t* lua_host = (m_host_t*) lua_newuserdata(L, sizeof(m_host_t));
574                                   /* table ud */
575   *lua_host = host;
576   luaL_getmetatable(L, HOST_MODULE_NAME);
577                                   /* table ud mt */
578   lua_setmetatable(L, -2);
579                                   /* table ud */
580   lua_setfield(L, -2, "__simgrid_host");
581                                   /* table */
582   return 1;
583 }
584
585 /**
586  * \brief Returns the value of a host property.
587  * \param L a Lua state
588  * \return number of values returned to Lua
589  *
590  * - Argument 1 (host): a host
591  * - Argument 2 (string): name of the property to get
592  * - Return value (string): the value of this property
593  */
594 static int l_host_get_property_value(lua_State * L)
595 {
596   m_host_t ht = sglua_checkhost(L, 1);
597   const char *prop = luaL_checkstring(L, 2);
598   lua_pushstring(L,MSG_host_get_property_value(ht,prop));
599   return 1;
600 }
601
602 /**
603  * \brief Makes the current process sleep for a while.
604  * \param L a Lua state
605  * \return number of values returned to Lua
606  *
607  * - Argument 1 (number): duration of the sleep
608  */
609 static int l_host_sleep(lua_State *L)
610 {
611   int time = luaL_checknumber(L, 1);
612   MSG_process_sleep(time);
613   return 0;
614 }
615
616 /**
617  * \brief Destroys a host.
618  * \param L a Lua state
619  * \return number of values returned to Lua
620  *
621  * - Argument 1 (host): the host to destroy
622  */
623 static int l_host_destroy(lua_State *L)
624 {
625   m_host_t ht = sglua_checkhost(L, 1);
626   __MSG_host_destroy(ht);
627   return 0;
628 }
629
630 static const luaL_reg host_functions[] = {
631   {"get_by_name", l_host_get_by_name},
632   {"name", l_host_get_name},
633   {"number", l_host_number},
634   {"at", l_host_at},
635   {"self", l_host_self},
636   {"get_prop_value", l_host_get_property_value},
637   {"sleep", l_host_sleep},
638   {"destroy", l_host_destroy},
639   // Bypass XML Methods
640   {"set_function", console_set_function},
641   {"set_property", console_host_set_property},
642   {NULL, NULL}
643 };
644
645 /**
646  * \brief Returns a string representation of a host.
647  * \param L a Lua state
648  * \return number of values returned to Lua
649  *
650  * - Argument 1 (userdata): a host
651  * - Return value (string): a string describing this host
652  */
653 static int l_host_tostring(lua_State * L)
654 {
655   lua_pushfstring(L, "Host :%p", lua_touserdata(L, 1));
656   return 1;
657 }
658
659 static const luaL_reg host_meta[] = {
660   {"__tostring", l_host_tostring},
661   {0, 0}
662 };
663
664 /* ********************************************************************************* */
665 /*                              simgrid.process API                                  */
666 /* ********************************************************************************* */
667
668 /**
669  * \brief Makes the current process sleep for a while.
670  * \param L a Lua state
671  * \return number of values returned to Lua
672  *
673  * - Argument 1 (number): duration of the sleep
674  * - Return value (nil or string): nil in everything went ok, or a string error
675  * if case of failure ("host failure")
676  */
677 static int l_process_sleep(lua_State* L)
678 {
679   double duration = luaL_checknumber(L, 1);
680   MSG_error_t res = MSG_process_sleep(duration);
681
682   switch (res) {
683
684   case MSG_OK:
685     return 0;
686
687   case MSG_HOST_FAILURE:
688     lua_pushliteral(L, "host failure");
689     return 1;
690
691   default:
692     xbt_die("Unexpected result of MSG_process_sleep: %d, please report this bug", res);
693   }
694 }
695
696 static const luaL_reg process_functions[] = {
697     {"sleep", l_process_sleep},
698     /* TODO: self, create, kill, suspend, is_suspended, resume, get_name,
699      * get_pid, get_ppid, migrate
700      */
701     {NULL, NULL}
702 };
703
704 /* ********************************************************************************* */
705 /*                           lua_stub_generator functions                            */
706 /* ********************************************************************************* */
707
708 xbt_dict_t process_function_set;
709 xbt_dynar_t process_list;
710 xbt_dict_t machine_set;
711 static s_process_t process;
712
713 void s_process_free(void *process)
714 {
715   s_process_t *p = (s_process_t *) process;
716   int i;
717   for (i = 0; i < p->argc; i++)
718     free(p->argv[i]);
719   free(p->argv);
720   free(p->host);
721 }
722
723 static int gras_add_process_function(lua_State * L)
724 {
725   const char *arg;
726   const char *process_host = luaL_checkstring(L, 1);
727   const char *process_function = luaL_checkstring(L, 2);
728
729   if (xbt_dict_is_empty(machine_set)
730       || xbt_dict_is_empty(process_function_set)
731       || xbt_dynar_is_empty(process_list)) {
732     process_function_set = xbt_dict_new();
733     process_list = xbt_dynar_new(sizeof(s_process_t), s_process_free);
734     machine_set = xbt_dict_new();
735   }
736
737   xbt_dict_set(machine_set, process_host, NULL, NULL);
738   xbt_dict_set(process_function_set, process_function, NULL, NULL);
739
740   process.argc = 1;
741   process.argv = xbt_new(char *, 1);
742   process.argv[0] = xbt_strdup(process_function);
743   process.host = strdup(process_host);
744
745   lua_pushnil(L);
746   while (lua_next(L, 3) != 0) {
747     arg = lua_tostring(L, -1);
748     process.argc++;
749     process.argv =
750         xbt_realloc(process.argv, (process.argc) * sizeof(char *));
751     process.argv[(process.argc) - 1] = xbt_strdup(arg);
752
753     XBT_DEBUG("index = %f , arg = %s \n", lua_tonumber(L, -2),
754            lua_tostring(L, -1));
755     lua_pop(L, 1);
756   }
757   lua_pop(L, 1);
758   //add to the process list
759   xbt_dynar_push(process_list, &process);
760   return 0;
761 }
762
763 static int gras_generate(lua_State * L)
764 {
765   const char *project_name = luaL_checkstring(L, 1);
766   generate_sim(project_name);
767   generate_rl(project_name);
768   generate_makefile_local(project_name);
769   return 0;
770 }
771
772 /* ********************************************************************************* */
773 /*                               simgrid.platf API                                   */
774 /* ********************************************************************************* */
775
776 static const luaL_reg platf_functions[] = {
777     {"open", console_open},
778     {"close", console_close},
779     {"AS_open", console_AS_open},
780     {"AS_close", console_AS_close},
781     {"host_new", console_add_host},
782     {"link_new", console_add_link},
783     {"router_new", console_add_router},
784     {"route_new", console_add_route},
785     {NULL, NULL}
786 };
787
788 /* ********************************************************************************* */
789 /*                                  simgrid API                                      */
790 /* ********************************************************************************* */
791
792 /**
793  * \brief Deploys your application.
794  * \param L a Lua state
795  * \return number of values returned to Lua
796  *
797  * - Argument 1 (string): name of the deployment file to load
798  */
799 static int launch_application(lua_State* L) {
800
801   const char* file = luaL_checkstring(L, 1);
802   MSG_function_register_default(run_lua_code);
803   MSG_launch_application(file);
804   return 0;
805 }
806
807 /**
808  * \brief Creates the platform.
809  * \param L a Lua state
810  * \return number of values returned to Lua
811  *
812  * - Argument 1 (string): name of the platform file to load
813  */
814 static int create_environment(lua_State* L) {
815
816   const char* file = luaL_checkstring(L, 1);
817   XBT_DEBUG("Loading environment file %s", file);
818   MSG_create_environment(file);
819   return 0;
820 }
821
822 /**
823  * \brief Prints a log string with debug level.
824  * \param L a Lua state
825  * \return number of values returned to Lua
826  *
827  * - Argument 1 (string): the text to print
828  */
829 static int debug(lua_State* L) {
830
831   const char* str = luaL_checkstring(L, 1);
832   XBT_DEBUG("%s", str);
833   return 0;
834 }
835
836 /**
837  * \brief Prints a log string with info level.
838  * \param L a Lua state
839  * \return number of values returned to Lua
840  *
841  * - Argument 1 (string): the text to print
842  */
843 static int info(lua_State* L) {
844
845   const char* str = luaL_checkstring(L, 1);
846   XBT_INFO("%s", str);
847   return 0;
848 }
849
850 /**
851  * \brief Runs your application.
852  * \param L a Lua state
853  * \return number of values returned to Lua
854  */
855 static int run(lua_State*  L) {
856
857   MSG_main();
858   return 0;
859 }
860
861 /**
862  * \brief Returns the current simulated time.
863  * \param L a Lua state
864  * \return number of values returned to Lua
865  *
866  * - Return value (number): the simulated time
867  */
868 static int get_clock(lua_State* L) {
869
870   lua_pushnumber(L, MSG_get_clock());
871   return 1;
872 }
873
874 /**
875  * \brief Cleans the simulation.
876  * \param L a Lua state
877  * \return number of values returned to Lua
878  */
879 static int simgrid_gc(lua_State * L)
880 {
881   MSG_clean();
882   return 0;
883 }
884
885 /*
886  * Register platform for MSG
887  */
888 static int msg_register_platform(lua_State * L)
889 {
890   /* Tell Simgrid we dont wanna use its parser */
891   //surf_parse = console_parse_platform;
892   surf_parse_reset_callbacks();
893   MSG_create_environment(NULL);
894   return 0;
895 }
896
897 /*
898  * Register platform for Simdag
899  */
900
901 static int sd_register_platform(lua_State * L)
902 {
903   //surf_parse = console_parse_platform_wsL07;
904   surf_parse_reset_callbacks();
905   SD_create_environment(NULL);
906   return 0;
907 }
908
909 /*
910  * Register platform for gras
911  */
912 static int gras_register_platform(lua_State * L)
913 {
914   //surf_parse = console_parse_platform;
915   surf_parse_reset_callbacks();
916   gras_create_environment(NULL);
917   return 0;
918 }
919
920 /**
921  * Register applicaiton for MSG
922  */
923 static int msg_register_application(lua_State * L)
924 {
925   MSG_function_register_default(run_lua_code);
926   //surf_parse = console_parse_application;
927   MSG_launch_application(NULL);
928   return 0;
929 }
930
931 /*
932  * Register application for gras
933  */
934 static int gras_register_application(lua_State * L)
935 {
936   gras_function_register_default(run_lua_code);
937   //surf_parse = console_parse_application;
938   gras_launch_application(NULL);
939   return 0;
940 }
941
942 static const luaL_Reg simgrid_functions[] = {
943   {"create_environment", create_environment},
944   {"launch_application", launch_application},
945   {"debug", debug},
946   {"info", info},
947   {"run", run},
948   {"get_clock", get_clock},
949   /* short names */
950   {"platform", create_environment},
951   {"application", launch_application},
952   /* methods to bypass XML parser */
953   {"msg_register_platform", msg_register_platform},
954   {"sd_register_platform", sd_register_platform},
955   {"msg_register_application", msg_register_application},
956   {"gras_register_platform", gras_register_platform},
957   {"gras_register_application", gras_register_application},
958   /* gras sub generator method */
959   {"gras_set_process_function", gras_add_process_function},
960   {"gras_generate", gras_generate},
961   {NULL, NULL}
962 };
963
964 /* ********************************************************************************* */
965 /*                           module management functions                             */
966 /* ********************************************************************************* */
967
968 #define LUA_MAX_ARGS_COUNT 10   /* maximum amount of arguments we can get from lua on command line */
969
970 /**
971  * \brief Opens the simgrid Lua module.
972  *
973  * This function is called automatically by the Lua interpreter when some
974  * Lua code requires the "simgrid" module.
975  *
976  * \param L the Lua state
977  */
978 int luaopen_simgrid(lua_State *L)
979 {
980   XBT_DEBUG("luaopen_simgrid *****");
981
982   /* Get the command line arguments from the lua interpreter */
983   char **argv = malloc(sizeof(char *) * LUA_MAX_ARGS_COUNT);
984   int argc = 1;
985   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? */
986
987   lua_getglobal(L, "arg");
988   /* if arg is a null value, it means we use lua only as a script to init platform
989    * else it should be a table and then take arg in consideration
990    */
991   if (lua_istable(L, -1)) {
992     int done = 0;
993     while (!done) {
994       argc++;
995       lua_pushinteger(L, argc - 2);
996       lua_gettable(L, -2);
997       if (lua_isnil(L, -1)) {
998         done = 1;
999       } else {
1000         xbt_assert(lua_isstring(L, -1),
1001                     "argv[%d] got from lua is no string", argc - 1);
1002         xbt_assert(argc < LUA_MAX_ARGS_COUNT,
1003                     "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",
1004                     __FILE__, LUA_MAX_ARGS_COUNT - 1);
1005         argv[argc - 1] = (char *) luaL_checkstring(L, -1);
1006         lua_pop(L, 1);
1007         XBT_DEBUG("Got command line argument %s from lua", argv[argc - 1]);
1008       }
1009     }
1010     argv[argc--] = NULL;
1011
1012     /* Initialize the MSG core */
1013     MSG_global_init(&argc, argv);
1014     XBT_DEBUG("Still %d arguments on command line", argc); // FIXME: update the lua's arg table to reflect the changes from SimGrid
1015   }
1016
1017   /* Keep the context mechanism informed of our lua world today */
1018   sglua_maestro_state = L;
1019
1020   /* initialize access to my tables by children Lua states */
1021   lua_newtable(L);
1022   lua_setfield(L, LUA_REGISTRYINDEX, "simgrid.maestro_tables");
1023
1024   register_c_functions(L);
1025
1026   return 1;
1027 }
1028
1029 /**
1030  * \brief Returns whether a Lua state is the maestro state.
1031  * \param L a Lua state
1032  * \return true if this is maestro
1033  */
1034 int sglua_is_maestro(lua_State* L) {
1035   return L == sglua_maestro_state;
1036 }
1037
1038 /**
1039  * \brief Returns the maestro state.
1040  * \return the maestro Lua state
1041  */
1042 lua_State* sglua_get_maestro(void) {
1043   return sglua_maestro_state;
1044 }
1045
1046 /**
1047  * \brief Registers the task functions into the table simgrid.task.
1048  *
1049  * Also initialize the metatable of the task userdata type.
1050  *
1051  * \param L a lua state
1052  */
1053 static void register_task_functions(lua_State* L)
1054 {
1055   /* create a table simgrid.task and fill it with task functions */
1056   luaL_openlib(L, TASK_MODULE_NAME, task_functions, 0);
1057                                   /* simgrid.task */
1058
1059   /* create the metatable for tasks, add it to the Lua registry */
1060   luaL_newmetatable(L, TASK_MODULE_NAME);
1061                                   /* simgrid.task mt */
1062   /* fill the metatable */
1063   luaL_openlib(L, NULL, task_meta, 0);
1064                                   /* simgrid.task mt */
1065   lua_pushvalue(L, -2);
1066                                   /* simgrid.task mt simgrid.task */
1067   /* metatable.__index = simgrid.task
1068    * we put the task functions inside the task itself:
1069    * this allows to write my_task:method(args) for
1070    * simgrid.task.method(my_task, args) */
1071   lua_setfield(L, -2, "__index");
1072                                   /* simgrid.task mt */
1073   lua_pop(L, 2);
1074                                   /* -- */
1075 }
1076
1077 /**
1078  * \brief Registers the comm functions into the table simgrid.comm.
1079  *
1080  * Also initialize the metatable of the comm userdata type.
1081  *
1082  * \param L a lua state
1083  */
1084 static void register_comm_functions(lua_State* L)
1085 {
1086   /* create a table simgrid.com and fill it with com functions */
1087   luaL_openlib(L, COMM_MODULE_NAME, comm_functions, 0);
1088                                   /* simgrid.comm */
1089
1090   /* create the metatable for comms, add it to the Lua registry */
1091   luaL_newmetatable(L, COMM_MODULE_NAME);
1092                                   /* simgrid.comm mt */
1093   /* fill the metatable */
1094   luaL_openlib(L, NULL, comm_meta, 0);
1095                                   /* simgrid.comm mt */
1096   lua_pushvalue(L, -2);
1097                                   /* simgrid.comm mt simgrid.comm */
1098   /* metatable.__index = simgrid.comm
1099    * we put the comm functions inside the comm itself:
1100    * this allows to write my_comm:method(args) for
1101    * simgrid.comm.method(my_comm, args) */
1102   lua_setfield(L, -2, "__index");
1103                                   /* simgrid.comm mt */
1104   lua_pop(L, 2);
1105                                   /* -- */
1106 }
1107
1108 /**
1109  * \brief Registers the host functions into the table simgrid.host.
1110  *
1111  * Also initialize the metatable of the host userdata type.
1112  *
1113  * \param L a lua state
1114  */
1115 static void register_host_functions(lua_State* L)
1116 {
1117   /* create a table simgrid.host and fill it with host functions */
1118   luaL_openlib(L, HOST_MODULE_NAME, host_functions, 0);
1119                                   /* simgrid.host */
1120
1121   /* create the metatable for host, add it to the Lua registry */
1122   luaL_newmetatable(L, HOST_MODULE_NAME);
1123                                   /* simgrid.host mt */
1124   /* fill the metatable */
1125   luaL_openlib(L, NULL, host_meta, 0);
1126                                   /* simgrid.host mt */
1127   lua_pushvalue(L, -2);
1128                                   /* simgrid.host mt simgrid.host */
1129   /* metatable.__index = simgrid.host
1130    * we put the host functions inside the host userdata itself:
1131    * this allows to write my_host:method(args) for
1132    * simgrid.host.method(my_host, args) */
1133   lua_setfield(L, -2, "__index");
1134                                   /* simgrid.host mt */
1135   lua_pop(L, 2);
1136                                   /* -- */
1137 }
1138
1139 /**
1140  * \brief Registers the process functions into the table simgrid.process.
1141  * \param L a lua state
1142  */
1143 static void register_process_functions(lua_State* L)
1144 {
1145   luaL_openlib(L, PROCESS_MODULE_NAME, process_functions, 0);
1146                                   /* simgrid.process */
1147   lua_pop(L, 1);
1148 }
1149
1150 /**
1151  * \brief Registers the platform functions into the table simgrid.platf.
1152  * \param L a lua state
1153  */
1154 static void register_platf_functions(lua_State* L)
1155 {
1156   luaL_openlib(L, PLATF_MODULE_NAME, platf_functions, 0);
1157                                   /* simgrid.platf */
1158   lua_pop(L, 1);
1159 }
1160
1161 /**
1162  * \brief Makes the core functions available to the Lua world.
1163  * \param L a Lua world
1164  */
1165 static void register_core_functions(lua_State *L)
1166 {
1167   /* register the core C functions to lua */
1168   luaL_register(L, "simgrid", simgrid_functions);
1169                                   /* simgrid */
1170
1171   /* set a finalizer that cleans simgrid, by adding to the simgrid module a
1172    * dummy userdata whose __gc metamethod calls MSG_clean() */
1173   lua_newuserdata(L, sizeof(void*));
1174                                   /* simgrid udata */
1175   lua_newtable(L);
1176                                   /* simgrid udata mt */
1177   lua_pushcfunction(L, simgrid_gc);
1178                                   /* simgrid udata mt simgrid_gc */
1179   lua_setfield(L, -2, "__gc");
1180                                   /* simgrid udata mt */
1181   lua_setmetatable(L, -2);
1182                                   /* simgrid udata */
1183   lua_setfield(L, -2, "__simgrid_loaded");
1184                                   /* simgrid */
1185   lua_pop(L, 1);
1186                                   /* -- */
1187 }
1188
1189 /**
1190  * \brief Creates the simgrid module and make it available to Lua.
1191  * \param L a Lua world
1192  */
1193 static void register_c_functions(lua_State *L)
1194 {
1195   register_core_functions(L);
1196   register_task_functions(L);
1197   register_comm_functions(L);
1198   register_host_functions(L);
1199   register_process_functions(L);
1200   register_platf_functions(L);
1201 }
1202
1203 /**
1204  * \brief Runs a Lua function as a new simulated process.
1205  * \param argc number of arguments of the function
1206  * \param argv name of the Lua function and array of its arguments
1207  * \return result of the function
1208  */
1209 static int run_lua_code(int argc, char **argv)
1210 {
1211   XBT_DEBUG("Run lua code %s", argv[0]);
1212
1213   /* create a new state, getting globals from maestro */
1214   lua_State *L = sglua_clone_maestro();
1215   int res = 1;
1216
1217   /* start the function */
1218   lua_getglobal(L, argv[0]);
1219   xbt_assert(lua_isfunction(L, -1),
1220               "There is no Lua function with name `%s'", argv[0]);
1221
1222   /* push arguments onto the stack */
1223   int i;
1224   for (i = 1; i < argc; i++)
1225     lua_pushstring(L, argv[i]);
1226
1227   /* call the function */
1228   _XBT_GNUC_UNUSED int err;
1229   err = lua_pcall(L, argc - 1, 1, 0);
1230   xbt_assert(err == 0, "Error running function `%s': %s", argv[0],
1231               lua_tostring(L, -1));
1232
1233   /* retrieve result */
1234   if (lua_isnumber(L, -1)) {
1235     res = lua_tonumber(L, -1);
1236     lua_pop(L, 1);              /* pop returned value */
1237   }
1238
1239   XBT_DEBUG("Execution of Lua code %s is over", (argv ? argv[0] : "(null)"));
1240
1241   return res;
1242 }