diff options
author | Benoit Germain <benoit.germain@ubisoft.com> | 2024-06-11 17:24:30 +0200 |
---|---|---|
committer | Benoit Germain <benoit.germain@ubisoft.com> | 2024-06-11 17:24:30 +0200 |
commit | 740b820e429cf7c856f2f305b6fc5b6fd969f3b3 (patch) | |
tree | ce885dc8200ad8c7a1f6b3506db9ceedc3cc9df7 /src/cancel.cpp | |
parent | 5f5b287b4548cb21fde9ae451392d82e64cc5de7 (diff) | |
download | lanes-740b820e429cf7c856f2f305b6fc5b6fd969f3b3.tar.gz lanes-740b820e429cf7c856f2f305b6fc5b6fd969f3b3.tar.bz2 lanes-740b820e429cf7c856f2f305b6fc5b6fd969f3b3.zip |
Move some cancel-related code around
Diffstat (limited to 'src/cancel.cpp')
-rw-r--r-- | src/cancel.cpp | 113 |
1 files changed, 25 insertions, 88 deletions
diff --git a/src/cancel.cpp b/src/cancel.cpp index 4205d1f..a62fcdf 100644 --- a/src/cancel.cpp +++ b/src/cancel.cpp | |||
@@ -50,7 +50,7 @@ THE SOFTWARE. | |||
50 | * Returns CANCEL_SOFT/HARD if any locks are to be exited, and 'raise_cancel_error()' called, | 50 | * Returns CANCEL_SOFT/HARD if any locks are to be exited, and 'raise_cancel_error()' called, |
51 | * to make execution of the lane end. | 51 | * to make execution of the lane end. |
52 | */ | 52 | */ |
53 | [[nodiscard]] static inline CancelRequest cancel_test(lua_State* L_) | 53 | [[nodiscard]] CancelRequest cancel_test(lua_State* const L_) |
54 | { | 54 | { |
55 | Lane* const _lane{ kLanePointerRegKey.readLightUserDataValue<Lane>(L_) }; | 55 | Lane* const _lane{ kLanePointerRegKey.readLightUserDataValue<Lane>(L_) }; |
56 | // 'lane' is nullptr for the original main state (and no-one can cancel that) | 56 | // 'lane' is nullptr for the original main state (and no-one can cancel that) |
@@ -58,33 +58,6 @@ THE SOFTWARE. | |||
58 | } | 58 | } |
59 | 59 | ||
60 | // ################################################################################################# | 60 | // ################################################################################################# |
61 | |||
62 | //--- | ||
63 | // bool = cancel_test() | ||
64 | // | ||
65 | // Available inside the global namespace of lanes | ||
66 | // returns a boolean saying if a cancel request is pending | ||
67 | // | ||
68 | LUAG_FUNC(cancel_test) | ||
69 | { | ||
70 | CancelRequest _test{ cancel_test(L_) }; | ||
71 | lua_pushboolean(L_, _test != CancelRequest::None); | ||
72 | return 1; | ||
73 | } | ||
74 | |||
75 | // ################################################################################################# | ||
76 | // ################################################################################################# | ||
77 | |||
78 | [[nodiscard]] static void cancel_hook(lua_State* L_, [[maybe_unused]] lua_Debug* ar_) | ||
79 | { | ||
80 | DEBUGSPEW_CODE(DebugSpew(nullptr) << "cancel_hook" << std::endl); | ||
81 | if (cancel_test(L_) != CancelRequest::None) { | ||
82 | lua_sethook(L_, nullptr, 0, 0); | ||
83 | raise_cancel_error(L_); | ||
84 | } | ||
85 | } | ||
86 | |||
87 | // ################################################################################################# | ||
88 | // ################################################################################################# | 61 | // ################################################################################################# |
89 | 62 | ||
90 | //--- | 63 | //--- |
@@ -105,64 +78,9 @@ LUAG_FUNC(cancel_test) | |||
105 | // | 78 | // |
106 | 79 | ||
107 | // ################################################################################################# | 80 | // ################################################################################################# |
108 | |||
109 | [[nodiscard]] static CancelResult thread_cancel_soft(Lane* lane_, std::chrono::time_point<std::chrono::steady_clock> until_, bool wakeLane_) | ||
110 | { | ||
111 | lane_->cancelRequest = CancelRequest::Soft; // it's now signaled to stop | ||
112 | // negative timeout: we don't want to truly abort the lane, we just want it to react to cancel_test() on its own | ||
113 | if (wakeLane_) { // wake the thread so that execution returns from any pending linda operation if desired | ||
114 | std::condition_variable* const _waiting_on{ lane_->waiting_on }; | ||
115 | if (lane_->status == Lane::Waiting && _waiting_on != nullptr) { | ||
116 | _waiting_on->notify_all(); | ||
117 | } | ||
118 | } | ||
119 | |||
120 | return lane_->waitForCompletion(until_) ? CancelResult::Cancelled : CancelResult::Timeout; | ||
121 | } | ||
122 | |||
123 | // ################################################################################################# | 81 | // ################################################################################################# |
124 | 82 | ||
125 | [[nodiscard]] static CancelResult thread_cancel_hard(Lane* lane_, std::chrono::time_point<std::chrono::steady_clock> until_, bool wakeLane_) | 83 | CancelOp WhichCancelOp(std::string_view const& opString_) |
126 | { | ||
127 | lane_->cancelRequest = CancelRequest::Hard; // it's now signaled to stop | ||
128 | // lane_->thread.get_stop_source().request_stop(); | ||
129 | if (wakeLane_) { // wake the thread so that execution returns from any pending linda operation if desired | ||
130 | std::condition_variable* const _waiting_on{ lane_->waiting_on }; | ||
131 | if (lane_->status == Lane::Waiting && _waiting_on != nullptr) { | ||
132 | _waiting_on->notify_all(); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | CancelResult result{ lane_->waitForCompletion(until_) ? CancelResult::Cancelled : CancelResult::Timeout }; | ||
137 | return result; | ||
138 | } | ||
139 | |||
140 | // ################################################################################################# | ||
141 | |||
142 | CancelResult thread_cancel(Lane* lane_, CancelOp op_, int hookCount_, std::chrono::time_point<std::chrono::steady_clock> until_, bool wakeLane_) | ||
143 | { | ||
144 | // remember that lanes are not transferable: only one thread can cancel a lane, so no multithreading issue here | ||
145 | // We can read 'lane_->status' without locks, but not wait for it (if Posix no PTHREAD_TIMEDJOIN) | ||
146 | if (lane_->status >= Lane::Done) { | ||
147 | // say "ok" by default, including when lane is already done | ||
148 | return CancelResult::Cancelled; | ||
149 | } | ||
150 | |||
151 | // signal the linda the wake up the thread so that it can react to the cancel query | ||
152 | // let us hope we never land here with a pointer on a linda that has been destroyed... | ||
153 | if (op_ == CancelOp::Soft) { | ||
154 | return thread_cancel_soft(lane_, until_, wakeLane_); | ||
155 | } else if (static_cast<int>(op_) > static_cast<int>(CancelOp::Soft)) { | ||
156 | lua_sethook(lane_->L, cancel_hook, static_cast<int>(op_), hookCount_); | ||
157 | } | ||
158 | |||
159 | return thread_cancel_hard(lane_, until_, wakeLane_); | ||
160 | } | ||
161 | |||
162 | // ################################################################################################# | ||
163 | // ################################################################################################# | ||
164 | |||
165 | CancelOp which_cancel_op(std::string_view const& opString_) | ||
166 | { | 84 | { |
167 | CancelOp _op{ CancelOp::Invalid }; | 85 | CancelOp _op{ CancelOp::Invalid }; |
168 | if (opString_ == "hard") { | 86 | if (opString_ == "hard") { |
@@ -183,11 +101,11 @@ CancelOp which_cancel_op(std::string_view const& opString_) | |||
183 | 101 | ||
184 | // ################################################################################################# | 102 | // ################################################################################################# |
185 | 103 | ||
186 | [[nodiscard]] static CancelOp which_cancel_op(lua_State* L_, int idx_) | 104 | [[nodiscard]] static CancelOp WhichCancelOp(lua_State* const L_, int const idx_) |
187 | { | 105 | { |
188 | if (luaG_type(L_, idx_) == LuaType::STRING) { | 106 | if (luaG_type(L_, idx_) == LuaType::STRING) { |
189 | std::string_view const _str{ luaG_tostring(L_, idx_) }; | 107 | std::string_view const _str{ luaG_tostring(L_, idx_) }; |
190 | CancelOp _op{ which_cancel_op(_str) }; | 108 | CancelOp _op{ WhichCancelOp(_str) }; |
191 | lua_remove(L_, idx_); // argument is processed, remove it | 109 | lua_remove(L_, idx_); // argument is processed, remove it |
192 | if (_op == CancelOp::Invalid) { | 110 | if (_op == CancelOp::Invalid) { |
193 | raise_luaL_error(L_, "invalid hook option %s", _str); | 111 | raise_luaL_error(L_, "invalid hook option %s", _str); |
@@ -198,12 +116,31 @@ CancelOp which_cancel_op(std::string_view const& opString_) | |||
198 | } | 116 | } |
199 | 117 | ||
200 | // ################################################################################################# | 118 | // ################################################################################################# |
119 | // ################################################################################################# | ||
120 | // ######################################### Lua API ############################################### | ||
121 | // ################################################################################################# | ||
122 | // ################################################################################################# | ||
123 | |||
124 | //--- | ||
125 | // bool = cancel_test() | ||
126 | // | ||
127 | // Available inside the global namespace of a lane | ||
128 | // returns a boolean saying if a cancel request is pending | ||
129 | // | ||
130 | LUAG_FUNC(cancel_test) | ||
131 | { | ||
132 | CancelRequest _test{ cancel_test(L_) }; | ||
133 | lua_pushboolean(L_, _test != CancelRequest::None); | ||
134 | return 1; | ||
135 | } | ||
136 | |||
137 | // ################################################################################################# | ||
201 | 138 | ||
202 | // bool[,reason] = lane_h:cancel( [mode, hookcount] [, timeout] [, wake_lane]) | 139 | // bool[,reason] = lane_h:cancel( [mode, hookcount] [, timeout] [, wake_lane]) |
203 | LUAG_FUNC(thread_cancel) | 140 | LUAG_FUNC(thread_cancel) |
204 | { | 141 | { |
205 | Lane* const _lane{ ToLane(L_, 1) }; | 142 | Lane* const _lane{ ToLane(L_, 1) }; |
206 | CancelOp const _op{ which_cancel_op(L_, 2) }; // this removes the op string from the stack | 143 | CancelOp const _op{ WhichCancelOp(L_, 2) }; // this removes the op string from the stack |
207 | 144 | ||
208 | int _hook_count{ 0 }; | 145 | int _hook_count{ 0 }; |
209 | if (static_cast<int>(_op) > static_cast<int>(CancelOp::Soft)) { // hook is requested | 146 | if (static_cast<int>(_op) > static_cast<int>(CancelOp::Soft)) { // hook is requested |
@@ -237,7 +174,7 @@ LUAG_FUNC(thread_cancel) | |||
237 | lua_remove(L_, 2); // argument is processed, remove it | 174 | lua_remove(L_, 2); // argument is processed, remove it |
238 | } | 175 | } |
239 | STACK_CHECK_START_REL(L_, 0); | 176 | STACK_CHECK_START_REL(L_, 0); |
240 | switch (thread_cancel(_lane, _op, _hook_count, _until, _wake_lane)) { | 177 | switch (_lane->cancel(_op, _hook_count, _until, _wake_lane)) { |
241 | default: // should never happen unless we added a case and forgot to handle it | 178 | default: // should never happen unless we added a case and forgot to handle it |
242 | LUA_ASSERT(L_, false); | 179 | LUA_ASSERT(L_, false); |
243 | break; | 180 | break; |