aboutsummaryrefslogtreecommitdiff
path: root/src/cancel.cpp
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2024-06-11 17:24:30 +0200
committerBenoit Germain <benoit.germain@ubisoft.com>2024-06-11 17:24:30 +0200
commit740b820e429cf7c856f2f305b6fc5b6fd969f3b3 (patch)
treece885dc8200ad8c7a1f6b3506db9ceedc3cc9df7 /src/cancel.cpp
parent5f5b287b4548cb21fde9ae451392d82e64cc5de7 (diff)
downloadlanes-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.cpp113
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//
68LUAG_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_) 83CancelOp 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
142CancelResult 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
165CancelOp 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//
130LUAG_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])
203LUAG_FUNC(thread_cancel) 140LUAG_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;