Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Revert "These messages should be print in debug logs only"
[simgrid.git] / src / bindings / lua / simgrid_lua.c
1 /* SimGrid Lua bindings                                                     */
2
3 /* Copyright (c) 2010. The SimGrid Team.
4  * All rights reserved.                                                     */
5
6 /* This program is free software; you can redistribute it and/or modify it
7  * under the terms of the license (GNU LGPL) which comes with this package. */
8 #include "simgrid_lua.h"
9 #include <string.h> // memcpy
10
11 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(lua, bindings, "Lua Bindings");
12
13 static lua_State *lua_maestro_state;
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 AS_MODULE_NAME "simgrid.AS"
21 #define TRACE_MODULE_NAME "simgrid.Trace"
22
23 /**
24  * @brief A chunk of memory.
25  *
26  * TODO replace this by a dynar
27  */
28 typedef struct s_buffer {
29   char* data;
30   size_t size;
31   size_t capacity;
32 } s_buffer_t, *buffer_t;
33
34 static const char* value_tostring(lua_State* L, int index);
35 static const char* keyvalue_tostring(lua_State* L, int key_index, int value_index);
36 static void stack_dump(const char *msg, lua_State* L);
37 static int writer(lua_State* L, const void* source, size_t size, void* userdata);
38 static void move_value(lua_State* dst, lua_State* src, const char* name);
39 static int l_get_from_father(lua_State* L);
40 static lua_State *clone_lua_state(lua_State* L);
41 static m_task_t check_task(lua_State *L, int index);
42 static void register_c_functions(lua_State *L);
43
44 /* ********************************************************************************* */
45 /*                            helper functions                                       */
46 /* ********************************************************************************* */
47
48 /**
49  * @brief Returns a string representation of a value in the Lua stack.
50  *
51  * This function is for debugging purposes.
52  * It always returns the same pointer.
53  *
54  * @param L the Lua state
55  * @param index index in the stack
56  * @return a string representation of the value at this index
57  */
58 static const char* value_tostring(lua_State* L, int index) {
59
60   static char buff[64];
61
62   switch (lua_type(L, index)) {
63
64     case LUA_TNIL:
65       sprintf(buff, "nil");
66       break;
67
68     case LUA_TNUMBER:
69       sprintf(buff, "%.3f", lua_tonumber(L, index));
70       break;
71
72     case LUA_TBOOLEAN:
73       sprintf(buff, "%s", lua_toboolean(L, index) ? "true" : "false");
74       break;
75
76     case LUA_TSTRING:
77       snprintf(buff, 63, "'%s'", lua_tostring(L, index));
78       break;
79
80     case LUA_TFUNCTION:
81       if (lua_iscfunction(L, index)) {
82         sprintf(buff, "C-function");
83       }
84       else {
85         sprintf(buff, "function");
86       }
87       break;
88
89     case LUA_TTABLE:
90       sprintf(buff, "table(%d)", lua_objlen(L, index));
91       break;
92
93     case LUA_TLIGHTUSERDATA:
94     case LUA_TUSERDATA:
95       sprintf(buff, "userdata(%p)", lua_touserdata(L, index));
96       break;
97
98     case LUA_TTHREAD:
99       sprintf(buff, "thread");
100       break;
101   }
102   return buff;
103 }
104
105 /**
106  * @brief Returns a string representation of a key-value pair.
107  *
108  * This function is for debugging purposes.
109  * It always returns the same pointer.
110  *
111  * @param L the Lua state
112  * @param key_index index of the key
113  * @param value_index index of the value
114  * @return a string representation of the key-value pair
115  */
116 static const char* keyvalue_tostring(lua_State* L, int key_index, int value_index) {
117
118   static char buff[64];
119   /* value_tostring also always returns the same pointer */
120   int len = snprintf(buff, 63, "%s -> ", value_tostring(L, key_index));
121   snprintf(buff + len, 63 - len, "%s", value_tostring(L, value_index));
122   return buff;
123 }
124
125 /**
126  * @brief Dumps the Lua stack for debugging purposes.
127  * @param msg a message to print
128  * @param L a Lua state
129  */
130 static void stack_dump(const char* msg, lua_State* L)
131 {
132   char buff[2048];
133   char* p = buff;
134   int i;
135   int top = lua_gettop(L);
136
137 //  if (1) return;
138
139   fflush(stdout);
140
141   p[0] = '\0';
142   for (i = 1; i <= top; i++) {  /* repeat for each level */
143
144     p += sprintf(p, "%s", value_tostring(L, i));
145     p += sprintf(p, " ");       /* put a separator */
146   }
147   XBT_INFO("%s%s", msg, buff);
148 }
149
150 /**
151  * @brief Writes the specified data into a memory buffer.
152  *
153  * This function is a valid lua_Writer that writes into a memory buffer passed
154  * as userdata.
155  *
156  * @param L a lua state
157  * @param source some data
158  * @param sz number of bytes of data
159  * @param user_data the memory buffer to write
160  */
161 static int writer(lua_State* L, const void* source, size_t size, void* userdata) {
162
163   buffer_t buffer = (buffer_t) userdata;
164   while (buffer->capacity < buffer->size + size) {
165     buffer->capacity *= 2;
166     buffer->data = xbt_realloc(buffer->data, buffer->capacity);
167   }
168   memcpy(buffer->data + buffer->size, source, size);
169   buffer->size += size;
170
171   return 0;
172 }
173
174 /**
175  * @brief Pops a value from the stack of a source state and pushes it on the
176  * stack of another state.
177  *
178  * If the value is a table, its content is copied recursively. To avoid cycles,
179  * a table of previsously visited tables must be present at index 1 of dst.
180  * Its keys are pointers to visited tables in src and its values are the tables
181  * already built.
182  *
183  * TODO: add support of upvalues
184  *
185  * @param src the source state
186  * @param dst the destination state
187  * @param name a name describing the value
188  */
189 static void move_value(lua_State* dst, lua_State *src, const char* name) {
190
191   luaL_checkany(src, -1);                  /* check the value to copy */
192   luaL_checktype(dst, 1, LUA_TTABLE);      /* check the presence of a table of
193                                               previously visited tables */
194
195   XBT_DEBUG("Copying value %s", name);
196
197   stack_dump("src before copying a value (should be ... value): ", src);
198   stack_dump("dst before copying a value (should be visited ...): ", dst);
199
200   switch (lua_type(src, -1)) {
201
202     case LUA_TNIL:
203       lua_pushnil(dst);
204       break;
205
206     case LUA_TNUMBER:
207       lua_pushnumber(dst, lua_tonumber(src, -1));
208       break;
209
210     case LUA_TBOOLEAN:
211       lua_pushboolean(dst, lua_toboolean(src, -1));
212       break;
213
214     case LUA_TSTRING:
215       /* no worries about memory: lua_pushstring makes a copy */
216       lua_pushstring(dst, lua_tostring(src, -1));
217       break;
218
219     case LUA_TFUNCTION:
220       /* it's a function that does not exist yet in L2 */
221
222       if (lua_iscfunction(src, -1)) {
223         /* it's a C function: just copy the pointer */
224         XBT_DEBUG("Copying C function '%s'", name);
225         lua_CFunction f = lua_tocfunction(src, -1);
226         lua_pushcfunction(dst, f);
227       }
228       else {
229         /* it's a Lua function: dump it from src */
230         XBT_DEBUG("Dumping Lua function '%s'", name);
231
232         s_buffer_t buffer;
233         buffer.capacity = 64;
234         buffer.size = 0;
235         buffer.data = xbt_new(char, buffer.capacity);
236
237         /* copy the binary chunk from src into a buffer */
238         int error = lua_dump(src, writer, &buffer);
239         xbt_assert(!error, "Failed to dump function '%s' from the source state: error %d",
240               name, error);
241
242         /* load the chunk into dst */
243         error = luaL_loadbuffer(dst, buffer.data, buffer.size, name);
244         xbt_assert(!error, "Failed to load function '%s' from the source state: %s",
245             name, lua_tostring(dst, -1));
246         XBT_DEBUG("Function '%s' successfully dumped from source state.", name);
247       }
248       break;
249
250     case LUA_TTABLE:
251
252       /* see if this table was already visited */
253       lua_pushlightuserdata(dst, (void*) lua_topointer(src, -1));
254                                   /* dst: visited ... psrctable */
255       lua_gettable(dst, 1);
256                                   /* dst: visited ... table/nil */
257       if (lua_istable(dst, -1)) {
258         XBT_DEBUG("Nothing to do: table already visited");
259                                   /* dst: visited ... table */
260       }
261       else {
262         XBT_DEBUG("First visit of this table");
263                                   /* dst: visited ... nil */
264         lua_pop(dst, 1);
265                                   /* dst: visited ... */
266
267         /* first visit: create the new table in dst */
268         lua_newtable(dst);
269                                   /* dst: visited ... table */
270
271         /* mark the table as visited to avoid infinite recursion */
272         lua_pushlightuserdata(dst, (void*) lua_topointer(src, -1));
273                                   /* dst: visited ... table psrctable */
274         lua_pushvalue(dst, -2);
275                                   /* dst: visited ... table psrctable table */
276         lua_settable(dst, 1);
277                                   /* dst: visited ... table */
278         XBT_DEBUG("Table marked as visited");
279
280         stack_dump("dst after marking the table as visited (should be visited ... table): ", dst);
281
282         /* copy the metatable if any */
283         int has_meta_table = lua_getmetatable(src, -1);
284                                   /* src: ... table mt? */
285         if (has_meta_table) {
286           XBT_DEBUG("Copying metatable");
287                                   /* src: ... table mt */
288           move_value(dst, src, "metatable");
289                                   /* src: ... table
290                                      dst: visited ... table mt */
291           lua_setmetatable(dst, -2);
292                                   /* dst: visited ... table */
293         }
294         else {
295           XBT_DEBUG("No metatable");
296         }
297
298         stack_dump("src before traversing the table (should be ... table): ", src);
299         stack_dump("dst before traversing the table (should be visited ... table): ", dst);
300
301         /* traverse the table of src and copy each element */
302         lua_pushnil(src);
303                                   /* src: ... table nil */
304         while (lua_next(src, -2) != 0) {
305                                   /* src: ... table key value */
306
307           XBT_DEBUG("Copying table element %s", keyvalue_tostring(src, -2, -1));
308
309           stack_dump("src before copying table element (should be ... table key value): ", src);
310           stack_dump("dst before copying table element (should be visited ... table): ", dst);
311
312           /* copy the key */
313           lua_pushvalue(src, -2);
314                                   /* src: ... table key value key */
315           XBT_DEBUG("Copying the element key");
316           move_value(dst, src, value_tostring(src, -1));
317                                   /* src: ... table key value
318                                      dst: visited ... table key */
319           XBT_DEBUG("Copied the element key");
320
321           /* copy the value */
322           XBT_DEBUG("Copying the element value");
323           move_value(dst, src, value_tostring(src, -1));
324                                   /* src: ... table key
325                                      dst: visited ... table key value */
326           XBT_DEBUG("Copied the element value");
327
328           /* set the table element */
329           lua_settable(dst, -3);
330                                   /* dst: visited ... table */
331
332           /* the key stays on top of src for next iteration */
333           stack_dump("src before next iteration (should be ... table key): ", src);
334           stack_dump("dst before next iteration (should be visited ... table): ", dst);
335         }
336         XBT_DEBUG("Finished traversing the table");
337       }
338       break;
339
340     case LUA_TLIGHTUSERDATA:
341       lua_pushlightuserdata(dst, lua_touserdata(src, -1));
342       break;
343
344     case LUA_TUSERDATA:
345       XBT_WARN("Cannot copy a full userdata from the source state.");
346       lua_pushnil(dst);
347       break;
348
349     case LUA_TTHREAD:
350       XBT_WARN("Cannot copy a thread from the source state.");
351       lua_pushnil(dst);
352       break;
353   }
354
355   /* pop the value from src */
356   lua_pop(src, 1);
357
358   stack_dump("src after copying a value (should be ...): ", src);
359   stack_dump("dst after copying a value (should be visited ... value): ", dst);
360 }
361
362 /**
363  * @brief Copies a global value from the father state.
364  *
365  * The state L must have a father, i.e. it should have been created by
366  * clone_lua_state().
367  * This function is meant to be an __index metamethod.
368  * Consequently, it assumes that the stack has two elements:
369  * a table (usually the environment of L) and the string key of a value
370  * that does not exist yet in this table. It copies the corresponding global
371  * value from the father state and pushes it on the stack of L.
372  * If the global value does not exist in the father state either, nil is
373  * pushed.
374  *
375  * TODO: make this function thread safe. If the simulation runs in parallel,
376  * several simulated processes may trigger this __index metamethod at the same
377  * time and get globals from maestro.
378  *
379  * @param L the current state
380  * @return number of return values pushed (always 1)
381  */
382 static int l_get_from_father(lua_State *L) {
383
384   /* retrieve the father */
385   lua_getfield(L, LUA_REGISTRYINDEX, "simgrid.father_state");
386   lua_State* father = lua_touserdata(L, -1);
387   xbt_assert(father != NULL, "This Lua state has no father");
388   lua_pop(L, 1);
389
390   /* get the global from the father */
391   const char* key = luaL_checkstring(L, 2);    /* L:      table key */
392   lua_getglobal(father, key);                  /* father: ... value */
393   XBT_DEBUG("__index of '%s' begins", key);
394
395   /* push the value onto the stack of L */
396   lua_newtable(L);                             /* L:      table key visited */
397   lua_insert(L, 1);                            /* L:      visited table key */
398   move_value(L, father, key);                  /* father: ...
399                                                   L:      visited table key value */
400   lua_remove(L, 1);                            /* L:      table key value */
401
402   /* prepare the return value of __index */
403   lua_pushvalue(L, -1);                        /* L:      table key value value */
404   lua_insert(L, 1);                            /* L:      value table key value */
405
406   /* save the copied value in the table for subsequent accesses */
407   lua_settable(L, -3);                         /* L:      value table */
408   lua_remove(L, 2);                            /* L:      value */
409
410   XBT_DEBUG("__index of '%s' returns %s", key, value_tostring(L, -1));
411
412   return 1;
413 }
414
415 /**
416  * @brief Creates a new Lua state and get its environment from an existing state.
417  *
418  * The state created is independent from the existing one and has its own
419  * copies of global variables and functions.
420  * However, the global variables and functions are not copied right now from
421  * the original state; they are copied only the first time they are accessed.
422  * This behavior saves time and memory, and is okay for Simgrid's needs.
423  *
424  * @param father an existing state
425  * @return the state created
426  */
427 static lua_State* clone_lua_state(lua_State *father) {
428
429   /* create the new state */
430   lua_State *L = luaL_newstate();
431
432   /* set its environment:
433    * - create a table newenv
434    * - create a metatable mt
435    * - set mt.__index = a function that copies the global from the father state
436    * - set mt as the metatable of newenv
437    * - set newenv as the environment of the new state
438    */
439   lua_pushthread(L);                        /* thread */
440   lua_newtable(L);                          /* thread newenv */
441   lua_newtable(L);                          /* thread newenv mt */
442   lua_pushcfunction(L, l_get_from_father);  /* thread newenv mt f */
443   lua_setfield(L, -2, "__index");           /* thread newenv mt */
444   lua_setmetatable(L, -2);                  /* thread newenv */
445   lua_setfenv(L, -2);                       /* thread */
446   lua_pop(L, 1);                            /* -- */
447
448   /* open the standard libs (theoretically, this is not necessary) */
449   luaL_openlibs(L);
450
451   /* put a pointer to the father */
452   lua_pushlightuserdata(L, father);
453   lua_setfield(L, LUA_REGISTRYINDEX, "simgrid.father_state");
454
455   XBT_DEBUG("New state created");
456
457   return L;
458 }
459
460 /**
461  * @brief Ensures that a userdata on the stack is a task
462  * and returns the pointer inside the userdata.
463  * @param L a Lua state
464  * @param index an index in the Lua stack
465  * @return the task at this index
466  */
467 static m_task_t checkTask(lua_State * L, int index)
468 {
469   m_task_t *pi, tk;
470   luaL_checktype(L, index, LUA_TTABLE);
471   lua_getfield(L, index, "__simgrid_task");
472   pi = (m_task_t *) luaL_checkudata(L, -1, TASK_MODULE_NAME);
473   if (pi == NULL)
474     luaL_typerror(L, index, TASK_MODULE_NAME);
475   tk = *pi;
476   if (!tk)
477     luaL_error(L, "null Task");
478   lua_pop(L, 1);
479   return tk;
480 }
481
482 /* ********************************************************************************* */
483 /*                           wrapper functions                                       */
484 /* ********************************************************************************* */
485
486 /**
487  * A task is either something to compute somewhere, or something to exchange between two hosts (or both).
488  * It is defined by a computing amount and a message size.
489  *
490  */
491
492 /* *              * *
493  * * Constructors * *
494  * *              * */
495
496 /**
497  * @brief Constructs a new task with the specified processing amount and amount
498  * of data needed.
499  *
500  * @param name  Task's name
501  *
502  * @param computeDuration       A value of the processing amount (in flop) needed to process the task.
503  *                              If 0, then it cannot be executed with the execute() method.
504  *                              This value has to be >= 0.
505  *
506  * @param messageSize           A value of amount of data (in bytes) needed to transfert this task.
507  *                              If 0, then it cannot be transfered with the get() and put() methods.
508  *                              This value has to be >= 0.
509  */
510 static int Task_new(lua_State * L)
511 {
512   XBT_DEBUG("Task new...");
513   const char *name = luaL_checkstring(L, 1);
514   int comp_size = luaL_checkint(L, 2);
515   int msg_size = luaL_checkint(L, 3);
516   m_task_t msg_task = MSG_task_create(name, comp_size, msg_size, NULL);
517   lua_newtable(L);              /* create a table, put the userdata on top of it */
518   m_task_t *lua_task = (m_task_t *) lua_newuserdata(L, sizeof(m_task_t));
519   *lua_task = msg_task;
520   luaL_getmetatable(L, TASK_MODULE_NAME);
521   lua_setmetatable(L, -2);
522   lua_setfield(L, -2, "__simgrid_task");        /* put the userdata as field of the table */
523   /* remove the args from the stack */
524   lua_remove(L, 1);
525   lua_remove(L, 1);
526   lua_remove(L, 1);
527   return 1;
528 }
529
530 static int Task_get_name(lua_State * L)
531 {
532   m_task_t tk = checkTask(L, -1);
533   lua_pushstring(L, MSG_task_get_name(tk));
534   return 1;
535 }
536
537 static int Task_computation_duration(lua_State * L)
538 {
539   m_task_t tk = checkTask(L, -1);
540   lua_pushnumber(L, MSG_task_get_compute_duration(tk));
541   return 1;
542 }
543
544 static int Task_execute(lua_State * L)
545 {
546   m_task_t tk = checkTask(L, -1);
547   int res = MSG_task_execute(tk);
548   lua_pushnumber(L, res);
549   return 1;
550 }
551
552 static int Task_destroy(lua_State * L)
553 {
554   m_task_t tk = checkTask(L, -1);
555   int res = MSG_task_destroy(tk);
556   lua_pushnumber(L, res);
557   return 1;
558 }
559
560 static int Task_send(lua_State * L)
561 {
562   //stackDump("send ",L);
563   m_task_t tk = checkTask(L, 1);
564   const char *mailbox = luaL_checkstring(L, 2);
565   lua_pop(L, 1);                // remove the string so that the task is on top of it
566   MSG_task_set_data(tk, L);     // Copy my stack into the task, so that the receiver can copy the lua task directly
567   MSG_error_t res = MSG_task_send(tk, mailbox);
568   while (MSG_task_get_data(tk) != NULL) // Don't mess up with my stack: the receiver didn't copy the data yet
569     MSG_process_sleep(0);       // yield
570
571   if (res != MSG_OK)
572     switch (res) {
573     case MSG_TIMEOUT:
574       XBT_DEBUG("MSG_task_send failed : Timeout");
575       break;
576     case MSG_TRANSFER_FAILURE:
577       XBT_DEBUG("MSG_task_send failed : Transfer Failure");
578       break;
579     case MSG_HOST_FAILURE:
580       XBT_DEBUG("MSG_task_send failed : Host Failure ");
581       break;
582     default:
583       XBT_ERROR
584           ("MSG_task_send failed : Unexpected error , please report this bug");
585       break;
586     }
587   return 0;
588 }
589
590 static int Task_recv_with_timeout(lua_State *L)
591 {
592   m_task_t tk = NULL;
593   const char *mailbox = luaL_checkstring(L, -2);
594   int timeout = luaL_checknumber(L, -1);
595   MSG_error_t res = MSG_task_receive_with_timeout(&tk, mailbox, timeout);
596
597   if (res == MSG_OK) {
598     lua_State *sender_stack = MSG_task_get_data(tk);
599     lua_xmove(sender_stack, L, 1);        // copy the data directly from sender's stack
600     MSG_task_set_data(tk, NULL);
601   }
602   else {
603     switch (res) {
604     case MSG_TIMEOUT:
605       XBT_DEBUG("MSG_task_receive failed : Timeout");
606       break;
607     case MSG_TRANSFER_FAILURE:
608       XBT_DEBUG("MSG_task_receive failed : Transfer Failure");
609       break;
610     case MSG_HOST_FAILURE:
611       XBT_DEBUG("MSG_task_receive failed : Host Failure ");
612       break;
613     default:
614       XBT_ERROR("MSG_task_receive failed : Unexpected error , please report this bug");
615       break;
616     }
617     lua_pushnil(L);
618   }
619   return 1;
620 }
621
622 static int Task_recv(lua_State * L)
623 {
624   lua_pushnumber(L, -1.0);
625   return Task_recv_with_timeout(L);
626 }
627
628 static const luaL_reg Task_methods[] = {
629   {"new", Task_new},
630   {"name", Task_get_name},
631   {"computation_duration", Task_computation_duration},
632   {"execute", Task_execute},
633   {"destroy", Task_destroy},
634   {"send", Task_send},
635   {"recv", Task_recv},
636   {"recv_timeout", Task_recv_with_timeout},
637   {NULL, NULL}
638 };
639
640 static int Task_gc(lua_State * L)
641 {
642   m_task_t tk = checkTask(L, -1);
643   if (tk)
644     MSG_task_destroy(tk);
645   return 0;
646 }
647
648 static int Task_tostring(lua_State * L)
649 {
650   lua_pushfstring(L, "Task :%p", lua_touserdata(L, 1));
651   return 1;
652 }
653
654 static const luaL_reg Task_meta[] = {
655   {"__gc", Task_gc},
656   {"__tostring", Task_tostring},
657   {NULL, NULL}
658 };
659
660 /**
661  * Host
662  */
663 static m_host_t checkHost(lua_State * L, int index)
664 {
665   m_host_t *pi, ht;
666   luaL_checktype(L, index, LUA_TTABLE);
667   lua_getfield(L, index, "__simgrid_host");
668   pi = (m_host_t *) luaL_checkudata(L, -1, HOST_MODULE_NAME);
669   if (pi == NULL)
670     luaL_typerror(L, index, HOST_MODULE_NAME);
671   ht = *pi;
672   if (!ht)
673     luaL_error(L, "null Host");
674   lua_pop(L, 1);
675   return ht;
676 }
677
678 static int Host_get_by_name(lua_State * L)
679 {
680   const char *name = luaL_checkstring(L, 1);
681   XBT_DEBUG("Getting Host from name...");
682   m_host_t msg_host = MSG_get_host_by_name(name);
683   if (!msg_host) {
684     luaL_error(L, "null Host : MSG_get_host_by_name failed");
685   }
686   lua_newtable(L);              /* create a table, put the userdata on top of it */
687   m_host_t *lua_host = (m_host_t *) lua_newuserdata(L, sizeof(m_host_t));
688   *lua_host = msg_host;
689   luaL_getmetatable(L, HOST_MODULE_NAME);
690   lua_setmetatable(L, -2);
691   lua_setfield(L, -2, "__simgrid_host");        /* put the userdata as field of the table */
692   /* remove the args from the stack */
693   lua_remove(L, 1);
694   return 1;
695 }
696
697 static int Host_get_name(lua_State * L)
698 {
699   m_host_t ht = checkHost(L, -1);
700   lua_pushstring(L, MSG_host_get_name(ht));
701   return 1;
702 }
703
704 static int Host_number(lua_State * L)
705 {
706   lua_pushnumber(L, MSG_get_host_number());
707   return 1;
708 }
709
710 static int Host_at(lua_State * L)
711 {
712   int index = luaL_checkinteger(L, 1);
713   m_host_t host = MSG_get_host_table()[index - 1];      // lua indexing start by 1 (lua[1] <=> C[0])
714   lua_newtable(L);              /* create a table, put the userdata on top of it */
715   m_host_t *lua_host = (m_host_t *) lua_newuserdata(L, sizeof(m_host_t));
716   *lua_host = host;
717   luaL_getmetatable(L, HOST_MODULE_NAME);
718   lua_setmetatable(L, -2);
719   lua_setfield(L, -2, "__simgrid_host");        /* put the userdata as field of the table */
720   return 1;
721
722 }
723
724 static int Host_self(lua_State * L)
725 {
726   m_host_t host = MSG_host_self();
727   lua_newtable(L);
728   m_host_t *lua_host =(m_host_t *)lua_newuserdata(L,sizeof(m_host_t));
729   *lua_host = host;
730   luaL_getmetatable(L, HOST_MODULE_NAME);
731   lua_setmetatable(L, -2);
732   lua_setfield(L, -2, "__simgrid_host");
733   return 1;
734 }
735
736 static int Host_get_property_value(lua_State * L)
737 {
738   m_host_t ht = checkHost(L, -2);
739   const char *prop = luaL_checkstring(L, -1);
740   lua_pushstring(L,MSG_host_get_property_value(ht,prop));
741   return 1;
742 }
743
744 static int Host_sleep(lua_State *L)
745 {
746   int time = luaL_checknumber(L, -1);
747   MSG_process_sleep(time);
748   return 1;
749 }
750
751 static int Host_destroy(lua_State *L)
752 {
753   m_host_t ht = checkHost(L, -1);
754   __MSG_host_destroy(ht);
755   return 1;
756 }
757
758 /* ********************************************************************************* */
759 /*                           lua_stub_generator functions                            */
760 /* ********************************************************************************* */
761
762 xbt_dict_t process_function_set;
763 xbt_dynar_t process_list;
764 xbt_dict_t machine_set;
765 static s_process_t process;
766
767 void s_process_free(void *process)
768 {
769   s_process_t *p = (s_process_t *) process;
770   int i;
771   for (i = 0; i < p->argc; i++)
772     free(p->argv[i]);
773   free(p->argv);
774   free(p->host);
775 }
776
777 static int gras_add_process_function(lua_State * L)
778 {
779   const char *arg;
780   const char *process_host = luaL_checkstring(L, 1);
781   const char *process_function = luaL_checkstring(L, 2);
782
783   if (xbt_dict_is_empty(machine_set)
784       || xbt_dict_is_empty(process_function_set)
785       || xbt_dynar_is_empty(process_list)) {
786     process_function_set = xbt_dict_new();
787     process_list = xbt_dynar_new(sizeof(s_process_t), s_process_free);
788     machine_set = xbt_dict_new();
789   }
790
791   xbt_dict_set(machine_set, process_host, NULL, NULL);
792   xbt_dict_set(process_function_set, process_function, NULL, NULL);
793
794   process.argc = 1;
795   process.argv = xbt_new(char *, 1);
796   process.argv[0] = xbt_strdup(process_function);
797   process.host = strdup(process_host);
798
799   lua_pushnil(L);
800   while (lua_next(L, 3) != 0) {
801     arg = lua_tostring(L, -1);
802     process.argc++;
803     process.argv =
804         xbt_realloc(process.argv, (process.argc) * sizeof(char *));
805     process.argv[(process.argc) - 1] = xbt_strdup(arg);
806
807     XBT_DEBUG("index = %f , arg = %s \n", lua_tonumber(L, -2),
808            lua_tostring(L, -1));
809     lua_pop(L, 1);
810   }
811   lua_pop(L, 1);
812   //add to the process list
813   xbt_dynar_push(process_list, &process);
814   return 0;
815 }
816
817
818 static int gras_generate(lua_State * L)
819 {
820   const char *project_name = luaL_checkstring(L, 1);
821   generate_sim(project_name);
822   generate_rl(project_name);
823   generate_makefile_local(project_name);
824   return 0;
825 }
826
827 /***********************************
828  *      Tracing
829  **********************************/
830 static int trace_start(lua_State *L)
831 {
832 #ifdef HAVE_TRACING
833   TRACE_start();
834 #endif
835   return 1;
836 }
837
838 static int trace_category(lua_State * L)
839 {
840 #ifdef HAVE_TRACING
841   TRACE_category(luaL_checkstring(L, 1));
842 #endif
843   return 1;
844 }
845
846 static int trace_set_task_category(lua_State *L)
847 {
848 #ifdef HAVE_TRACING
849   TRACE_msg_set_task_category(checkTask(L, -2), luaL_checkstring(L, -1));
850 #endif
851   return 1;
852 }
853
854 static int trace_end(lua_State *L)
855 {
856 #ifdef HAVE_TRACING
857   TRACE_end();
858 #endif
859   return 1;
860 }
861
862 // *********** Register Methods ******************************************* //
863
864 /*
865  * Host Methods
866  */
867 static const luaL_reg Host_methods[] = {
868   {"getByName", Host_get_by_name},
869   {"name", Host_get_name},
870   {"number", Host_number},
871   {"at", Host_at},
872   {"self", Host_self},
873   {"getPropValue", Host_get_property_value},
874   {"sleep", Host_sleep},
875   {"destroy", Host_destroy},
876   // Bypass XML Methods
877   {"setFunction", console_set_function},
878   {"setProperty", console_host_set_property},
879   {NULL, NULL}
880 };
881
882 static int Host_gc(lua_State * L)
883 {
884   m_host_t ht = checkHost(L, -1);
885   if (ht)
886     ht = NULL;
887   return 0;
888 }
889
890 static int Host_tostring(lua_State * L)
891 {
892   lua_pushfstring(L, "Host :%p", lua_touserdata(L, 1));
893   return 1;
894 }
895
896 static const luaL_reg Host_meta[] = {
897   {"__gc", Host_gc},
898   {"__tostring", Host_tostring},
899   {0, 0}
900 };
901
902 /*
903  * AS Methods
904  */
905 static const luaL_reg AS_methods[] = {
906   {"new", console_add_AS},
907   {"addHost", console_add_host},
908   {"addLink", console_add_link},
909   {"addRoute", console_add_route},
910   {NULL, NULL}
911 };
912
913 /**
914  * Tracing Functions
915  */
916 static const luaL_reg Trace_methods[] = {
917   {"start", trace_start},
918   {"category", trace_category},
919   {"setTaskCategory", trace_set_task_category},
920   {"finish", trace_end},
921   {NULL, NULL}
922 };
923
924 /*
925  * Environment related
926  */
927
928 /**
929  * @brief Runs a Lua function as a new simulated process.
930  * @param argc number of arguments of the function
931  * @param argv name of the Lua function and array of its arguments
932  * @return result of the function
933  */
934 static int run_lua_code(int argc, char **argv)
935 {
936   XBT_DEBUG("Run lua code %s", argv[0]);
937
938   lua_State *L = clone_lua_state(lua_maestro_state);
939   int res = 1;
940
941   /* start the function */
942   lua_getglobal(L, argv[0]);
943   xbt_assert(lua_isfunction(L, -1),
944               "The lua function %s does not seem to exist", argv[0]);
945
946   /* push arguments onto the stack */
947   int i;
948   for (i = 1; i < argc; i++)
949     lua_pushstring(L, argv[i]);
950
951   /* call the function */
952   int err;
953   err = lua_pcall(L, argc - 1, 1, 0);
954   xbt_assert(err == 0, "error running function `%s': %s", argv[0],
955               lua_tostring(L, -1));
956
957   /* retrieve result */
958   if (lua_isnumber(L, -1)) {
959     res = lua_tonumber(L, -1);
960     lua_pop(L, 1);              /* pop returned value */
961   }
962
963   XBT_DEBUG("Execution of Lua code %s is over", (argv ? argv[0] : "(null)"));
964
965   return res;
966 }
967
968 static int launch_application(lua_State * L)
969 {
970   const char *file = luaL_checkstring(L, 1);
971   MSG_function_register_default(run_lua_code);
972   MSG_launch_application(file);
973   return 0;
974 }
975
976 static int create_environment(lua_State * L)
977 {
978   const char *file = luaL_checkstring(L, 1);
979   XBT_DEBUG("Loading environment file %s", file);
980   MSG_create_environment(file);
981   return 0;
982 }
983
984 static int debug(lua_State * L)
985 {
986   const char *str = luaL_checkstring(L, 1);
987   XBT_DEBUG("%s", str);
988   return 0;
989 }
990
991 static int info(lua_State * L)
992 {
993   const char *str = luaL_checkstring(L, 1);
994   XBT_INFO("%s", str);
995   return 0;
996 }
997
998 static int run(lua_State * L)
999 {
1000   MSG_main();
1001   return 0;
1002 }
1003
1004 static int clean(lua_State * L)
1005 {
1006   MSG_clean();
1007   return 0;
1008 }
1009
1010 /*
1011  * Bypass XML Parser (lua console)
1012  */
1013
1014 /*
1015  * Register platform for MSG
1016  */
1017 static int msg_register_platform(lua_State * L)
1018 {
1019   /* Tell Simgrid we dont wanna use its parser */
1020   surf_parse = console_parse_platform;
1021   surf_parse_reset_callbacks();
1022   surf_config_models_setup(NULL);
1023   MSG_create_environment(NULL);
1024   return 0;
1025 }
1026
1027 /*
1028  * Register platform for Simdag
1029  */
1030
1031 static int sd_register_platform(lua_State * L)
1032 {
1033   surf_parse = console_parse_platform_wsL07;
1034   surf_parse_reset_callbacks();
1035   surf_config_models_setup(NULL);
1036   SD_create_environment(NULL);
1037   return 0;
1038 }
1039
1040 /*
1041  * Register platform for gras
1042  */
1043 static int gras_register_platform(lua_State * L)
1044 {
1045   /* Tell Simgrid we dont wanna use surf parser */
1046   surf_parse = console_parse_platform;
1047   surf_parse_reset_callbacks();
1048   surf_config_models_setup(NULL);
1049   gras_create_environment(NULL);
1050   return 0;
1051 }
1052
1053 /**
1054  * Register applicaiton for MSG
1055  */
1056 static int msg_register_application(lua_State * L)
1057 {
1058   MSG_function_register_default(run_lua_code);
1059   surf_parse = console_parse_application;
1060   MSG_launch_application(NULL);
1061   return 0;
1062 }
1063
1064 /*
1065  * Register application for gras
1066  */
1067 static int gras_register_application(lua_State * L)
1068 {
1069   gras_function_register_default(run_lua_code);
1070   surf_parse = console_parse_application;
1071   gras_launch_application(NULL);
1072   return 0;
1073 }
1074
1075 static const luaL_Reg simgrid_funcs[] = {
1076   {"create_environment", create_environment},
1077   {"launch_application", launch_application},
1078   {"debug", debug},
1079   {"info", info},
1080   {"run", run},
1081   {"clean", clean},
1082   /* short names */
1083   {"platform", create_environment},
1084   {"application", launch_application},
1085   /* methods to bypass XML parser */
1086   {"msg_register_platform", msg_register_platform},
1087   {"sd_register_platform", sd_register_platform},
1088   {"msg_register_application", msg_register_application},
1089   {"gras_register_platform", gras_register_platform},
1090   {"gras_register_application", gras_register_application},
1091   /* gras sub generator method */
1092   {"gras_set_process_function", gras_add_process_function},
1093   {"gras_generate", gras_generate},
1094   {NULL, NULL}
1095 };
1096
1097 /* ********************************************************************************* */
1098 /*                       module management functions                                 */
1099 /* ********************************************************************************* */
1100
1101 #define LUA_MAX_ARGS_COUNT 10   /* maximum amount of arguments we can get from lua on command line */
1102
1103 int luaopen_simgrid(lua_State *L);     // Fuck gcc: we don't need that prototype
1104
1105 /**
1106  * This function is called automatically by the Lua interpreter when some Lua code requires
1107  * the "simgrid" module.
1108  * @param L the Lua state
1109  */
1110 int luaopen_simgrid(lua_State *L)
1111 {
1112   XBT_DEBUG("luaopen_simgrid *****");
1113
1114   /* Get the command line arguments from the lua interpreter */
1115   char **argv = malloc(sizeof(char *) * LUA_MAX_ARGS_COUNT);
1116   int argc = 1;
1117   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? */
1118
1119   lua_getglobal(L, "arg");
1120   /* if arg is a null value, it means we use lua only as a script to init platform
1121    * else it should be a table and then take arg in consideration
1122    */
1123   if (lua_istable(L, -1)) {
1124     int done = 0;
1125     while (!done) {
1126       argc++;
1127       lua_pushinteger(L, argc - 2);
1128       lua_gettable(L, -2);
1129       if (lua_isnil(L, -1)) {
1130         done = 1;
1131       } else {
1132         xbt_assert(lua_isstring(L, -1),
1133                     "argv[%d] got from lua is no string", argc - 1);
1134         xbt_assert(argc < LUA_MAX_ARGS_COUNT,
1135                     "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",
1136                     __FILE__, LUA_MAX_ARGS_COUNT - 1);
1137         argv[argc - 1] = (char *) luaL_checkstring(L, -1);
1138         lua_pop(L, 1);
1139         XBT_DEBUG("Got command line argument %s from lua", argv[argc - 1]);
1140       }
1141     }
1142     argv[argc--] = NULL;
1143
1144     /* Initialize the MSG core */
1145     MSG_global_init(&argc, argv);
1146     XBT_DEBUG("Still %d arguments on command line", argc); // FIXME: update the lua's arg table to reflect the changes from SimGrid
1147   }
1148
1149   /* Keep the context mechanism informed of our lua world today */
1150   lua_maestro_state = L;
1151
1152   register_c_functions(L);
1153
1154   return 1;
1155 }
1156
1157 /**
1158  * Makes the appropriate Simgrid functions available to the Lua world.
1159  * @param L a Lua world
1160  */
1161 void register_c_functions(lua_State *L) {
1162
1163   /* register the core C functions to lua */
1164   luaL_register(L, "simgrid", simgrid_funcs);
1165
1166   /* register the task methods to lua */
1167   luaL_openlib(L, TASK_MODULE_NAME, Task_methods, 0);   // create methods table, add it to the globals
1168   luaL_newmetatable(L, TASK_MODULE_NAME);       // create metatable for Task, add it to the Lua registry
1169   luaL_openlib(L, 0, Task_meta, 0);     // fill metatable
1170   lua_pushliteral(L, "__index");
1171   lua_pushvalue(L, -3);         // dup methods table
1172   lua_rawset(L, -3);            // matatable.__index = methods
1173   lua_pushliteral(L, "__metatable");
1174   lua_pushvalue(L, -3);         // dup methods table
1175   lua_rawset(L, -3);            // hide metatable:metatable.__metatable = methods
1176   lua_pop(L, 1);                // drop metatable
1177
1178   /* register the hosts methods to lua */
1179   luaL_openlib(L, HOST_MODULE_NAME, Host_methods, 0);
1180   luaL_newmetatable(L, HOST_MODULE_NAME);
1181   luaL_openlib(L, 0, Host_meta, 0);
1182   lua_pushliteral(L, "__index");
1183   lua_pushvalue(L, -3);
1184   lua_rawset(L, -3);
1185   lua_pushliteral(L, "__metatable");
1186   lua_pushvalue(L, -3);
1187   lua_rawset(L, -3);
1188   lua_pop(L, 1);
1189
1190   /* register the links methods to lua */
1191   luaL_openlib(L, AS_MODULE_NAME, AS_methods, 0);
1192   luaL_newmetatable(L, AS_MODULE_NAME);
1193   lua_pop(L, 1);
1194
1195   /* register the Tracing functions to lua */
1196   luaL_openlib(L, TRACE_MODULE_NAME, Trace_methods, 0);
1197   luaL_newmetatable(L, TRACE_MODULE_NAME);
1198   lua_pop(L, 1);
1199 }