Add minetest.ipc_swap

This commit is contained in:
sfan5 2024-05-15 16:18:43 +02:00
parent dfe0f1b7d7
commit aa9057218b
4 changed files with 32 additions and 11 deletions

View File

@ -6897,10 +6897,13 @@ different Lua environments (main, mapgen and async).
* Write a value to the shared data area.
* `key`: as above
* `value`: an arbitrary Lua value, cannot be or contain userdata.
* `minetest.ipc_swap(key, value)`:
* Like `minetest.ipc_set` but returns the value that was at the same key
before writing the new one. This is atomic.
Interacting with the shared data will perform an operation comparable to
(de)serialization.
Modifying references will not do anything, as in this example:
Modifying references will not have any effect, as in this example:
```lua
minetest.ipc_set("test:foo", {})
minetest.ipc_get("test:foo").subkey = "value"

View File

@ -22,8 +22,11 @@ local function do_tests()
assert(core.registered_items["unittests:description_test"].on_place == true)
end
-- this is checked from the main env
core.ipc_set("unittests:mg", { pcall(do_tests) })
-- first thread to get here runs the tests
if core.ipc_swap("unittests:mg_once", 1) == nil then
-- this is checked from the main env
core.ipc_set("unittests:mg", { pcall(do_tests) })
end
core.register_on_generated(function(vm, pos1, pos2, blockseed)
local n = tonumber(core.get_mapgen_setting("chunksize")) * 16 - 1

View File

@ -27,26 +27,38 @@ int ModApiIPC::l_ipc_get(lua_State *L)
return 1;
}
int ModApiIPC::l_ipc_set(lua_State *L)
int ModApiIPC::ipc_put(lua_State *L, bool push_old)
{
auto *store = getGameDef(L)->getModIPCStore();
auto key = readParam<std::string>(L, 1);
std::unique_ptr<PackedValue> vnew, vold;
luaL_checkany(L, 2);
std::unique_ptr<PackedValue> pv;
if (!lua_isnil(L, 2)) {
pv.reset(script_pack(L, 2));
if (pv->contains_userdata)
vnew.reset(script_pack(L, 2));
if (vnew->contains_userdata)
throw LuaError("Userdata not allowed");
}
{
SharedWriteLock autolock(store->mutex);
if (pv)
store->map[key] = std::move(pv);
auto it = store->map.find(key);
if (it == store->map.end()) {
[[maybe_unused]] auto r = store->map.emplace(std::move(key), std::move(vnew));
assert(r.second);
} else {
vold = std::move(it->second);
it->second = std::move(vnew);
}
}
if (push_old) {
if (vold)
script_unpack(L, vold.get());
else
store->map.erase(key); // delete the map value for nil
lua_pushnil(L);
return 1;
}
return 0;
}
@ -65,4 +77,5 @@ void ModApiIPC::Initialize(lua_State *L, int top)
API_FCT(ipc_get);
API_FCT(ipc_set);
API_FCT(ipc_swap);
}

View File

@ -8,7 +8,9 @@
class ModApiIPC : public ModApiBase {
private:
static int l_ipc_get(lua_State *L);
static int l_ipc_set(lua_State *L);
static int ipc_put(lua_State *L, bool push_old);
static int l_ipc_set(lua_State *L) { return ipc_put(L, false); }
static int l_ipc_swap(lua_State *L) { return ipc_put(L, true); }
public:
static void Initialize(lua_State *L, int top);