Implement minetest.ipc_poll()
This commit is contained in:
parent
72801d0233
commit
d2b4c27f21
@ -7077,6 +7077,15 @@ minetest.ipc_get("test:foo") -- returns an empty table
|
|||||||
* `old_value`: value compared to using `==` (`nil` compares equal for non-existing keys)
|
* `old_value`: value compared to using `==` (`nil` compares equal for non-existing keys)
|
||||||
* `new_value`: value that will be set
|
* `new_value`: value that will be set
|
||||||
* returns: true on success, false otherwise
|
* returns: true on success, false otherwise
|
||||||
|
* `minetest.ipc_poll(key, timeout)`:
|
||||||
|
* Do a blocking wait until a value (other than `nil`) is present at the key.
|
||||||
|
* **IMPORTANT**: You usually don't need this function. Use this as a last resort
|
||||||
|
if nothing else can satisfy your use case! None of the Lua environments the
|
||||||
|
engine has are safe to block for extended periods, especially on the main
|
||||||
|
thread any delays directly translate to lag felt by players.
|
||||||
|
* `key`: as above
|
||||||
|
* `timeout`: maximum wait time, in milliseconds (positive values only)
|
||||||
|
* returns: true on success, false on timeout
|
||||||
|
|
||||||
Bans
|
Bans
|
||||||
----
|
----
|
||||||
|
@ -279,3 +279,18 @@ local function test_ipc_vector_preserve(cb)
|
|||||||
assert(vector.check(v))
|
assert(vector.check(v))
|
||||||
end
|
end
|
||||||
unittests.register("test_ipc_vector_preserve", test_ipc_vector_preserve)
|
unittests.register("test_ipc_vector_preserve", test_ipc_vector_preserve)
|
||||||
|
|
||||||
|
local function test_ipc_poll(cb)
|
||||||
|
core.ipc_set("unittests:flag", nil)
|
||||||
|
assert(core.ipc_poll("unittests:flag", 1) == false)
|
||||||
|
|
||||||
|
-- Note that unlike the async result callback - which has to wait for the
|
||||||
|
-- next server step - the IPC is instant
|
||||||
|
local t0 = core.get_us_time()
|
||||||
|
core.handle_async(function()
|
||||||
|
core.ipc_set("unittests:flag", true)
|
||||||
|
end, function() end)
|
||||||
|
assert(core.ipc_poll("unittests:flag", 1000) == true, "Wait failed (or slow machine?)")
|
||||||
|
print("delta: " .. (core.get_us_time() - t0) .. "us")
|
||||||
|
end
|
||||||
|
unittests.register("test_ipc_poll", test_ipc_poll)
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "common/c_packer.h"
|
#include "common/c_packer.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
typedef std::shared_lock<std::shared_mutex> SharedReadLock;
|
typedef std::shared_lock<std::shared_mutex> SharedReadLock;
|
||||||
typedef std::unique_lock<std::shared_mutex> SharedWriteLock;
|
typedef std::unique_lock<std::shared_mutex> SharedWriteLock;
|
||||||
@ -54,6 +55,7 @@ int ModApiIPC::l_ipc_set(lua_State *L)
|
|||||||
else
|
else
|
||||||
store->map.erase(key); // delete the map value for nil
|
store->map.erase(key); // delete the map value for nil
|
||||||
}
|
}
|
||||||
|
store->signal();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,10 +91,37 @@ int ModApiIPC::l_ipc_cas(lua_State *L)
|
|||||||
store->map.erase(key);
|
store->map.erase(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ok)
|
||||||
|
store->signal();
|
||||||
lua_pushboolean(L, ok);
|
lua_pushboolean(L, ok);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ModApiIPC::l_ipc_poll(lua_State *L)
|
||||||
|
{
|
||||||
|
auto *store = getGameDef(L)->getModIPCStore();
|
||||||
|
|
||||||
|
auto key = readParam<std::string>(L, 1);
|
||||||
|
|
||||||
|
auto timeout = std::chrono::milliseconds(
|
||||||
|
std::max<int>(0, luaL_checkinteger(L, 2))
|
||||||
|
);
|
||||||
|
|
||||||
|
bool ret;
|
||||||
|
{
|
||||||
|
SharedReadLock autolock(store->mutex);
|
||||||
|
|
||||||
|
// wait until value exists or timeout
|
||||||
|
ret = store->condvar.wait_for(autolock, timeout, [&] () -> bool {
|
||||||
|
return store->map.count(key) != 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pushboolean(L, ret);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Implementation note:
|
* Implementation note:
|
||||||
* Iterating over the IPC table is intentionally not supported.
|
* Iterating over the IPC table is intentionally not supported.
|
||||||
@ -108,4 +137,5 @@ void ModApiIPC::Initialize(lua_State *L, int top)
|
|||||||
API_FCT(ipc_get);
|
API_FCT(ipc_get);
|
||||||
API_FCT(ipc_set);
|
API_FCT(ipc_set);
|
||||||
API_FCT(ipc_cas);
|
API_FCT(ipc_cas);
|
||||||
|
API_FCT(ipc_poll);
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ private:
|
|||||||
static int l_ipc_get(lua_State *L);
|
static int l_ipc_get(lua_State *L);
|
||||||
static int l_ipc_set(lua_State *L);
|
static int l_ipc_set(lua_State *L);
|
||||||
static int l_ipc_cas(lua_State *L);
|
static int l_ipc_cas(lua_State *L);
|
||||||
|
static int l_ipc_poll(lua_State *L);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void Initialize(lua_State *L, int top);
|
static void Initialize(lua_State *L, int top);
|
||||||
|
@ -48,6 +48,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <shared_mutex>
|
#include <shared_mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
class ChatEvent;
|
class ChatEvent;
|
||||||
struct ChatEventChat;
|
struct ChatEventChat;
|
||||||
@ -149,12 +150,17 @@ struct ModIPCStore {
|
|||||||
|
|
||||||
/// RW lock for this entire structure
|
/// RW lock for this entire structure
|
||||||
std::shared_mutex mutex;
|
std::shared_mutex mutex;
|
||||||
|
/// Signalled on any changes to the map contents
|
||||||
|
std::condition_variable_any condvar;
|
||||||
/**
|
/**
|
||||||
* Map storing the data
|
* Map storing the data
|
||||||
*
|
*
|
||||||
* @note Do not store `nil` data in this map, instead remove the whole key.
|
* @note Do not store `nil` data in this map, instead remove the whole key.
|
||||||
*/
|
*/
|
||||||
std::unordered_map<std::string, std::unique_ptr<PackedValue>> map;
|
std::unordered_map<std::string, std::unique_ptr<PackedValue>> map;
|
||||||
|
|
||||||
|
/// @note Should be called without holding the lock.
|
||||||
|
inline void signal() { condvar.notify_all(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Server : public con::PeerHandler, public MapEventReceiver,
|
class Server : public con::PeerHandler, public MapEventReceiver,
|
||||||
|
Loading…
Reference in New Issue
Block a user