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"
19 /* ********************************************************************************* */
20 /* helper functions */
21 /* ********************************************************************************* */
22 static void stackDump(const char *msg, lua_State * L)
27 int top = lua_gettop(L);
30 p += sprintf(p, "STACK(top=%d): ", top);
32 for (i = 1; i <= top; i++) { /* repeat for each level */
33 int t = lua_type(L, i);
36 case LUA_TSTRING: /* strings */
37 p += sprintf(p, "`%s'", lua_tostring(L, i));
40 case LUA_TBOOLEAN: /* booleans */
41 p += sprintf(p, lua_toboolean(L, i) ? "true" : "false");
44 case LUA_TNUMBER: /* numbers */
45 p += sprintf(p, "%g", lua_tonumber(L, i));
49 p += sprintf(p, "Table");
52 default: /* other values */
53 p += sprintf(p, "???");
54 /* if ((ptr = luaL_checkudata(L,i,TASK_MODULE_NAME))) {
57 p+=printf(p,"%s", lua_typename(L, t));
62 p += sprintf(p, " "); /* put a separator */
64 INFO2("%s%s", msg, buff);
67 /** @brief ensures that a userdata on the stack is a task and returns the pointer inside the userdata */
68 static m_task_t checkTask(lua_State * L, int index)
71 luaL_checktype(L, index, LUA_TTABLE);
72 lua_getfield(L, index, "__simgrid_task");
73 pi = (m_task_t *) luaL_checkudata(L, -1, TASK_MODULE_NAME);
75 luaL_typerror(L, index, TASK_MODULE_NAME);
78 luaL_error(L, "null Task");
83 /* ********************************************************************************* */
84 /* wrapper functions */
85 /* ********************************************************************************* */
88 * A task is either something to compute somewhere, or something to exchange between two hosts (or both).
89 * It is defined by a computing amount and a message size.
97 * Construct an new task with the specified processing amount and amount
100 * @param name Task's name
102 * @param computeDuration A value of the processing amount (in flop) needed to process the task.
103 * If 0, then it cannot be executed with the execute() method.
104 * This value has to be >= 0.
106 * @param messageSize A value of amount of data (in bytes) needed to transfert this task.
107 * If 0, then it cannot be transfered with the get() and put() methods.
108 * This value has to be >= 0.
110 static int Task_new(lua_State * L)
112 const char *name = luaL_checkstring(L, 1);
113 int comp_size = luaL_checkint(L, 2);
114 int msg_size = luaL_checkint(L, 3);
115 m_task_t msg_task = MSG_task_create(name, comp_size, msg_size, NULL);
116 lua_newtable(L); /* create a table, put the userdata on top of it */
117 m_task_t *lua_task = (m_task_t *) lua_newuserdata(L, sizeof(m_task_t));
118 *lua_task = msg_task;
119 luaL_getmetatable(L, TASK_MODULE_NAME);
120 lua_setmetatable(L, -2);
121 lua_setfield(L, -2, "__simgrid_task"); /* put the userdata as field of the table */
122 /* remove the args from the stack */
129 static int Task_get_name(lua_State * L)
131 m_task_t tk = checkTask(L, -1);
132 lua_pushstring(L, MSG_task_get_name(tk));
136 static int Task_computation_duration(lua_State * L)
138 m_task_t tk = checkTask(L, -1);
139 lua_pushnumber(L, MSG_task_get_compute_duration(tk));
143 static int Task_execute(lua_State * L)
145 m_task_t tk = checkTask(L, -1);
146 int res = MSG_task_execute(tk);
147 lua_pushnumber(L, res);
151 static int Task_destroy(lua_State * L)
153 m_task_t tk = checkTask(L, -1);
154 int res = MSG_task_destroy(tk);
155 lua_pushnumber(L, res);
159 static int Task_send(lua_State * L)
161 //stackDump("send ",L);
162 m_task_t tk = checkTask(L, -2);
163 const char *mailbox = luaL_checkstring(L, -1);
164 lua_pop(L, 1); // remove the string so that the task is on top of it
165 MSG_task_set_data(tk, L); // Copy my stack into the task, so that the receiver can copy the lua task directly
166 MSG_error_t res = MSG_task_send(tk, mailbox);
167 while (MSG_task_get_data(tk) != NULL) // Don't mess up with my stack: the receiver didn't copy the data yet
168 MSG_process_sleep(0); // yield
173 ERROR0("MSG_task_send failed : Timeout");
175 case MSG_TRANSFER_FAILURE:
176 ERROR0("MSG_task_send failed : Transfer Failure");
178 case MSG_HOST_FAILURE:
179 ERROR0("MSG_task_send failed : Host Failure ");
183 ("MSG_task_send failed : Unexpected error , please report this bug");
189 static int Task_recv(lua_State * L)
192 const char *mailbox = luaL_checkstring(L, -1);
193 MSG_error_t res = MSG_task_receive(&tk, mailbox);
195 lua_State *sender_stack = MSG_task_get_data(tk);
196 lua_xmove(sender_stack, L, 1); // copy the data directly from sender's stack
197 MSG_task_set_data(tk, NULL);
202 ERROR0("MSG_task_receive failed : Timeout");
204 case MSG_TRANSFER_FAILURE:
205 ERROR0("MSG_task_receive failed : Transfer Failure");
207 case MSG_HOST_FAILURE:
208 ERROR0("MSG_task_receive failed : Host Failure ");
212 ("MSG_task_receive failed : Unexpected error , please report this bug");
219 static const luaL_reg Task_methods[] = {
221 {"name", Task_get_name},
222 {"computation_duration", Task_computation_duration},
223 {"execute", Task_execute},
224 {"destroy", Task_destroy},
230 static int Task_gc(lua_State * L)
232 m_task_t tk = checkTask(L, -1);
234 MSG_task_destroy(tk);
238 static int Task_tostring(lua_State * L)
240 lua_pushfstring(L, "Task :%p", lua_touserdata(L, 1));
244 static const luaL_reg Task_meta[] = {
246 {"__tostring", Task_tostring},
253 static m_host_t checkHost(lua_State * L, int index)
256 luaL_checktype(L, index, LUA_TTABLE);
257 lua_getfield(L, index, "__simgrid_host");
258 pi = (m_host_t *) luaL_checkudata(L, -1, HOST_MODULE_NAME);
260 luaL_typerror(L, index, HOST_MODULE_NAME);
263 luaL_error(L, "null Host");
268 static int Host_get_by_name(lua_State * L)
270 const char *name = luaL_checkstring(L, 1);
271 DEBUG0("Getting Host from name...");
272 m_host_t msg_host = MSG_get_host_by_name(name);
274 luaL_error(L, "null Host : MSG_get_host_by_name failled");
276 lua_newtable(L); /* create a table, put the userdata on top of it */
277 m_host_t *lua_host = (m_host_t *) lua_newuserdata(L, sizeof(m_host_t));
278 *lua_host = msg_host;
279 luaL_getmetatable(L, HOST_MODULE_NAME);
280 lua_setmetatable(L, -2);
281 lua_setfield(L, -2, "__simgrid_host"); /* put the userdata as field of the table */
282 /* remove the args from the stack */
288 static int Host_get_name(lua_State * L)
290 m_host_t ht = checkHost(L, -1);
291 lua_pushstring(L, MSG_host_get_name(ht));
295 static int Host_number(lua_State * L)
297 lua_pushnumber(L, MSG_get_host_number());
301 static int Host_at(lua_State * L)
303 int index = luaL_checkinteger(L, 1);
304 m_host_t host = MSG_get_host_table()[index - 1]; // lua indexing start by 1 (lua[1] <=> C[0])
305 lua_newtable(L); /* create a table, put the userdata on top of it */
306 m_host_t *lua_host = (m_host_t *) lua_newuserdata(L, sizeof(m_host_t));
308 luaL_getmetatable(L, HOST_MODULE_NAME);
309 lua_setmetatable(L, -2);
310 lua_setfield(L, -2, "__simgrid_host"); /* put the userdata as field of the table */
316 /* ********************************************************************************* */
317 /* lua_stub_generator functions */
318 /* ********************************************************************************* */
320 xbt_dict_t process_function_set;
321 xbt_dynar_t process_list;
322 xbt_dict_t machine_set;
323 static s_process_t process;
325 void s_process_free(void *process)
327 s_process_t *p = (s_process_t *) process;
329 for (i = 0; i < p->argc; i++)
335 static int gras_add_process_function(lua_State * L)
338 const char *process_host = luaL_checkstring(L, 1);
339 const char *process_function = luaL_checkstring(L, 2);
341 if (xbt_dict_is_empty(machine_set)
342 || xbt_dict_is_empty(process_function_set)
343 || xbt_dynar_is_empty(process_list)) {
344 process_function_set = xbt_dict_new();
345 process_list = xbt_dynar_new(sizeof(s_process_t), s_process_free);
346 machine_set = xbt_dict_new();
349 xbt_dict_set(machine_set, process_host, NULL, NULL);
350 xbt_dict_set(process_function_set, process_function, NULL, NULL);
353 process.argv = xbt_new(char *, 1);
354 process.argv[0] = xbt_strdup(process_function);
355 process.host = strdup(process_host);
358 while (lua_next(L, 3) != 0) {
359 arg = lua_tostring(L, -1);
362 xbt_realloc(process.argv, (process.argc) * sizeof(char *));
363 process.argv[(process.argc) - 1] = xbt_strdup(arg);
365 DEBUG2("index = %f , arg = %s \n", lua_tonumber(L, -2),
366 lua_tostring(L, -1));
370 //add to the process list
371 xbt_dynar_push(process_list, &process);
378 static int gras_generate(lua_State * L)
380 const char *project_name = luaL_checkstring(L, 1);
381 generate_sim(project_name);
382 generate_rl(project_name);
383 generate_makefile_local(project_name);
388 //***********Register Methods *******************************************//
393 static const luaL_reg Host_methods[] = {
394 {"getByName", Host_get_by_name},
395 {"name", Host_get_name},
396 {"number", Host_number},
398 // Bypass XML Methods
399 {"new", console_add_host},
400 {"setFunction", console_set_function},
404 static int Host_gc(lua_State * L)
406 m_host_t ht = checkHost(L, -1);
412 static int Host_tostring(lua_State * L)
414 lua_pushfstring(L, "Host :%p", lua_touserdata(L, 1));
418 static const luaL_reg Host_meta[] = {
420 {"__tostring", Host_tostring},
427 static const luaL_reg AS_methods[] = {
428 {"new", console_add_AS},
436 static const luaL_reg Link_methods[] = {
437 {"new", console_add_link},
444 static const luaL_reg Route_methods[] = {
445 {"new", console_add_route},
450 * Environment related
453 extern lua_State *simgrid_lua_state;
455 static int run_lua_code(int argc, char **argv)
457 DEBUG1("Run lua code %s", argv[0]);
458 lua_State *L = lua_newthread(simgrid_lua_state);
459 int ref = luaL_ref(simgrid_lua_state, LUA_REGISTRYINDEX); // protect the thread from being garbage collected
462 /* Start the co-routine */
463 lua_getglobal(L, argv[0]);
464 xbt_assert1(lua_isfunction(L, -1),
465 "The lua function %s does not seem to exist", argv[0]);
467 // push arguments onto the stack
469 for (i = 1; i < argc; i++)
470 lua_pushstring(L, argv[i]);
472 // Call the function (in resume)
473 xbt_assert2(lua_pcall(L, argc - 1, 1, 0) == 0,
474 "error running function `%s': %s", argv[0], lua_tostring(L,
477 /* retrieve result */
478 if (lua_isnumber(L, -1)) {
479 res = lua_tonumber(L, -1);
480 lua_pop(L, 1); /* pop returned value */
483 luaL_unref(simgrid_lua_state, LUA_REGISTRYINDEX, ref);
484 DEBUG1("Execution of lua code %s is over", (argv ? argv[0] : "(null)"));
488 static int launch_application(lua_State * L)
490 const char *file = luaL_checkstring(L, 1);
491 MSG_function_register_default(run_lua_code);
492 MSG_launch_application(file);
496 #include "simix/simix.h" //FIXME: KILLME when debugging on simix internals become useless
497 static int create_environment(lua_State * L)
499 const char *file = luaL_checkstring(L, 1);
500 DEBUG1("Loading environment file %s", file);
501 MSG_create_environment(file);
502 smx_host_t *hosts = SIMIX_host_get_table();
504 for (i = 0; i < SIMIX_host_get_number(); i++) {
505 DEBUG1("We have an host %s", SIMIX_host_get_name(hosts[i]));
511 static int debug(lua_State * L)
513 const char *str = luaL_checkstring(L, 1);
518 static int info(lua_State * L)
520 const char *str = luaL_checkstring(L, 1);
525 static int run(lua_State * L)
531 static int clean(lua_State * L)
538 * Bypass XML Parser (lua console)
542 * Register platform for MSG
544 static int msg_register_platform(lua_State * L)
546 /* Tell Simgrid we dont wanna use its parser */
547 surf_parse = console_parse_platform;
548 MSG_create_environment(NULL);
553 * Register platform for Simdag
556 static int sd_register_platform(lua_State * L)
558 surf_parse = console_parse_platform_wsL07;
559 SD_create_environment(NULL);
564 * Register platform for gras
566 static int gras_register_platform(lua_State * L)
568 /* Tell Simgrid we dont wanna use surf parser */
569 surf_parse = console_parse_platform;
570 gras_create_environment(NULL);
575 * Register applicaiton for MSG
577 static int msg_register_application(lua_State * L)
579 MSG_function_register_default(run_lua_code);
580 surf_parse = console_parse_application;
581 MSG_launch_application(NULL);
586 * Register application for gras
588 static int gras_register_application(lua_State * L)
590 gras_function_register_default(run_lua_code);
591 surf_parse = console_parse_application;
592 gras_launch_application(NULL);
596 static const luaL_Reg simgrid_funcs[] = {
597 {"create_environment", create_environment},
598 {"launch_application", launch_application},
604 {"platform", create_environment},
605 {"application", launch_application},
606 /* methods to bypass XML parser */
607 {"msg_register_platform", msg_register_platform},
608 {"sd_register_platform", sd_register_platform},
609 {"msg_register_application", msg_register_application},
610 {"gras_register_platform", gras_register_platform},
611 {"gras_register_application", gras_register_application},
612 /* gras sub generator method */
613 {"gras_set_process_function", gras_add_process_function},
614 {"gras_generate", gras_generate},
618 /* ********************************************************************************* */
619 /* module management functions */
620 /* ********************************************************************************* */
622 extern const char *xbt_ctx_factory_to_use; /*Hack: let msg load directly the right factory */
624 #define LUA_MAX_ARGS_COUNT 10 /* maximum amount of arguments we can get from lua on command line */
626 int luaopen_simgrid(lua_State * L); // Fuck gcc: we don't need that prototype
627 int luaopen_simgrid(lua_State * L)
630 //xbt_ctx_factory_to_use = "lua";
631 char **argv = malloc(sizeof(char *) * LUA_MAX_ARGS_COUNT);
633 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? */
634 /* Get the command line arguments from the lua interpreter */
635 lua_getglobal(L, "arg");
636 /* if arg is a null value, it means we use lua only as a script to init platform
637 * else it should be a table and then take arg in consideration
639 if (lua_istable(L, -1)) {
643 lua_pushinteger(L, argc - 2);
645 if (lua_isnil(L, -1)) {
648 xbt_assert1(lua_isstring(L, -1),
649 "argv[%d] got from lua is no string", argc - 1);
650 xbt_assert2(argc < LUA_MAX_ARGS_COUNT,
651 "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",
652 __FILE__, LUA_MAX_ARGS_COUNT - 1);
653 argv[argc - 1] = (char *) luaL_checkstring(L, -1);
655 DEBUG1("Got command line argument %s from lua", argv[argc - 1]);
660 /* Initialize the MSG core */
661 MSG_global_init(&argc, argv);
662 DEBUG1("Still %d arguments on command line", argc); // FIXME: update the lua's arg table to reflect the changes from SimGrid
664 /* register the core C functions to lua */
665 luaL_register(L, "simgrid", simgrid_funcs);
666 /* register the task methods to lua */
667 luaL_openlib(L, TASK_MODULE_NAME, Task_methods, 0); //create methods table,add it to the globals
668 luaL_newmetatable(L, TASK_MODULE_NAME); //create metatable for Task,add it to the Lua registry
669 luaL_openlib(L, 0, Task_meta, 0); // fill metatable
670 lua_pushliteral(L, "__index");
671 lua_pushvalue(L, -3); //dup methods table
672 lua_rawset(L, -3); //matatable.__index = methods
673 lua_pushliteral(L, "__metatable");
674 lua_pushvalue(L, -3); //dup methods table
675 lua_rawset(L, -3); //hide metatable:metatable.__metatable = methods
676 lua_pop(L, 1); //drop metatable
678 /* register the hosts methods to lua */
679 luaL_openlib(L, HOST_MODULE_NAME, Host_methods, 0);
680 luaL_newmetatable(L, HOST_MODULE_NAME);
681 luaL_openlib(L, 0, Host_meta, 0);
682 lua_pushliteral(L, "__index");
683 lua_pushvalue(L, -3);
685 lua_pushliteral(L, "__metatable");
686 lua_pushvalue(L, -3);
690 /* register the links methods to lua */
691 luaL_openlib(L, AS_MODULE_NAME, AS_methods, 0);
692 luaL_newmetatable(L, AS_MODULE_NAME);
695 /* register the links methods to lua */
696 luaL_openlib(L, LINK_MODULE_NAME, Link_methods, 0);
697 luaL_newmetatable(L, LINK_MODULE_NAME);
700 /*register the routes methods to lua */
701 luaL_openlib(L, ROUTE_MODULE_NAME, Route_methods, 0);
702 luaL_newmetatable(L, LINK_MODULE_NAME);
705 /* Keep the context mechanism informed of our lua world today */
706 simgrid_lua_state = L;