Logo AND Algorithmique Numérique Distribuée

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