Logo AND Algorithmique Numérique Distribuée

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