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 #define TASK_MODULE_NAME "simgrid.Task"
13 #define HOST_MODULE_NAME "simgrid.Host"
14 // Surf ( bypass XML )
15 #define LINK_MODULE_NAME "simgrid.Link"
16 #define ROUTE_MODULE_NAME "simgrid.Route"
17 #define AS_MODULE_NAME "simgrid.AS"
18 #define TRACE_MODULE_NAME "simgrid.Trace"
20 /* ********************************************************************************* */
21 /* helper functions */
22 /* ********************************************************************************* */
23 static void stackDump(const char *msg, lua_State * L)
28 int top = lua_gettop(L);
31 p += sprintf(p, "STACK(top=%d): ", top);
33 for (i = 1; i <= top; i++) { /* repeat for each level */
34 int t = lua_type(L, i);
37 case LUA_TSTRING: /* strings */
38 p += sprintf(p, "`%s'", lua_tostring(L, i));
41 case LUA_TBOOLEAN: /* booleans */
42 p += sprintf(p, lua_toboolean(L, i) ? "true" : "false");
45 case LUA_TNUMBER: /* numbers */
46 p += sprintf(p, "%g", lua_tonumber(L, i));
50 p += sprintf(p, "Table");
53 default: /* other values */
54 p += sprintf(p, "???");
55 /* if ((ptr = luaL_checkudata(L,i,TASK_MODULE_NAME))) {
58 p+=printf(p,"%s", lua_typename(L, t));
63 p += sprintf(p, " "); /* put a separator */
65 INFO2("%s%s", msg, buff);
68 /** @brief ensures that a userdata on the stack is a task and returns the pointer inside the userdata */
69 static m_task_t checkTask(lua_State * L, int index)
72 luaL_checktype(L, index, LUA_TTABLE);
73 lua_getfield(L, index, "__simgrid_task");
74 pi = (m_task_t *) luaL_checkudata(L, -1, TASK_MODULE_NAME);
76 luaL_typerror(L, index, TASK_MODULE_NAME);
79 luaL_error(L, "null Task");
84 /* ********************************************************************************* */
85 /* wrapper functions */
86 /* ********************************************************************************* */
89 * A task is either something to compute somewhere, or something to exchange between two hosts (or both).
90 * It is defined by a computing amount and a message size.
98 * Construct an new task with the specified processing amount and amount
101 * @param name Task's name
103 * @param computeDuration A value of the processing amount (in flop) needed to process the task.
104 * If 0, then it cannot be executed with the execute() method.
105 * This value has to be >= 0.
107 * @param messageSize A value of amount of data (in bytes) needed to transfert this task.
108 * If 0, then it cannot be transfered with the get() and put() methods.
109 * This value has to be >= 0.
111 static int Task_new(lua_State * L)
113 const char *name = luaL_checkstring(L, 1);
114 int comp_size = luaL_checkint(L, 2);
115 int msg_size = luaL_checkint(L, 3);
116 m_task_t msg_task = MSG_task_create(name, comp_size, msg_size, NULL);
117 lua_newtable(L); /* create a table, put the userdata on top of it */
118 m_task_t *lua_task = (m_task_t *) lua_newuserdata(L, sizeof(m_task_t));
119 *lua_task = msg_task;
120 luaL_getmetatable(L, TASK_MODULE_NAME);
121 lua_setmetatable(L, -2);
122 lua_setfield(L, -2, "__simgrid_task"); /* put the userdata as field of the table */
123 /* remove the args from the stack */
130 static int Task_get_name(lua_State * L)
132 m_task_t tk = checkTask(L, -1);
133 lua_pushstring(L, MSG_task_get_name(tk));
137 static int Task_computation_duration(lua_State * L)
139 m_task_t tk = checkTask(L, -1);
140 lua_pushnumber(L, MSG_task_get_compute_duration(tk));
144 static int Task_execute(lua_State * L)
146 m_task_t tk = checkTask(L, -1);
147 int res = MSG_task_execute(tk);
148 lua_pushnumber(L, res);
152 static int Task_destroy(lua_State * L)
154 m_task_t tk = checkTask(L, -1);
155 int res = MSG_task_destroy(tk);
156 lua_pushnumber(L, res);
160 static int Task_send(lua_State * L)
162 //stackDump("send ",L);
163 m_task_t tk = checkTask(L, -2);
164 const char *mailbox = luaL_checkstring(L, -1);
165 lua_pop(L, 1); // remove the string so that the task is on top of it
166 MSG_task_set_data(tk, L); // Copy my stack into the task, so that the receiver can copy the lua task directly
167 MSG_error_t res = MSG_task_send(tk, mailbox);
168 while (MSG_task_get_data(tk) != NULL) // Don't mess up with my stack: the receiver didn't copy the data yet
169 MSG_process_sleep(0); // yield
174 ERROR0("MSG_task_send failed : Timeout");
176 case MSG_TRANSFER_FAILURE:
177 ERROR0("MSG_task_send failed : Transfer Failure");
179 case MSG_HOST_FAILURE:
180 ERROR0("MSG_task_send failed : Host Failure ");
184 ("MSG_task_send failed : Unexpected error , please report this bug");
190 static int Task_recv(lua_State * L)
193 const char *mailbox = luaL_checkstring(L, -1);
194 MSG_error_t res = MSG_task_receive(&tk, mailbox);
196 lua_State *sender_stack = MSG_task_get_data(tk);
197 lua_xmove(sender_stack, L, 1); // copy the data directly from sender's stack
198 MSG_task_set_data(tk, NULL);
203 ERROR0("MSG_task_receive failed : Timeout");
205 case MSG_TRANSFER_FAILURE:
206 ERROR0("MSG_task_receive failed : Transfer Failure");
208 case MSG_HOST_FAILURE:
209 ERROR0("MSG_task_receive failed : Host Failure ");
213 ("MSG_task_receive failed : Unexpected error , please report this bug");
220 static const luaL_reg Task_methods[] = {
222 {"name", Task_get_name},
223 {"computation_duration", Task_computation_duration},
224 {"execute", Task_execute},
225 {"destroy", Task_destroy},
231 static int Task_gc(lua_State * L)
233 m_task_t tk = checkTask(L, -1);
235 MSG_task_destroy(tk);
239 static int Task_tostring(lua_State * L)
241 lua_pushfstring(L, "Task :%p", lua_touserdata(L, 1));
245 static const luaL_reg Task_meta[] = {
247 {"__tostring", Task_tostring},
254 static m_host_t checkHost(lua_State * L, int index)
257 luaL_checktype(L, index, LUA_TTABLE);
258 lua_getfield(L, index, "__simgrid_host");
259 pi = (m_host_t *) luaL_checkudata(L, -1, HOST_MODULE_NAME);
261 luaL_typerror(L, index, HOST_MODULE_NAME);
264 luaL_error(L, "null Host");
269 static int Host_get_by_name(lua_State * L)
271 const char *name = luaL_checkstring(L, 1);
272 DEBUG0("Getting Host from name...");
273 m_host_t msg_host = MSG_get_host_by_name(name);
275 luaL_error(L, "null Host : MSG_get_host_by_name failled");
277 lua_newtable(L); /* create a table, put the userdata on top of it */
278 m_host_t *lua_host = (m_host_t *) lua_newuserdata(L, sizeof(m_host_t));
279 *lua_host = msg_host;
280 luaL_getmetatable(L, HOST_MODULE_NAME);
281 lua_setmetatable(L, -2);
282 lua_setfield(L, -2, "__simgrid_host"); /* put the userdata as field of the table */
283 /* remove the args from the stack */
289 static int Host_get_name(lua_State * L)
291 m_host_t ht = checkHost(L, -1);
292 lua_pushstring(L, MSG_host_get_name(ht));
296 static int Host_number(lua_State * L)
298 lua_pushnumber(L, MSG_get_host_number());
302 static int Host_at(lua_State * L)
304 int index = luaL_checkinteger(L, 1);
305 m_host_t host = MSG_get_host_table()[index - 1]; // lua indexing start by 1 (lua[1] <=> C[0])
306 lua_newtable(L); /* create a table, put the userdata on top of it */
307 m_host_t *lua_host = (m_host_t *) lua_newuserdata(L, sizeof(m_host_t));
309 luaL_getmetatable(L, HOST_MODULE_NAME);
310 lua_setmetatable(L, -2);
311 lua_setfield(L, -2, "__simgrid_host"); /* put the userdata as field of the table */
316 static int Host_self(lua_State * L)
318 m_host_t host = MSG_host_self();
320 m_host_t *lua_host =(m_host_t *)lua_newuserdata(L,sizeof(m_host_t));
322 luaL_getmetatable(L, HOST_MODULE_NAME);
323 lua_setmetatable(L, -2);
324 lua_setfield(L, -2, "__simgrid_host");
329 static int Host_get_property_value(lua_State * L)
331 m_host_t ht = checkHost(L, -2);
332 const char *prop = luaL_checkstring(L, -1);
333 lua_pushstring(L,MSG_host_get_property_value(ht,prop));
337 /* ********************************************************************************* */
338 /* lua_stub_generator functions */
339 /* ********************************************************************************* */
341 xbt_dict_t process_function_set;
342 xbt_dynar_t process_list;
343 xbt_dict_t machine_set;
344 static s_process_t process;
346 void s_process_free(void *process)
348 s_process_t *p = (s_process_t *) process;
350 for (i = 0; i < p->argc; i++)
356 static int gras_add_process_function(lua_State * L)
359 const char *process_host = luaL_checkstring(L, 1);
360 const char *process_function = luaL_checkstring(L, 2);
362 if (xbt_dict_is_empty(machine_set)
363 || xbt_dict_is_empty(process_function_set)
364 || xbt_dynar_is_empty(process_list)) {
365 process_function_set = xbt_dict_new();
366 process_list = xbt_dynar_new(sizeof(s_process_t), s_process_free);
367 machine_set = xbt_dict_new();
370 xbt_dict_set(machine_set, process_host, NULL, NULL);
371 xbt_dict_set(process_function_set, process_function, NULL, NULL);
374 process.argv = xbt_new(char *, 1);
375 process.argv[0] = xbt_strdup(process_function);
376 process.host = strdup(process_host);
379 while (lua_next(L, 3) != 0) {
380 arg = lua_tostring(L, -1);
383 xbt_realloc(process.argv, (process.argc) * sizeof(char *));
384 process.argv[(process.argc) - 1] = xbt_strdup(arg);
386 DEBUG2("index = %f , arg = %s \n", lua_tonumber(L, -2),
387 lua_tostring(L, -1));
391 //add to the process list
392 xbt_dynar_push(process_list, &process);
399 static int gras_generate(lua_State * L)
401 const char *project_name = luaL_checkstring(L, 1);
402 generate_sim(project_name);
403 generate_rl(project_name);
404 generate_makefile_local(project_name);
408 /***********************************
410 **********************************/
411 static int trace_start(lua_State *L)
417 static int trace_category(lua_State * L)
419 TRACE_category(luaL_checkstring(L, 1));
423 static int trace_set_task_category(lua_State *L)
425 TRACE_msg_set_task_category(checkTask(L, -2), luaL_checkstring(L, -1));
429 static int trace_end(lua_State *L)
434 //***********Register Methods *******************************************//
438 static const luaL_reg Host_methods[] = {
439 {"getByName", Host_get_by_name},
440 {"name", Host_get_name},
441 {"number", Host_number},
444 {"getPropValue",Host_get_property_value},
445 // Bypass XML Methods
446 {"new", console_add_host},
447 {"setFunction", console_set_function},
451 static int Host_gc(lua_State * L)
453 m_host_t ht = checkHost(L, -1);
459 static int Host_tostring(lua_State * L)
461 lua_pushfstring(L, "Host :%p", lua_touserdata(L, 1));
465 static const luaL_reg Host_meta[] = {
467 {"__tostring", Host_tostring},
474 static const luaL_reg AS_methods[] = {
475 {"new", console_add_AS},
483 static const luaL_reg Link_methods[] = {
484 {"new", console_add_link},
491 static const luaL_reg Route_methods[] = {
492 {"new", console_add_route},
499 static const luaL_reg Trace_methods[] = {
500 {"start",trace_start},
501 {"category",trace_category},
502 {"setTaskCategory",trace_set_task_category},
503 {"finish",trace_end},
507 * Environment related
510 extern lua_State *simgrid_lua_state;
512 static int run_lua_code(int argc, char **argv)
514 DEBUG1("Run lua code %s", argv[0]);
515 lua_State *L = lua_newthread(simgrid_lua_state);
516 int ref = luaL_ref(simgrid_lua_state, LUA_REGISTRYINDEX); // protect the thread from being garbage collected
519 /* Start the co-routine */
520 lua_getglobal(L, argv[0]);
521 xbt_assert1(lua_isfunction(L, -1),
522 "The lua function %s does not seem to exist", argv[0]);
524 // push arguments onto the stack
526 for (i = 1; i < argc; i++)
527 lua_pushstring(L, argv[i]);
529 // Call the function (in resume)
530 xbt_assert2(lua_pcall(L, argc - 1, 1, 0) == 0,
531 "error running function `%s': %s", argv[0], lua_tostring(L,
534 /* retrieve result */
535 if (lua_isnumber(L, -1)) {
536 res = lua_tonumber(L, -1);
537 lua_pop(L, 1); /* pop returned value */
540 luaL_unref(simgrid_lua_state, LUA_REGISTRYINDEX, ref);
541 DEBUG1("Execution of lua code %s is over", (argv ? argv[0] : "(null)"));
545 static int launch_application(lua_State * L)
547 const char *file = luaL_checkstring(L, 1);
548 MSG_function_register_default(run_lua_code);
549 MSG_launch_application(file);
553 #include "simix/simix.h" //FIXME: KILLME when debugging on simix internals become useless
554 static int create_environment(lua_State * L)
556 const char *file = luaL_checkstring(L, 1);
557 DEBUG1("Loading environment file %s", file);
558 MSG_create_environment(file);
559 smx_host_t *hosts = SIMIX_host_get_table();
561 for (i = 0; i < SIMIX_host_get_number(); i++) {
562 DEBUG1("We have an host %s", SIMIX_host_get_name(hosts[i]));
568 static int debug(lua_State * L)
570 const char *str = luaL_checkstring(L, 1);
575 static int info(lua_State * L)
577 const char *str = luaL_checkstring(L, 1);
582 static int run(lua_State * L)
588 static int clean(lua_State * L)
595 * Bypass XML Parser (lua console)
599 * Register platform for MSG
601 static int msg_register_platform(lua_State * L)
603 /* Tell Simgrid we dont wanna use its parser */
604 surf_parse = console_parse_platform;
605 MSG_create_environment(NULL);
610 * Register platform for Simdag
613 static int sd_register_platform(lua_State * L)
615 surf_parse = console_parse_platform_wsL07;
616 SD_create_environment(NULL);
621 * Register platform for gras
623 static int gras_register_platform(lua_State * L)
625 /* Tell Simgrid we dont wanna use surf parser */
626 surf_parse = console_parse_platform;
627 gras_create_environment(NULL);
632 * Register applicaiton for MSG
634 static int msg_register_application(lua_State * L)
636 MSG_function_register_default(run_lua_code);
637 surf_parse = console_parse_application;
638 MSG_launch_application(NULL);
643 * Register application for gras
645 static int gras_register_application(lua_State * L)
647 gras_function_register_default(run_lua_code);
648 surf_parse = console_parse_application;
649 gras_launch_application(NULL);
653 static const luaL_Reg simgrid_funcs[] = {
654 {"create_environment", create_environment},
655 {"launch_application", launch_application},
661 {"platform", create_environment},
662 {"application", launch_application},
663 /* methods to bypass XML parser */
664 {"msg_register_platform", msg_register_platform},
665 {"sd_register_platform", sd_register_platform},
666 {"msg_register_application", msg_register_application},
667 {"gras_register_platform", gras_register_platform},
668 {"gras_register_application", gras_register_application},
669 /* gras sub generator method */
670 {"gras_set_process_function", gras_add_process_function},
671 {"gras_generate", gras_generate},
675 /* ********************************************************************************* */
676 /* module management functions */
677 /* ********************************************************************************* */
679 extern const char *xbt_ctx_factory_to_use; /*Hack: let msg load directly the right factory */
681 #define LUA_MAX_ARGS_COUNT 10 /* maximum amount of arguments we can get from lua on command line */
683 int luaopen_simgrid(lua_State * L); // Fuck gcc: we don't need that prototype
684 int luaopen_simgrid(lua_State * L)
687 //xbt_ctx_factory_to_use = "lua";
688 char **argv = malloc(sizeof(char *) * LUA_MAX_ARGS_COUNT);
690 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? */
691 /* Get the command line arguments from the lua interpreter */
692 lua_getglobal(L, "arg");
693 /* if arg is a null value, it means we use lua only as a script to init platform
694 * else it should be a table and then take arg in consideration
696 if (lua_istable(L, -1)) {
700 lua_pushinteger(L, argc - 2);
702 if (lua_isnil(L, -1)) {
705 xbt_assert1(lua_isstring(L, -1),
706 "argv[%d] got from lua is no string", argc - 1);
707 xbt_assert2(argc < LUA_MAX_ARGS_COUNT,
708 "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",
709 __FILE__, LUA_MAX_ARGS_COUNT - 1);
710 argv[argc - 1] = (char *) luaL_checkstring(L, -1);
712 DEBUG1("Got command line argument %s from lua", argv[argc - 1]);
717 /* Initialize the MSG core */
718 MSG_global_init(&argc, argv);
719 DEBUG1("Still %d arguments on command line", argc); // FIXME: update the lua's arg table to reflect the changes from SimGrid
721 /* register the core C functions to lua */
722 luaL_register(L, "simgrid", simgrid_funcs);
723 /* register the task methods to lua */
724 luaL_openlib(L, TASK_MODULE_NAME, Task_methods, 0); //create methods table,add it to the globals
725 luaL_newmetatable(L, TASK_MODULE_NAME); //create metatable for Task,add it to the Lua registry
726 luaL_openlib(L, 0, Task_meta, 0); // fill metatable
727 lua_pushliteral(L, "__index");
728 lua_pushvalue(L, -3); //dup methods table
729 lua_rawset(L, -3); //matatable.__index = methods
730 lua_pushliteral(L, "__metatable");
731 lua_pushvalue(L, -3); //dup methods table
732 lua_rawset(L, -3); //hide metatable:metatable.__metatable = methods
733 lua_pop(L, 1); //drop metatable
735 /* register the hosts methods to lua */
736 luaL_openlib(L, HOST_MODULE_NAME, Host_methods, 0);
737 luaL_newmetatable(L, HOST_MODULE_NAME);
738 luaL_openlib(L, 0, Host_meta, 0);
739 lua_pushliteral(L, "__index");
740 lua_pushvalue(L, -3);
742 lua_pushliteral(L, "__metatable");
743 lua_pushvalue(L, -3);
747 /* register the links methods to lua */
748 luaL_openlib(L, AS_MODULE_NAME, AS_methods, 0);
749 luaL_newmetatable(L, AS_MODULE_NAME);
752 /* register the links methods to lua */
753 luaL_openlib(L, LINK_MODULE_NAME, Link_methods, 0);
754 luaL_newmetatable(L, LINK_MODULE_NAME);
757 /*register the routes methods to lua */
758 luaL_openlib(L, ROUTE_MODULE_NAME, Route_methods, 0);
759 luaL_newmetatable(L, ROUTE_MODULE_NAME);
762 /*register the Tracing functions to lua */
763 luaL_openlib(L, TRACE_MODULE_NAME, Trace_methods, 0);
764 luaL_newmetatable(L, TRACE_MODULE_NAME);
767 /* Keep the context mechanism informed of our lua world today */
768 simgrid_lua_state = L;