Logo AND Algorithmique Numérique Distribuée

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