aboutsummaryrefslogtreecommitdiff
path: root/src/lane.h
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2024-05-14 14:15:01 +0200
committerBenoit Germain <benoit.germain@ubisoft.com>2024-05-14 14:15:01 +0200
commit9589d1941671818f78d9894cfc9485054d62d122 (patch)
treec804998ba5cf89b75cb3d27052ee469fd4986595 /src/lane.h
parent1013970853e6acfd60591a89ae08cc40c64bee06 (diff)
downloadlanes-9589d1941671818f78d9894cfc9485054d62d122.tar.gz
lanes-9589d1941671818f78d9894cfc9485054d62d122.tar.bz2
lanes-9589d1941671818f78d9894cfc9485054d62d122.zip
Move Lane implementation in a separate file
Diffstat (limited to 'src/lane.h')
-rw-r--r--src/lane.h140
1 files changed, 140 insertions, 0 deletions
diff --git a/src/lane.h b/src/lane.h
new file mode 100644
index 0000000..f28a402
--- /dev/null
+++ b/src/lane.h
@@ -0,0 +1,140 @@
1#pragma once
2
3#include "cancel.h"
4#include "uniquekey.h"
5#include "universe.h"
6
7#include <chrono>
8#include <condition_variable>
9#include <latch>
10#include <stop_token>
11#include <thread>
12
13// #################################################################################################
14
15/*
16 * registry[FINALIZER_REG_KEY] is either nil (no finalizers) or a table
17 * of functions that Lanes will call after the executing 'pcall' has ended.
18 *
19 * We're NOT using the GC system for finalizer mainly because providing the
20 * error (and maybe stack trace) parameters to the finalizer functions would
21 * anyways complicate that approach.
22 */
23// xxh64 of string "kFinalizerRegKey" generated at https://www.pelock.com/products/hash-calculator
24static constexpr RegistryUniqueKey kFinalizerRegKey{ 0xFE936BFAA718FEEAull };
25
26// xxh64 of string "kExtendedStackTraceRegKey" generated at https://www.pelock.com/products/hash-calculator
27static constexpr RegistryUniqueKey kExtendedStackTraceRegKey{ 0x38147AD48FB426E2ull }; // used as registry key
28
29// xxh64 of string "kLaneGC" generated at https://www.pelock.com/products/hash-calculator
30static constexpr UniqueKey kLaneGC{ 0x5D6122141727F960ull };
31
32// xxh64 of string "kLanePointerRegKey" generated at https://www.pelock.com/products/hash-calculator
33static constexpr RegistryUniqueKey kLanePointerRegKey{ 0x2D8CF03FE9F0A51Aull }; // used as registry key
34
35// #################################################################################################
36
37// The chain is ended by '(Lane*)(-1)', not nullptr: 'selfdestructFirst -> ... -> ... -> (-1)'
38#define SELFDESTRUCT_END ((Lane*) (-1))
39
40// must be a #define instead of a constexpr to work with lua_pushliteral (until I templatize it)
41#define kLaneMetatableName "Lane"
42#define kLanesLibName "lanes"
43#define kLanesCoreLibName kLanesLibName ".core"
44
45// NOTE: values to be changed by either thread, during execution, without
46// locking, are marked "volatile"
47//
48class Lane
49{
50 public:
51 /*
52 Pending: The Lua VM hasn't done anything yet.
53 Running, Waiting: Thread is inside the Lua VM. If the thread is forcefully stopped, we can't lua_close() the Lua State.
54 Done, Error, Cancelled: Thread execution is outside the Lua VM. It can be lua_close()d.
55 */
56 enum class Status
57 {
58 Pending,
59 Running,
60 Waiting,
61 Done,
62 Error,
63 Cancelled
64 };
65 using enum Status;
66
67 // the thread
68 std::jthread thread;
69 // a latch to wait for the lua_State to be ready
70 std::latch ready{ 1 };
71 // to wait for stop requests through thread's stop_source
72 std::mutex doneMutex;
73 std::condition_variable doneCondVar; // use condition_variable_any if waiting for a stop_token
74 //
75 // M: sub-thread OS thread
76 // S: not used
77
78 char const* debugName{ "<unnamed>" };
79
80 Universe* const U;
81 lua_State* L;
82 //
83 // M: prepares the state, and reads results
84 // S: while S is running, M must keep out of modifying the state
85
86 Status volatile status{ Pending };
87 //
88 // M: sets to Pending (before launching)
89 // S: updates -> Running/Waiting -> Done/Error/Cancelled
90
91 std::condition_variable* volatile waiting_on{ nullptr };
92 //
93 // When status is Waiting, points on the linda's signal the thread waits on, else nullptr
94
95 CancelRequest volatile cancelRequest{ CancelRequest::None };
96 //
97 // M: sets to false, flags true for cancel request
98 // S: reads to see if cancel is requested
99
100 Lane* volatile selfdestruct_next{ nullptr };
101 //
102 // M: sets to non-nullptr if facing lane handle '__gc' cycle but the lane
103 // is still running
104 // S: cleans up after itself if non-nullptr at lane exit
105
106#if HAVE_LANE_TRACKING()
107 Lane* volatile tracking_next{ nullptr };
108#endif // HAVE_LANE_TRACKING()
109 //
110 // For tracking only
111
112 [[nodiscard]] static void* operator new(size_t size_, Universe* U_) noexcept { return U_->internalAllocator.alloc(size_); }
113 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception
114 static void operator delete(void* p_, Universe* U_) { U_->internalAllocator.free(p_, sizeof(Lane)); }
115 // this one is for us, to make sure memory is freed by the correct allocator
116 static void operator delete(void* p_) { static_cast<Lane*>(p_)->U->internalAllocator.free(p_, sizeof(Lane)); }
117
118 Lane(Universe* U_, lua_State* L_);
119 ~Lane();
120
121 void changeDebugName(int nameIdx_);
122 void pushThreadStatus(lua_State* L_) const;
123 void securizeDebugName(lua_State* L_);
124 void startThread(int priority_);
125 char const* threadStatusString() const;
126 [[nodiscard]] bool waitForCompletion(std::chrono::time_point<std::chrono::steady_clock> until_);
127
128 static void PushMetatable(lua_State* L_);
129};
130
131// #################################################################################################
132
133// To allow free-running threads (longer lifespan than the handle's)
134// 'Lane' are malloc/free'd and the handle only carries a pointer.
135// This is not deep userdata since the handle's not portable among lanes.
136//
137[[nodiscard]] inline Lane* ToLane(lua_State* L_, int i_)
138{
139 return *(static_cast<Lane**>(luaL_checkudata(L_, i_, kLaneMetatableName)));
140}