+
+ /* pop the value from src */
+ lua_pop(src, 1);
+
+ stack_dump("src after copying a value (should be ...): ", src);
+ stack_dump("dst after copying a value (should be visited ... value): ", dst);
+}
+
+/**
+ * @brief Copies a global 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 (usually the environment of L) and the string key of a value
+ * that does not exist yet in this table. It copies the corresponding global
+ * value from the father state and pushes it on the stack of L.
+ * If the global 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) {
+
+ /* retrieve the father */
+ lua_getfield(L, LUA_REGISTRYINDEX, "simgrid.father_state");
+ lua_State* father = lua_touserdata(L, -1);
+ xbt_assert(father != NULL, "This Lua state has no father");
+ lua_pop(L, 1);
+
+ /* get the global from the father */
+ const char* key = luaL_checkstring(L, 2); /* L: table key */
+ lua_getglobal(father, key); /* father: ... value */
+ XBT_DEBUG("__index of '%s' begins", key);
+
+ /* push the value onto the stack of L */
+ lua_newtable(L); /* L: table key visited */
+ lua_insert(L, 1); /* L: visited table key */
+ move_value(L, father, 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_remove(L, 2); /* 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:
+ * - 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 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_pushcfunction(L, l_get_from_father); /* thread newenv mt f */
+ lua_setfield(L, -2, "__index"); /* thread newenv mt */
+ lua_setmetatable(L, -2); /* thread newenv */
+ lua_setfenv(L, -2); /* thread */
+ lua_pop(L, 1); /* -- */
+
+ /* open the standard libs (theoretically, this is not necessary) */
+ luaL_openlibs(L);
+
+ /* put a pointer to the father */
+ lua_pushlightuserdata(L, father);
+ lua_setfield(L, LUA_REGISTRYINDEX, "simgrid.father_state");
+
+ XBT_DEBUG("New state created");
+
+ return L;