35#include <unordered_map>
42class TOAST_API LuaState {
47 class TOAST_API Lock {
50 Lock(Lock&& other)
noexcept;
51 auto operator=(Lock&& other)
noexcept -> Lock&;
52 Lock(
const Lock&) =
delete;
53 auto operator=(
const Lock&) -> Lock& =
delete;
56 explicit operator bool()
const noexcept {
return m_entry !=
nullptr; }
59 auto state()
const noexcept -> lua_State* {
64 auto index()
const noexcept ->
size_t {
72 friend class LuaState;
73 Lock(Entry* entry, lua_State* state,
size_t index)
noexcept;
75 Entry* m_entry =
nullptr;
76 lua_State* m_state =
nullptr;
80 static auto create() noexcept -> std::unique_ptr<LuaState>;
81 static auto get() noexcept -> LuaState&;
84 static auto exists() noexcept ->
bool {
85 return instance !=
nullptr;
97 auto lock(
size_t index) noexcept -> Lock;
101 auto tryLock(
size_t index) noexcept -> Lock;
104 static auto indexOf(lua_State* state) noexcept -> std::optional<
size_t>;
108 static auto ownedByCurrentThread(
size_t index) noexcept ->
bool;
110 static auto ownedByCurrentThread(lua_State* state) noexcept ->
bool;
114 static auto ownsAnyState() noexcept ->
bool;
118 static auto lastOwnedIndex() noexcept -> std::optional<
size_t>;
136 auto
assign(uint64_t group, std::optional<
size_t> forced = std::nullopt) ->
size_t;
139 void unassign(uint64_t group,
size_t index) noexcept;
143 auto
loads() const -> std::vector<uint32_t>;
147 static auto
newGroup() noexcept -> uint64_t;
150 auto poolSize() const noexcept ->
size_t {
156 auto mainState(
size_t index)
const noexcept -> lua_State*;
163 void retire(
size_t index, std::move_only_function<
void()> destroyer)
noexcept;
166 static void retireOrLeak(
size_t index, std::move_only_function<
void()> destroyer)
noexcept;
171 return m_contention.load(std::memory_order_relaxed);
177 return m_waits.load(std::memory_order_relaxed);
183 class TOAST_API NonBlockingScope {
185 NonBlockingScope()
noexcept;
188 NonBlockingScope(
const NonBlockingScope&) =
delete;
189 auto operator=(
const NonBlockingScope&) -> NonBlockingScope& =
delete;
190 NonBlockingScope(NonBlockingScope&&) =
delete;
191 auto operator=(NonBlockingScope&&) -> NonBlockingScope& =
delete;
195 auto runString(std::string_view lua_code)
noexcept -> bool;
198 auto runStringOn(
size_t index, std::string_view lua_code, std::string* error =
nullptr) noexcept ->
bool;
204 static inline LuaState* instance =
nullptr;
207 lua_State* state =
nullptr;
208 std::recursive_mutex mutex;
209 std::atomic<uint64_t> owner {0};
211 std::mutex pending_mutex;
212 std::vector<std::move_only_function<void()>> pending;
213 std::atomic<size_t> pending_count {0};
216 size_t m_pool_size = 0;
217 std::vector<Entry> m_entries;
218 std::atomic<uint64_t> m_contention {0};
219 std::atomic<uint64_t> m_waits {0};
222 struct GroupPlacement {
223 std::vector<uint32_t> per_index;
225 uint32_t members = 0;
229 mutable std::mutex m_placement_mutex;
230 std::vector<uint32_t> m_loads;
231 std::unordered_map<uint64_t, GroupPlacement> m_groups;
232 size_t m_next_tie = 0;
236 auto acquire(
size_t index,
bool wait)
noexcept -> Lock;
237 static void release(Entry& entry,
size_t index)
noexcept;
238 static void drainPending(Entry& entry)
noexcept;
240 static void registerApi(lua_State* state)
noexcept;
241 static void registerTypeMarkers(lua_State* state)
noexcept;
250#define TOAST_LUA_ASSERT_OWNED(state) \
252 ::scripting::LuaState::ownedByCurrentThread(state), "Lua", "A Lua interpreter was used by a thread that does not own it" \
254#elif defined(TOAST_LUA_OWNERSHIP_CHECKS)
255#define TOAST_LUA_ASSERT_OWNED(state) \
257 if (!::scripting::LuaState::ownedByCurrentThread(state)) { \
258 TOAST_CRITICAL("Lua", "A Lua interpreter was used by a thread that does not own it"); \
262#define TOAST_LUA_ASSERT_OWNED(state) ((void)(state))
void unlock() noexcept
Gives the interpreter back before the end of the scope.
Definition lua_state.cpp:211
Definition lua_state.hpp:42
static auto newGroup() noexcept -> uint64_t
Allocates the number of a new script group, never zero.
Definition lua_state.cpp:450
auto assign(uint64_t group, std::optional< size_t > forced=std::nullopt) -> size_t
Picks the interpreter for a new script runtime.
Definition lua_state.cpp:378
auto waitCount() const noexcept -> uint64_t
How many times a thread had to wait for an interpreter that another thread owned.
Definition lua_state.hpp:176
void refreshTypeMarkers() noexcept
Re-registers the Node/Asset type-marker globals on every state.
Definition lua_state.cpp:1341
void unassign(uint64_t group, size_t index) noexcept
Gives back what assign() handed out.
Definition lua_state.cpp:429
auto runStringOn(size_t index, std::string_view lua_code, std::string *error=nullptr) noexcept -> bool
Runs a chunk on the given interpreter.
Definition lua_state.cpp:459
auto runString(std::string_view lua_code) noexcept -> bool
Runs a chunk on state 0; intended for debug/console use.
Definition lua_state.cpp:455
auto loads() const -> std::vector< uint32_t >
How many runtimes every interpreter hosts, for diagnostics and tests.
Definition lua_state.cpp:424
auto contentionCount() const noexcept -> uint64_t
How many times a thread that owned an interpreter found another one busy; non zero means work was que...
Definition lua_state.hpp:170
static constexpr uint32_t k_group_chunk
How many runtimes of one script group share an interpreter before the next ones go to another.
Definition lua_state.hpp:121
Public logging interface for the engine.
Thread pool implementation for parallel task execution.
@ release
the input went from on to off
Definition value.hpp:79