+/**
+ * @brief Copies a global value or a registry value from the father state.
+ *
+ * The state L must have a father, i.e. it should have been created by
+ * clone_lua_state().
+ * This function is meant to be an __index metamethod.
+ * Consequently, it assumes that the stack has two elements:
+ * a table (either the environment or the registry of L) and the string key of
+ * a value that does not exist yet in this table. It copies the corresponding
+ * value from the father state and pushes it on the stack of L.
+ * If the value does not exist in the father state either, nil is pushed.
+ *
+ * TODO: make this function thread safe. If the simulation runs in parallel,
+ * several simulated processes may trigger this __index metamethod at the same
+ * time and get globals from maestro.
+ *
+ * @param L the current state
+ * @return number of return values pushed (always 1)
+ */
+static int l_get_from_father(lua_State *L) {
+
+ /* check the arguments */
+ luaL_checktype(L, 1, LUA_TTABLE);
+ const char* key = luaL_checkstring(L, 2);
+ /* L: table key */
+ XBT_DEBUG("__index of '%s' begins", key);
+
+ /* want a global or a registry value? */
+ int pseudo_index;
+ if (lua_equal(L, 1, LUA_REGISTRYINDEX)) {
+ /* registry */
+ pseudo_index = LUA_REGISTRYINDEX;
+ XBT_DEBUG("Will get the value from the registry of the father");
+ }
+ else {
+ /* global */
+ pseudo_index = LUA_GLOBALSINDEX;
+ XBT_DEBUG("Will get the value from the globals of the father");
+ }
+
+ /* get the father */
+ lua_State* father = get_father(L);
+
+ if (father == NULL) {
+ XBT_WARN("This state has no father");
+ lua_pop(L, 3);
+ lua_pushnil(L);
+ return 1;
+ }
+ /* L: table key */
+
+ /* get the list of visited tables */
+ lua_pushstring(L, "simgrid.father_visited_tables");
+ /* L: table key "simgrid.father_visited_tables" */
+ lua_rawget(L, LUA_REGISTRYINDEX);
+ /* L: table key visited */
+ lua_insert(L, 1);
+ /* L: visited table key */
+
+ /* get the value from the father */
+ lua_getfield(father, pseudo_index, key);
+ /* father: ... value */
+
+ /* push the value onto the stack of L */
+ move_value_impl(father, L, key);
+ /* father: ...
+ L: visited table key value */
+ lua_remove(L, 1);
+ /* L: table key value */
+
+ /* prepare the return value of __index */
+ lua_pushvalue(L, -1);
+ /* L: table key value value */
+ lua_insert(L, 1);
+ /* L: value table key value */
+
+ /* save the copied value in the table for subsequent accesses */
+ lua_settable(L, -3);
+ /* L: value table */
+ lua_settop(L, 1);
+ /* L: value */
+
+ XBT_DEBUG("__index of '%s' returns %s", key, value_tostring(L, -1));
+
+ return 1;
+}
+
+/**
+ * @brief Creates a new Lua state and get its environment from an existing state.
+ *
+ * The state created is independent from the existing one and has its own
+ * copies of global variables and functions.
+ * However, the global variables and functions are not copied right now from
+ * the original state; they are copied only the first time they are accessed.
+ * This behavior saves time and memory, and is okay for Simgrid's needs.
+ *
+ * @param father an existing state
+ * @return the state created
+ */
+static lua_State* clone_lua_state(lua_State *father) {
+
+ /* create the new state */
+ lua_State *L = luaL_newstate();
+
+ /* set its environment and its registry:
+ * - create a table newenv
+ * - create a metatable mt
+ * - set mt.__index = a function that copies the global from the father state
+ * - set mt as the metatable of the registry
+ * - set mt as the metatable of newenv
+ * - set newenv as the environment of the new state
+ */
+ lua_pushthread(L); /* thread */
+ lua_newtable(L); /* thread newenv */
+ lua_newtable(L); /* thread newenv mt */
+ lua_pushvalue(L, LUA_REGISTRYINDEX); /* thread newenv mt reg */
+ lua_pushcfunction(L, l_get_from_father); /* thread newenv mt reg f */
+ lua_setfield(L, -3, "__index"); /* thread newenv mt reg */
+ lua_pushvalue(L, -2); /* thread newenv mt reg mt */
+ lua_setmetatable(L, -2); /* thread newenv mt reg */
+ lua_pop(L, 1); /* thread newenv mt */
+ lua_setmetatable(L, -2); /* thread newenv */
+ lua_setfenv(L, -2); /* thread */
+ lua_pop(L, 1); /* -- */
+
+ /* set a pointer to the father */
+ lua_pushstring(L, "simgrid.father"); /* "simgrid.father" */
+ lua_pushlightuserdata(L, father); /* "simgrid.father" father */
+ lua_rawset(L, LUA_REGISTRYINDEX);
+ /* -- */
+
+ /* create the table of visited tables from the father */
+ lua_pushstring(L, "simgrid.father_visited_tables");
+ /* "simgrid.father_visited_tables" */
+ lua_newtable(L); /* "simgrid.father_visited_tables" visited */
+ lua_rawset(L, LUA_REGISTRYINDEX);
+ /* -- */
+
+ /* create the table of my own visited tables */
+ /* TODO simgrid.father_visited_tables probably becomes useless */
+ lua_pushstring(L, "simgrid.visited_tables");
+ /* "simgrid.visited_tables" */
+ lua_newtable(L); /* "simgrid.visited_tables" visited */
+ 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);
+
+ XBT_DEBUG("New state created");
+
+ return L;
+}
+
+/*
+static void *my_checkudata (lua_State *L, int ud, const char *tname) {
+ void *p = lua_touserdata(L, ud);
+ lua_getfield(L, LUA_REGISTRYINDEX, tname);
+ const void* correct_mt = lua_topointer(L, -1);
+
+ int has_mt = lua_getmetatable(L, ud);
+ const void* actual_mt = NULL;
+ if (has_mt) { actual_mt = lua_topointer(L, -1); lua_pop(L, 1); }
+ XBT_DEBUG("Checking the task's metatable: expected %p, found %p", correct_mt, actual_mt);
+ stack_dump("my_checkudata: ", L);
+
+ if (p == NULL || !lua_getmetatable(L, ud) || !lua_rawequal(L, -1, -2))
+ luaL_typerror(L, ud, tname);
+ lua_pop(L, 2);
+ return p;
+}
+*/
+