X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/34fcc7044aabdd6b72530471344eb5744335e272..f4d117984401d94136223dc1d254a288c06606f2:/src/bindings/lua/lua_state_cloner.c diff --git a/src/bindings/lua/lua_state_cloner.c b/src/bindings/lua/lua_state_cloner.c index fbe640a5e8..ce6d83c1b5 100644 --- a/src/bindings/lua/lua_state_cloner.c +++ b/src/bindings/lua/lua_state_cloner.c @@ -13,9 +13,10 @@ #include #include -XBT_LOG_NEW_DEFAULT_SUBCATEGORY(lua_state_cloner, lua, "Lua state management"); +XBT_LOG_NEW_DEFAULT_SUBCATEGORY(lua_state_cloner, bindings, "Lua state management"); static void sglua_add_maestro_table(lua_State* L, int index, void* maestro_table_ptr); +static void sglua_remove_maestro_table(lua_State* L, int index, void* maestro_table_ptr); static void* sglua_get_maestro_table_ptr(lua_State* L, int index); static void sglua_get_table_by_ptr(lua_State* L, void* table_ptr); static int l_get_from_maestro(lua_State* L); @@ -30,24 +31,6 @@ static void sglua_copy_lightuserdata(lua_State* src, lua_State* dst); static void sglua_copy_userdata(lua_State* src, lua_State* dst); static void sglua_copy_thread(lua_State* src, lua_State* dst); -/** - * @brief Returns the father of a state, i.e. the state that created it. - * @param L a Lua state - * @return its father, or NULL if the state was not created by sglua_clone_state() - */ -static lua_State* sglua_get_father(lua_State* L) { - - /* ... */ - lua_pushstring(L, "simgrid.father"); - /* ... "simgrid.father" */ - lua_rawget(L, LUA_REGISTRYINDEX); - /* ... father */ - lua_State* father = lua_touserdata(L, -1); - lua_pop(L, 1); - /* ... */ - return father; -} - /** * @brief Adds a reference to a maestro table to the list of known maestro * tables of a state. @@ -59,14 +42,16 @@ static lua_State* sglua_get_father(lua_State* L) { * @param index index of the copy of the maestro table in the stack of L * @param maestro_table_ptr pointer to the original table in maestro's world */ -void sglua_add_maestro_table(lua_State* L, int index, void* maestro_table_ptr) { +static void sglua_add_maestro_table(lua_State* L, int index, void* maestro_table_ptr) { /* we will set both [ptr] -> table and [table] -> ptr */ /* ... */ lua_pushvalue(L, index); /* ... table */ - lua_getfield(L, LUA_REGISTRYINDEX, "simgrid.maestro_tables"); + lua_pushstring(L, "simgrid.maestro_tables"); + /* ... table "simgrid.maestro_tables" */ + lua_rawget(L, LUA_REGISTRYINDEX); /* ... table maestrotbs */ lua_pushvalue(L, -2); /* ... table maestrotbs table */ @@ -84,6 +69,41 @@ void sglua_add_maestro_table(lua_State* L, int index, void* maestro_table_ptr) { /* ... */ } +/** + * @brief Removes a reference to a maestro table to the list of known maestro + * tables of a state. + * + * @param L a state (can be maestro itself) + * @param index index of the copy of the maestro table in the stack of L + * @param maestro_table_ptr pointer to the original table in maestro's world + */ +static void sglua_remove_maestro_table(lua_State* L, int index, void* maestro_table_ptr) { + + /* we will unset both [ptr] -> table and [table] -> ptr */ + + /* ... */ + lua_pushvalue(L, index); + /* ... table */ + lua_pushstring(L, "simgrid.maestro_tables"); + /* ... table "simgrid.maestro_tables" */ + lua_rawget(L, LUA_REGISTRYINDEX); + /* ... table maestrotbs */ + lua_pushvalue(L, -2); + /* ... table maestrotbs table */ + lua_pushnil(L); + /* ... table maestrotbs table nil */ + lua_pushlightuserdata(L, maestro_table_ptr); + /* ... table maestrotbs table nil tableptr */ + lua_pushnil(L); + /* ... table maestrotbs table nil tableptr nil*/ + lua_settable(L, -5); + /* ... table maestrotbs table nil */ + lua_settable(L, -3); + /* ... table maestrotbs */ + lua_pop(L, 2); + /* ... */ +} + /** * @brief For a table in the stack of L, returns a pointer that identifies the * same table in in maestro's world. @@ -96,20 +116,22 @@ static void* sglua_get_maestro_table_ptr(lua_State* L, int index) { void* maestro_table_ptr = NULL; /* ... */ + lua_pushvalue(L, index); + /* ... table */ lua_pushstring(L, "simgrid.maestro_tables"); - /* ... "simgrid.maestro_tables" */ + /* ... table "simgrid.maestro_tables" */ lua_rawget(L, LUA_REGISTRYINDEX); - /* ... maestrotbs */ - lua_pushvalue(L, index); - /* ... maestrotbs table */ + /* ... table maestrotbs */ + lua_pushvalue(L, -2); + /* ... table maestrotbs table */ lua_gettable(L, -2); - /* ... maestrotbs tableptr/nil */ + /* ... table maestrotbs tableptr/nil */ if (!lua_isnil(L, -1)) { - /* ... maestrotbs tableptr */ + /* ... table maestrotbs tableptr */ maestro_table_ptr = (void*) lua_topointer(L, -1); } - lua_pop(L, 2); + lua_pop(L, 3); /* ... */ return maestro_table_ptr; } @@ -140,15 +162,30 @@ static void sglua_get_table_by_ptr(lua_State* L, void* maestro_table_ptr) { /** * @brief Pops a value from the stack of a source state and pushes it on the * stack of another state. + * If the value is a table, its content is copied recursively. + * + * This function is similar to lua_xmove() but it allows to move a value + * between two different global states. * + * @param src the source state (not necessarily maestro) + * @param dst the destination state + */ +void sglua_move_value(lua_State* src, lua_State* dst) { + + sglua_copy_value(src, dst); + lua_pop(src, 1); +} + +/** + * @brief Pushes onto the stack a copy of the value on top another stack. * If the value is a table, its content is copied recursively. * - * TODO: add support of closures + * This function allows to move a value between two different global states. * * @param src the source state (not necessarily maestro) * @param dst the destination state */ -void sglua_move_value(lua_State* src, lua_State *dst) { +void sglua_copy_value(lua_State* src, lua_State* dst) { luaL_checkany(src, -1); /* check the value to copy */ @@ -197,13 +234,9 @@ void sglua_move_value(lua_State* src, lua_State *dst) { break; } - /* the value has been copied to dst: remove it from src */ - lua_pop(src, 1); - - indent -= 2; XBT_DEBUG("%sData copied", sglua_get_spaces(indent)); - sglua_stack_dump("src after copying a value (should be ...): ", src); + sglua_stack_dump("src after copying a value (should be ... value): ", src); sglua_stack_dump("dst after copying a value (should be ... value): ", dst); } @@ -246,12 +279,12 @@ static void sglua_copy_string(lua_State* src, lua_State* dst) { } /** - * @brief Copies the table value on the top of src to the top of dst. + * @brief Copies the table value on top of src to the top of dst. * * A deep copy of the table is made. If the table has a metatable, the * metatable is also copied. - * If the table is already known by the destination state, it is not copied - * again. + * If the table comes from maestro and is already known by the destination + * state, it is not copied again. * * @param src source state * @param dst destination state @@ -264,17 +297,22 @@ static void sglua_copy_table(lua_State* src, lua_State* dst) { /* get from maestro the pointer that identifies this table */ void* table_ptr = sglua_get_maestro_table_ptr(src, -1); - if (table_ptr == NULL) { + int known_by_maestro = (table_ptr != NULL); + + if (!known_by_maestro) { /* the table didn't come from maestro: nevermind, use the pointer of src */ table_ptr = (void*) lua_topointer(src, -1); - - if (!sglua_is_maestro(src)) { - XBT_DEBUG("Using a non-maestro table pointer"); - } + XBT_DEBUG("%sMaestro does not know this table", + sglua_get_spaces(indent)); } - else if (sglua_is_maestro(src)) { + + if (sglua_is_maestro(src)) { /* register the table in maestro itself */ + XBT_DEBUG("%sKeeping track of this table in maestro itself", + sglua_get_spaces(indent)); sglua_add_maestro_table(src, -1, table_ptr); + known_by_maestro = 1; + xbt_assert(sglua_get_maestro_table_ptr(src, -1) == table_ptr); } /* to avoid infinite recursion, see if this table is already known by dst */ @@ -298,9 +336,10 @@ static void sglua_copy_table(lua_State* src, lua_State* dst) { /* mark the table as known right now to avoid infinite recursion */ sglua_add_maestro_table(dst, -1, table_ptr); - /* FIXME: we may have added a table with a non-maestro pointer, is this a - problem? */ + /* we may have added a table with a non-maestro pointer, but if it was the + * case, we will remove it later */ XBT_DEBUG("%sTable marked as known", sglua_get_spaces(indent)); + xbt_assert(sglua_get_maestro_table_ptr(dst, -1) == table_ptr); sglua_stack_dump("dst after marking the table as known (should be ... table): ", dst); @@ -371,13 +410,17 @@ static void sglua_copy_table(lua_State* src, lua_State* dst) { } XBT_DEBUG("%sFinished traversing the table", sglua_get_spaces(indent)); } + + if (!known_by_maestro) { + /* actually,it was not a maestro table: forget the pointer */ + sglua_remove_maestro_table(dst, -1, table_ptr); + } } /** * @brief Copies the function on the top of src to the top of dst. * * It can be a Lua function or a C function. - * Copying upvalues is not implemented yet (TODO). * * @param src source state * @param dst destination state @@ -385,22 +428,52 @@ static void sglua_copy_table(lua_State* src, lua_State* dst) { static void sglua_copy_function(lua_State* src, lua_State* dst) { if (lua_iscfunction(src, -1)) { - /* it's a C function: just copy the pointer */ - lua_CFunction f = lua_tocfunction(src, -1); - lua_pushcfunction(dst, f); + /* it's a C function */ + + XBT_DEBUG("It's a C function"); + sglua_stack_dump("src before copying upvalues: ", src); + + /* get the function pointer */ + int function_index = lua_gettop(src); + lua_CFunction f = lua_tocfunction(src, function_index); + + /* copy the upvalues */ + int i = 0; + const char* upvalue_name = NULL; + do { + i++; + upvalue_name = lua_getupvalue(src, function_index, i); + + if (upvalue_name != NULL) { + XBT_DEBUG("Upvalue %s", upvalue_name); + sglua_move_value(src, dst); + } + } while (upvalue_name != NULL); + + sglua_stack_dump("src before copying pointer: ", src); + + /* set the function */ + lua_pushcclosure(dst, f, i - 1); + XBT_DEBUG("Function pointer copied"); } else { /* it's a Lua function: dump it from src */ s_sglua_buffer_t buffer; - buffer.capacity = 64; + buffer.capacity = 128; /* an empty function uses 77 bytes */ buffer.size = 0; buffer.data = xbt_new(char, buffer.capacity); /* copy the binary chunk from src into a buffer */ - int error = lua_dump(src, sglua_memory_writer, &buffer); + _XBT_GNUC_UNUSED int error = lua_dump(src, sglua_memory_writer, &buffer); xbt_assert(!error, "Failed to dump the function from the source state: error %d", error); + XBT_DEBUG("Fonction dumped: %zu bytes", buffer.size); + + /* + fwrite(buffer.data, buffer.size, buffer.size, stderr); + fprintf(stderr, "\n"); + */ /* load the chunk into dst */ error = luaL_loadbuffer(dst, buffer.data, buffer.size, "(dumped function)"); @@ -588,15 +661,13 @@ lua_State* sglua_clone_maestro(void) { /* create the table of known tables from maestro */ lua_pushstring(L, "simgrid.maestro_tables"); /* "simgrid.maestro_tables" */ - lua_newtable(L); /* "simgrid.maestro_tables" maestrotbs*/ + lua_newtable(L); /* "simgrid.maestro_tables" maestrotbs */ lua_rawset(L, LUA_REGISTRYINDEX); /* -- */ - /* open the standard libs (theoretically, this is not necessary as they can - * be inherited like any global values, but without a proper support of - * closures, iterators like ipairs don't work). */ - XBT_DEBUG("Metatable of globals and registry set, opening standard libraries now"); - luaL_openlibs(L); + /* opening the standard libs is not necessary as they are + * inherited like any global values */ + /* luaL_openlibs(L); */ XBT_DEBUG("New state created");