Logo AND Algorithmique Numérique Distribuée

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