1 /* SimGrid Lua bindings */
3 /* Copyright (c) 2010. The SimGrid Team.
4 * All rights reserved. */
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"
10 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(lua, bindings, "Lua Bindings");
12 lua_State *simgrid_lua_state;
14 #define TASK_MODULE_NAME "simgrid.Task"
15 #define HOST_MODULE_NAME "simgrid.Host"
16 // Surf ( bypass XML )
17 #define LINK_MODULE_NAME "simgrid.Link"
18 #define ROUTE_MODULE_NAME "simgrid.Route"
19 #define AS_MODULE_NAME "simgrid.AS"
20 #define TRACE_MODULE_NAME "simgrid.Trace"
22 /* ********************************************************************************* */
23 /* helper functions */
24 /* ********************************************************************************* */
25 static void stackDump(const char *msg, lua_State * L)
30 int top = lua_gettop(L);
33 p += sprintf(p, "STACK(top=%d): ", top);
35 for (i = 1; i <= top; i++) { /* repeat for each level */
36 int t = lua_type(L, i);
39 case LUA_TSTRING: /* strings */
40 p += sprintf(p, "`%s'", lua_tostring(L, i));
43 case LUA_TBOOLEAN: /* booleans */
44 p += sprintf(p, lua_toboolean(L, i) ? "true" : "false");
47 case LUA_TNUMBER: /* numbers */
48 p += sprintf(p, "%g", lua_tonumber(L, i));
52 p += sprintf(p, "Table");
55 default: /* other values */
56 p += sprintf(p, "???");
57 /* if ((ptr = luaL_checkudata(L,i,TASK_MODULE_NAME))) {
60 p+=printf(p,"%s", lua_typename(L, t));
65 p += sprintf(p, " "); /* put a separator */
67 XBT_INFO("%s%s", msg, buff);
70 /** @brief ensures that a userdata on the stack is a task and returns the pointer inside the userdata */
71 static m_task_t checkTask(lua_State * L, int index)
74 luaL_checktype(L, index, LUA_TTABLE);
75 lua_getfield(L, index, "__simgrid_task");
76 pi = (m_task_t *) luaL_checkudata(L, -1, TASK_MODULE_NAME);
78 luaL_typerror(L, index, TASK_MODULE_NAME);
81 luaL_error(L, "null Task");
86 /* ********************************************************************************* */
87 /* wrapper functions */
88 /* ********************************************************************************* */
91 * A task is either something to compute somewhere, or something to exchange between two hosts (or both).
92 * It is defined by a computing amount and a message size.
100 * Construct an new task with the specified processing amount and amount
103 * @param name Task's name
105 * @param computeDuration A value of the processing amount (in flop) needed to process the task.
106 * If 0, then it cannot be executed with the execute() method.
107 * This value has to be >= 0.
109 * @param messageSize A value of amount of data (in bytes) needed to transfert this task.
110 * If 0, then it cannot be transfered with the get() and put() methods.
111 * This value has to be >= 0.
113 static int Task_new(lua_State * L)
115 XBT_DEBUG("Task new...");
116 const char *name = luaL_checkstring(L, 1);
117 int comp_size = luaL_checkint(L, 2);
118 int msg_size = luaL_checkint(L, 3);
119 m_task_t msg_task = MSG_task_create(name, comp_size, msg_size, NULL);
120 lua_newtable(L); /* create a table, put the userdata on top of it */
121 m_task_t *lua_task = (m_task_t *) lua_newuserdata(L, sizeof(m_task_t));
122 *lua_task = msg_task;
123 luaL_getmetatable(L, TASK_MODULE_NAME);
124 lua_setmetatable(L, -2);
125 lua_setfield(L, -2, "__simgrid_task"); /* put the userdata as field of the table */
126 /* remove the args from the stack */
133 static int Task_get_name(lua_State * L)
135 m_task_t tk = checkTask(L, -1);
136 lua_pushstring(L, MSG_task_get_name(tk));
140 static int Task_computation_duration(lua_State * L)
142 m_task_t tk = checkTask(L, -1);
143 lua_pushnumber(L, MSG_task_get_compute_duration(tk));
147 static int Task_execute(lua_State * L)
149 m_task_t tk = checkTask(L, -1);
150 int res = MSG_task_execute(tk);
151 lua_pushnumber(L, res);
155 static int Task_destroy(lua_State * L)
157 m_task_t tk = checkTask(L, -1);
158 int res = MSG_task_destroy(tk);
159 lua_pushnumber(L, res);
163 static int Task_send(lua_State * L)
165 //stackDump("send ",L);
166 m_task_t tk = checkTask(L, 1);
167 const char *mailbox = luaL_checkstring(L, 2);
168 lua_pop(L, 1); // remove the string so that the task is on top of it
169 MSG_task_set_data(tk, L); // Copy my stack into the task, so that the receiver can copy the lua task directly
170 MSG_error_t res = MSG_task_send(tk, mailbox);
171 while (MSG_task_get_data(tk) != NULL) // Don't mess up with my stack: the receiver didn't copy the data yet
172 MSG_process_sleep(0); // yield
177 XBT_ERROR("MSG_task_send failed : Timeout");
179 case MSG_TRANSFER_FAILURE:
180 XBT_ERROR("MSG_task_send failed : Transfer Failure");
182 case MSG_HOST_FAILURE:
183 XBT_ERROR("MSG_task_send failed : Host Failure ");
187 ("MSG_task_send failed : Unexpected error , please report this bug");
193 static int Task_recv(lua_State * L)
196 const char *mailbox = luaL_checkstring(L, -1);
197 MSG_error_t res = MSG_task_receive(&tk, mailbox);
199 lua_State *sender_stack = MSG_task_get_data(tk);
200 lua_xmove(sender_stack, L, 1); // copy the data directly from sender's stack
201 MSG_task_set_data(tk, NULL);
206 XBT_ERROR("MSG_task_receive failed : Timeout");
208 case MSG_TRANSFER_FAILURE:
209 XBT_ERROR("MSG_task_receive failed : Transfer Failure");
211 case MSG_HOST_FAILURE:
212 XBT_ERROR("MSG_task_receive failed : Host Failure ");
216 ("MSG_task_receive failed : Unexpected error , please report this bug");
223 static int Task_recv_with_timeout(lua_State * L)
226 const char *mailbox = luaL_checkstring(L, -2);
227 int timeout = luaL_checknumber(L, -1);
228 MSG_error_t res = MSG_task_receive_with_timeout(&tk, mailbox, timeout);
230 lua_State *sender_stack = MSG_task_get_data(tk);
231 lua_xmove(sender_stack, L, 1); // copy the data directly from sender's stack
232 MSG_task_set_data(tk, NULL);
237 XBT_ERROR("MSG_task_receive failed : Timeout");
239 case MSG_TRANSFER_FAILURE:
240 XBT_ERROR("MSG_task_receive failed : Transfer Failure");
242 case MSG_HOST_FAILURE:
243 XBT_ERROR("MSG_task_receive failed : Host Failure ");
247 ("MSG_task_receive failed : Unexpected error , please report this bug");
255 * Static Binding for the Splay methods : event.sleep :
256 * it use MSG_task_irecv with MSG_comm_wait
258 static int Task_splay_irecv(lua_State *L)
260 m_task_t task = NULL;
261 msg_comm_t comm = NULL; //current communication to receive
262 const char *mailbox = luaL_checkstring(L, -2);
263 double timeout = luaL_checknumber(L, -1);
264 comm = MSG_task_irecv(&task, mailbox);
265 MSG_comm_wait(comm, timeout);
266 if (MSG_comm_get_status(comm) == MSG_OK)
268 lua_State *sender_stack = MSG_task_get_data(task);
269 lua_xmove(sender_stack, L, 1); // copy the data directly from sender's stack
270 MSG_task_set_data(task, NULL);
271 MSG_comm_destroy(comm);
277 static int Task_splay_isend(lua_State *L)
279 m_task_t tk = checkTask(L, 1);
280 const char *mailbox = luaL_checkstring(L, 2);
281 lua_pop(L, 1); // remove the string so that the task is on top of it
282 MSG_task_set_data(tk, L); // Copy my stack into the task, so that the receiver can copy the lua task directly
283 MSG_task_isend(tk, mailbox);
288 static const luaL_reg Task_methods[] = {
290 {"name", Task_get_name},
291 {"computation_duration", Task_computation_duration},
292 {"execute", Task_execute},
293 {"destroy", Task_destroy},
296 {"recv_timeout",Task_recv_with_timeout},
297 {"splay_recv",Task_splay_irecv},
298 {"iSend",Task_splay_isend},
302 static int Task_gc(lua_State * L)
304 m_task_t tk = checkTask(L, -1);
306 MSG_task_destroy(tk);
310 static int Task_tostring(lua_State * L)
312 lua_pushfstring(L, "Task :%p", lua_touserdata(L, 1));
316 static const luaL_reg Task_meta[] = {
318 {"__tostring", Task_tostring},
325 static m_host_t checkHost(lua_State * L, int index)
328 luaL_checktype(L, index, LUA_TTABLE);
329 lua_getfield(L, index, "__simgrid_host");
330 pi = (m_host_t *) luaL_checkudata(L, -1, HOST_MODULE_NAME);
332 luaL_typerror(L, index, HOST_MODULE_NAME);
335 luaL_error(L, "null Host");
340 static int Host_get_by_name(lua_State * L)
342 const char *name = luaL_checkstring(L, 1);
343 XBT_DEBUG("Getting Host from name...");
344 m_host_t msg_host = MSG_get_host_by_name(name);
346 luaL_error(L, "null Host : MSG_get_host_by_name failed");
348 lua_newtable(L); /* create a table, put the userdata on top of it */
349 m_host_t *lua_host = (m_host_t *) lua_newuserdata(L, sizeof(m_host_t));
350 *lua_host = msg_host;
351 luaL_getmetatable(L, HOST_MODULE_NAME);
352 lua_setmetatable(L, -2);
353 lua_setfield(L, -2, "__simgrid_host"); /* put the userdata as field of the table */
354 /* remove the args from the stack */
360 static int Host_get_name(lua_State * L)
362 m_host_t ht = checkHost(L, -1);
363 lua_pushstring(L, MSG_host_get_name(ht));
367 static int Host_number(lua_State * L)
369 lua_pushnumber(L, MSG_get_host_number());
373 static int Host_at(lua_State * L)
375 int index = luaL_checkinteger(L, 1);
376 m_host_t host = MSG_get_host_table()[index - 1]; // lua indexing start by 1 (lua[1] <=> C[0])
377 lua_newtable(L); /* create a table, put the userdata on top of it */
378 m_host_t *lua_host = (m_host_t *) lua_newuserdata(L, sizeof(m_host_t));
380 luaL_getmetatable(L, HOST_MODULE_NAME);
381 lua_setmetatable(L, -2);
382 lua_setfield(L, -2, "__simgrid_host"); /* put the userdata as field of the table */
387 static int Host_self(lua_State * L)
389 m_host_t host = MSG_host_self();
391 m_host_t *lua_host =(m_host_t *)lua_newuserdata(L,sizeof(m_host_t));
393 luaL_getmetatable(L, HOST_MODULE_NAME);
394 lua_setmetatable(L, -2);
395 lua_setfield(L, -2, "__simgrid_host");
400 static int Host_get_property_value(lua_State * L)
402 m_host_t ht = checkHost(L, -2);
403 const char *prop = luaL_checkstring(L, -1);
404 lua_pushstring(L,MSG_host_get_property_value(ht,prop));
408 static int Host_sleep(lua_State *L)
410 int time = luaL_checknumber(L, -1);
411 MSG_process_sleep(time);
415 static int Host_destroy(lua_State *L)
417 m_host_t ht = checkHost(L, -1);
418 __MSG_host_destroy(ht);
422 /* ********************************************************************************* */
423 /* lua_stub_generator functions */
424 /* ********************************************************************************* */
426 xbt_dict_t process_function_set;
427 xbt_dynar_t process_list;
428 xbt_dict_t machine_set;
429 static s_process_t process;
431 void s_process_free(void *process)
433 s_process_t *p = (s_process_t *) process;
435 for (i = 0; i < p->argc; i++)
441 static int gras_add_process_function(lua_State * L)
444 const char *process_host = luaL_checkstring(L, 1);
445 const char *process_function = luaL_checkstring(L, 2);
447 if (xbt_dict_is_empty(machine_set)
448 || xbt_dict_is_empty(process_function_set)
449 || xbt_dynar_is_empty(process_list)) {
450 process_function_set = xbt_dict_new();
451 process_list = xbt_dynar_new(sizeof(s_process_t), s_process_free);
452 machine_set = xbt_dict_new();
455 xbt_dict_set(machine_set, process_host, NULL, NULL);
456 xbt_dict_set(process_function_set, process_function, NULL, NULL);
459 process.argv = xbt_new(char *, 1);
460 process.argv[0] = xbt_strdup(process_function);
461 process.host = strdup(process_host);
464 while (lua_next(L, 3) != 0) {
465 arg = lua_tostring(L, -1);
468 xbt_realloc(process.argv, (process.argc) * sizeof(char *));
469 process.argv[(process.argc) - 1] = xbt_strdup(arg);
471 XBT_DEBUG("index = %f , arg = %s \n", lua_tonumber(L, -2),
472 lua_tostring(L, -1));
476 //add to the process list
477 xbt_dynar_push(process_list, &process);
482 static int gras_generate(lua_State * L)
484 const char *project_name = luaL_checkstring(L, 1);
485 generate_sim(project_name);
486 generate_rl(project_name);
487 generate_makefile_local(project_name);
491 /***********************************
493 **********************************/
494 static int trace_start(lua_State *L)
502 static int trace_category(lua_State * L)
505 TRACE_category(luaL_checkstring(L, 1));
510 static int trace_set_task_category(lua_State *L)
513 TRACE_msg_set_task_category(checkTask(L, -2), luaL_checkstring(L, -1));
518 static int trace_end(lua_State *L)
525 //***********Register Methods *******************************************//
529 static const luaL_reg Host_methods[] = {
530 {"getByName", Host_get_by_name},
531 {"name", Host_get_name},
532 {"number", Host_number},
535 {"getPropValue", Host_get_property_value},
536 {"sleep", Host_sleep},
537 {"destroy",Host_destroy},
538 // Bypass XML Methods
539 {"setFunction", console_set_function},
540 {"setProperty", console_host_set_property},
544 static int Host_gc(lua_State * L)
546 m_host_t ht = checkHost(L, -1);
552 static int Host_tostring(lua_State * L)
554 lua_pushfstring(L, "Host :%p", lua_touserdata(L, 1));
558 static const luaL_reg Host_meta[] = {
560 {"__tostring", Host_tostring},
567 static const luaL_reg AS_methods[] = {
568 {"new", console_add_AS},
569 {"addHost",console_add_host},
570 {"addLink",console_add_link},
571 {"addRoute",console_add_route},
578 static const luaL_reg Trace_methods[] = {
579 {"start",trace_start},
580 {"category",trace_category},
581 {"setTaskCategory",trace_set_task_category},
582 {"finish",trace_end},
586 * Environment related
589 //extern lua_State *simgrid_lua_state;
591 static int run_lua_code(int argc, char **argv)
593 XBT_DEBUG("Run lua code %s", argv[0]);
594 lua_State *L = lua_newthread(simgrid_lua_state);
595 int ref = luaL_ref(simgrid_lua_state, LUA_REGISTRYINDEX); // protect the thread from being garbage collected
598 /* Start the co-routine */
599 lua_getglobal(L, argv[0]);
600 xbt_assert(lua_isfunction(L, -1),
601 "The lua function %s does not seem to exist", argv[0]);
603 // push arguments onto the stack
605 for (i = 1; i < argc; i++)
606 lua_pushstring(L, argv[i]);
608 // Call the function (in resume)
610 err = lua_pcall(L, argc - 1, 1, 0);
611 xbt_assert(err == 0, "error running function `%s': %s", argv[0],
612 lua_tostring(L, -1));
614 /* retrieve result */
615 if (lua_isnumber(L, -1)) {
616 res = lua_tonumber(L, -1);
617 lua_pop(L, 1); /* pop returned value */
620 luaL_unref(simgrid_lua_state, LUA_REGISTRYINDEX, ref);
621 XBT_DEBUG("Execution of lua code %s is over", (argv ? argv[0] : "(null)"));
625 static int launch_application(lua_State * L)
627 const char *file = luaL_checkstring(L, 1);
628 MSG_function_register_default(run_lua_code);
629 MSG_launch_application(file);
633 #include "simix/simix.h" //FIXME: KILLME when debugging on simix internals become useless
634 static int create_environment(lua_State * L)
636 const char *file = luaL_checkstring(L, 1);
637 XBT_DEBUG("Loading environment file %s", file);
638 MSG_create_environment(file);
641 xbt_dict_t hosts = SIMIX_host_get_dict();
646 xbt_dict_foreach(hosts, c, name, host) {
647 XBT_DEBUG("We have an host %s", SIMIX_host_get_name(host));
654 static int debug(lua_State * L)
656 const char *str = luaL_checkstring(L, 1);
657 XBT_DEBUG("%s", str);
661 static int info(lua_State * L)
663 const char *str = luaL_checkstring(L, 1);
668 static int run(lua_State * L)
674 static int clean(lua_State * L)
681 * Bypass XML Parser (lua console)
685 * Register platform for MSG
687 static int msg_register_platform(lua_State * L)
689 /* Tell Simgrid we dont wanna use its parser */
690 surf_parse = console_parse_platform;
691 surf_parse_reset_callbacks();
692 surf_config_models_setup(NULL);
693 MSG_create_environment(NULL);
698 * Register platform for Simdag
701 static int sd_register_platform(lua_State * L)
703 surf_parse = console_parse_platform_wsL07;
704 surf_parse_reset_callbacks();
705 surf_config_models_setup(NULL);
706 SD_create_environment(NULL);
711 * Register platform for gras
713 static int gras_register_platform(lua_State * L)
715 /* Tell Simgrid we dont wanna use surf parser */
716 surf_parse = console_parse_platform;
717 surf_parse_reset_callbacks();
718 surf_config_models_setup(NULL);
719 gras_create_environment(NULL);
724 * Register applicaiton for MSG
726 static int msg_register_application(lua_State * L)
728 MSG_function_register_default(run_lua_code);
729 surf_parse = console_parse_application;
730 MSG_launch_application(NULL);
735 * Register application for gras
737 static int gras_register_application(lua_State * L)
739 gras_function_register_default(run_lua_code);
740 surf_parse = console_parse_application;
741 gras_launch_application(NULL);
745 static const luaL_Reg simgrid_funcs[] = {
746 {"create_environment", create_environment},
747 {"launch_application", launch_application},
753 {"platform", create_environment},
754 {"application", launch_application},
755 /* methods to bypass XML parser */
756 {"msg_register_platform", msg_register_platform},
757 {"sd_register_platform", sd_register_platform},
758 {"msg_register_application", msg_register_application},
759 {"gras_register_platform", gras_register_platform},
760 {"gras_register_application", gras_register_application},
761 /* gras sub generator method */
762 {"gras_set_process_function", gras_add_process_function},
763 {"gras_generate", gras_generate},
767 /* ********************************************************************************* */
768 /* module management functions */
769 /* ********************************************************************************* */
771 #define LUA_MAX_ARGS_COUNT 10 /* maximum amount of arguments we can get from lua on command line */
773 int luaopen_simgrid(lua_State * L); // Fuck gcc: we don't need that prototype
774 int luaopen_simgrid(lua_State * L)
776 XBT_DEBUG("Luaopen_Simgrid *****");
777 char **argv = malloc(sizeof(char *) * LUA_MAX_ARGS_COUNT);
779 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? */
780 /* Get the command line arguments from the lua interpreter */
781 lua_getglobal(L, "arg");
782 /* if arg is a null value, it means we use lua only as a script to init platform
783 * else it should be a table and then take arg in consideration
785 if (lua_istable(L, -1)) {
789 lua_pushinteger(L, argc - 2);
791 if (lua_isnil(L, -1)) {
794 xbt_assert(lua_isstring(L, -1),
795 "argv[%d] got from lua is no string", argc - 1);
796 xbt_assert(argc < LUA_MAX_ARGS_COUNT,
797 "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",
798 __FILE__, LUA_MAX_ARGS_COUNT - 1);
799 argv[argc - 1] = (char *) luaL_checkstring(L, -1);
801 XBT_DEBUG("Got command line argument %s from lua", argv[argc - 1]);
806 /* Initialize the MSG core */
807 MSG_global_init(&argc, argv);
808 XBT_DEBUG("Still %d arguments on command line", argc); // FIXME: update the lua's arg table to reflect the changes from SimGrid
810 /* register the core C functions to lua */
811 luaL_register(L, "simgrid", simgrid_funcs);
812 /* register the task methods to lua */
813 luaL_openlib(L, TASK_MODULE_NAME, Task_methods, 0); //create methods table,add it to the globals
814 luaL_newmetatable(L, TASK_MODULE_NAME); //create metatable for Task,add it to the Lua registry
815 luaL_openlib(L, 0, Task_meta, 0); // fill metatable
816 lua_pushliteral(L, "__index");
817 lua_pushvalue(L, -3); //dup methods table
818 lua_rawset(L, -3); //matatable.__index = methods
819 lua_pushliteral(L, "__metatable");
820 lua_pushvalue(L, -3); //dup methods table
821 lua_rawset(L, -3); //hide metatable:metatable.__metatable = methods
822 lua_pop(L, 1); //drop metatable
824 /* register the hosts methods to lua */
825 luaL_openlib(L, HOST_MODULE_NAME, Host_methods, 0);
826 luaL_newmetatable(L, HOST_MODULE_NAME);
827 luaL_openlib(L, 0, Host_meta, 0);
828 lua_pushliteral(L, "__index");
829 lua_pushvalue(L, -3);
831 lua_pushliteral(L, "__metatable");
832 lua_pushvalue(L, -3);
836 /* register the links methods to lua */
837 luaL_openlib(L, AS_MODULE_NAME, AS_methods, 0);
838 luaL_newmetatable(L, AS_MODULE_NAME);
843 /*register the Tracing functions to lua */
844 luaL_openlib(L, TRACE_MODULE_NAME, Trace_methods, 0);
845 luaL_newmetatable(L, TRACE_MODULE_NAME);
848 /* Keep the context mechanism informed of our lua world today */
849 simgrid_lua_state = L;