diff options
Diffstat (limited to '')
-rw-r--r-- | src/cancel.cpp | 117 |
1 files changed, 56 insertions, 61 deletions
diff --git a/src/cancel.cpp b/src/cancel.cpp index c0867a9..8b8977b 100644 --- a/src/cancel.cpp +++ b/src/cancel.cpp | |||
@@ -55,9 +55,9 @@ THE SOFTWARE. | |||
55 | */ | 55 | */ |
56 | static inline CancelRequest cancel_test(lua_State* L) | 56 | static inline CancelRequest cancel_test(lua_State* L) |
57 | { | 57 | { |
58 | Lane* const s = get_lane_from_registry( L); | 58 | Lane* const lane{ get_lane_from_registry(L) }; |
59 | // 's' is nullptr for the original main state (and no-one can cancel that) | 59 | // 's' is nullptr for the original main state (and no-one can cancel that) |
60 | return s ? s->cancel_request : CancelRequest::None; | 60 | return lane ? lane->cancel_request : CancelRequest::None; |
61 | } | 61 | } |
62 | 62 | ||
63 | // ################################################################################################ | 63 | // ################################################################################################ |
@@ -111,38 +111,36 @@ static void cancel_hook(lua_State* L, [[maybe_unused]] lua_Debug* ar) | |||
111 | 111 | ||
112 | // ################################################################################################ | 112 | // ################################################################################################ |
113 | 113 | ||
114 | static CancelResult thread_cancel_soft(Lane* s, double secs_, bool wake_lindas_) | 114 | static CancelResult thread_cancel_soft(Lane* lane_, double secs_, bool wake_lindas_) |
115 | { | 115 | { |
116 | s->cancel_request = CancelRequest::Soft; // it's now signaled to stop | 116 | lane_->cancel_request = CancelRequest::Soft; // it's now signaled to stop |
117 | // negative timeout: we don't want to truly abort the lane, we just want it to react to cancel_test() on its own | 117 | // negative timeout: we don't want to truly abort the lane, we just want it to react to cancel_test() on its own |
118 | if( wake_lindas_) // wake the thread so that execution returns from any pending linda operation if desired | 118 | if (wake_lindas_) // wake the thread so that execution returns from any pending linda operation if desired |
119 | { | 119 | { |
120 | SIGNAL_T* waiting_on = s->waiting_on; | 120 | SIGNAL_T* const waiting_on{ lane_->waiting_on }; |
121 | if( s->status == WAITING && waiting_on != nullptr) | 121 | if (lane_->status == WAITING && waiting_on != nullptr) |
122 | { | 122 | { |
123 | SIGNAL_ALL( waiting_on); | 123 | SIGNAL_ALL( waiting_on); |
124 | } | 124 | } |
125 | } | 125 | } |
126 | 126 | ||
127 | return THREAD_WAIT(&s->thread, secs_, &s->done_signal, &s->done_lock, &s->status) ? CancelResult::Cancelled : CancelResult::Timeout; | 127 | return THREAD_WAIT(&lane_->thread, secs_, &lane_->done_signal, &lane_->done_lock, &lane_->status) ? CancelResult::Cancelled : CancelResult::Timeout; |
128 | } | 128 | } |
129 | 129 | ||
130 | // ################################################################################################ | 130 | // ################################################################################################ |
131 | 131 | ||
132 | static CancelResult thread_cancel_hard(lua_State* L, Lane* s, double secs_, bool force_, double waitkill_timeout_) | 132 | static CancelResult thread_cancel_hard(lua_State* L, Lane* lane_, double secs_, bool force_, double waitkill_timeout_) |
133 | { | 133 | { |
134 | CancelResult result; | 134 | lane_->cancel_request = CancelRequest::Hard; // it's now signaled to stop |
135 | |||
136 | s->cancel_request = CancelRequest::Hard; // it's now signaled to stop | ||
137 | { | 135 | { |
138 | SIGNAL_T* waiting_on = s->waiting_on; | 136 | SIGNAL_T* waiting_on = lane_->waiting_on; |
139 | if( s->status == WAITING && waiting_on != nullptr) | 137 | if (lane_->status == WAITING && waiting_on != nullptr) |
140 | { | 138 | { |
141 | SIGNAL_ALL( waiting_on); | 139 | SIGNAL_ALL( waiting_on); |
142 | } | 140 | } |
143 | } | 141 | } |
144 | 142 | ||
145 | result = THREAD_WAIT(&s->thread, secs_, &s->done_signal, &s->done_lock, &s->status) ? CancelResult::Cancelled : CancelResult::Timeout; | 143 | CancelResult result{ THREAD_WAIT(&lane_->thread, secs_, &lane_->done_signal, &lane_->done_lock, &lane_->status) ? CancelResult::Cancelled : CancelResult::Timeout }; |
146 | 144 | ||
147 | if ((result == CancelResult::Timeout) && force_) | 145 | if ((result == CancelResult::Timeout) && force_) |
148 | { | 146 | { |
@@ -151,11 +149,11 @@ static CancelResult thread_cancel_hard(lua_State* L, Lane* s, double secs_, bool | |||
151 | // would be use of "cancellation cleanup handlers" that at least | 149 | // would be use of "cancellation cleanup handlers" that at least |
152 | // PThread seems to have). | 150 | // PThread seems to have). |
153 | // | 151 | // |
154 | THREAD_KILL( &s->thread); | 152 | THREAD_KILL(&lane_->thread); |
155 | #if THREADAPI == THREADAPI_PTHREAD | 153 | #if THREADAPI == THREADAPI_PTHREAD |
156 | // pthread: make sure the thread is really stopped! | 154 | // pthread: make sure the thread is really stopped! |
157 | // note that this may block forever if the lane doesn't call a cancellation point and pthread doesn't honor PTHREAD_CANCEL_ASYNCHRONOUS | 155 | // note that this may block forever if the lane doesn't call a cancellation point and pthread doesn't honor PTHREAD_CANCEL_ASYNCHRONOUS |
158 | result = THREAD_WAIT(&s->thread, waitkill_timeout_, &s->done_signal, &s->done_lock, &s->status) ? CancelResult::Killed : CancelResult::Timeout; | 156 | result = THREAD_WAIT(&lane_->thread, waitkill_timeout_, &lane_->done_signal, &lane_->done_lock, &lane_->status) ? CancelResult::Killed : CancelResult::Timeout; |
159 | if (result == CancelResult::Timeout) | 157 | if (result == CancelResult::Timeout) |
160 | { | 158 | { |
161 | std::ignore = luaL_error( L, "force-killed lane failed to terminate within %f second%s", waitkill_timeout_, waitkill_timeout_ > 1 ? "s" : ""); | 159 | std::ignore = luaL_error( L, "force-killed lane failed to terminate within %f second%s", waitkill_timeout_, waitkill_timeout_ > 1 ? "s" : ""); |
@@ -164,8 +162,8 @@ static CancelResult thread_cancel_hard(lua_State* L, Lane* s, double secs_, bool | |||
164 | (void) waitkill_timeout_; // unused | 162 | (void) waitkill_timeout_; // unused |
165 | (void) L; // unused | 163 | (void) L; // unused |
166 | #endif // THREADAPI == THREADAPI_PTHREAD | 164 | #endif // THREADAPI == THREADAPI_PTHREAD |
167 | s->mstatus = ThreadStatus::Killed; // mark 'gc' to wait for it | 165 | lane_->mstatus = ThreadStatus::Killed; // mark 'gc' to wait for it |
168 | // note that s->status value must remain to whatever it was at the time of the kill | 166 | // note that lane_->status value must remain to whatever it was at the time of the kill |
169 | // because we need to know if we can lua_close() the Lua State or not. | 167 | // because we need to know if we can lua_close() the Lua State or not. |
170 | result = CancelResult::Killed; | 168 | result = CancelResult::Killed; |
171 | } | 169 | } |
@@ -174,16 +172,16 @@ static CancelResult thread_cancel_hard(lua_State* L, Lane* s, double secs_, bool | |||
174 | 172 | ||
175 | // ################################################################################################ | 173 | // ################################################################################################ |
176 | 174 | ||
177 | CancelResult thread_cancel(lua_State* L, Lane* s, CancelOp op_, double secs_, bool force_, double waitkill_timeout_) | 175 | CancelResult thread_cancel(lua_State* L, Lane* lane_, CancelOp op_, double secs_, bool force_, double waitkill_timeout_) |
178 | { | 176 | { |
179 | // remember that lanes are not transferable: only one thread can cancel a lane, so no multithreading issue here | 177 | // remember that lanes are not transferable: only one thread can cancel a lane, so no multithreading issue here |
180 | // We can read 's->status' without locks, but not wait for it (if Posix no PTHREAD_TIMEDJOIN) | 178 | // We can read 'lane_->status' without locks, but not wait for it (if Posix no PTHREAD_TIMEDJOIN) |
181 | if (s->mstatus == ThreadStatus::Killed) | 179 | if (lane_->mstatus == ThreadStatus::Killed) |
182 | { | 180 | { |
183 | return CancelResult::Killed; | 181 | return CancelResult::Killed; |
184 | } | 182 | } |
185 | 183 | ||
186 | if( s->status >= DONE) | 184 | if (lane_->status >= DONE) |
187 | { | 185 | { |
188 | // say "ok" by default, including when lane is already done | 186 | // say "ok" by default, including when lane is already done |
189 | return CancelResult::Cancelled; | 187 | return CancelResult::Cancelled; |
@@ -191,12 +189,12 @@ CancelResult thread_cancel(lua_State* L, Lane* s, CancelOp op_, double secs_, bo | |||
191 | 189 | ||
192 | // signal the linda the wake up the thread so that it can react to the cancel query | 190 | // signal the linda the wake up the thread so that it can react to the cancel query |
193 | // let us hope we never land here with a pointer on a linda that has been destroyed... | 191 | // let us hope we never land here with a pointer on a linda that has been destroyed... |
194 | if( op_ == CO_Soft) | 192 | if (op_ == CO_Soft) |
195 | { | 193 | { |
196 | return thread_cancel_soft( s, secs_, force_); | 194 | return thread_cancel_soft(lane_, secs_, force_); |
197 | } | 195 | } |
198 | 196 | ||
199 | return thread_cancel_hard( L, s, secs_, force_, waitkill_timeout_); | 197 | return thread_cancel_hard(L, lane_, secs_, force_, waitkill_timeout_); |
200 | } | 198 | } |
201 | 199 | ||
202 | // ################################################################################################ | 200 | // ################################################################################################ |
@@ -247,54 +245,51 @@ static CancelOp which_op( lua_State* L, int idx_) | |||
247 | // ################################################################################################ | 245 | // ################################################################################################ |
248 | 246 | ||
249 | // bool[,reason] = lane_h:cancel( [mode, hookcount] [, timeout] [, force [, forcekill_timeout]]) | 247 | // bool[,reason] = lane_h:cancel( [mode, hookcount] [, timeout] [, force [, forcekill_timeout]]) |
250 | LUAG_FUNC( thread_cancel) | 248 | LUAG_FUNC(thread_cancel) |
251 | { | 249 | { |
252 | Lane* s = lua_toLane( L, 1); | 250 | Lane* const lane{ lua_toLane(L, 1) }; |
253 | double secs = 0.0; | 251 | CancelOp const op{ which_op(L, 2) }; // this removes the op string from the stack |
254 | CancelOp op = which_op( L, 2); // this removes the op string from the stack | ||
255 | 252 | ||
256 | if( op > 0) // hook is requested | 253 | if (op > 0) // hook is requested |
257 | { | 254 | { |
258 | int hook_count = (int) lua_tointeger( L, 2); | 255 | int hook_count = (int) lua_tointeger(L, 2); |
259 | lua_remove( L, 2); // argument is processed, remove it | 256 | lua_remove(L, 2); // argument is processed, remove it |
260 | if( hook_count < 1) | 257 | if (hook_count < 1) |
261 | { | 258 | { |
262 | return luaL_error( L, "hook count cannot be < 1"); | 259 | return luaL_error(L, "hook count cannot be < 1"); |
263 | } | 260 | } |
264 | lua_sethook( s->L, cancel_hook, op, hook_count); | 261 | lua_sethook(lane->L, cancel_hook, op, hook_count); |
265 | } | 262 | } |
266 | 263 | ||
267 | if( lua_type( L, 2) == LUA_TNUMBER) | 264 | double secs{ 0.0 }; |
265 | if (lua_type(L, 2) == LUA_TNUMBER) | ||
268 | { | 266 | { |
269 | secs = lua_tonumber( L, 2); | 267 | secs = lua_tonumber(L, 2); |
270 | lua_remove( L, 2); // argument is processed, remove it | 268 | lua_remove(L, 2); // argument is processed, remove it |
271 | if( secs < 0.0) | 269 | if (secs < 0.0) |
272 | { | 270 | { |
273 | return luaL_error( L, "cancel timeout cannot be < 0"); | 271 | return luaL_error(L, "cancel timeout cannot be < 0"); |
274 | } | 272 | } |
275 | } | 273 | } |
276 | 274 | ||
275 | bool const force{ lua_toboolean(L, 2) ? true : false }; // false if nothing there | ||
276 | double const forcekill_timeout{ luaL_optnumber(L, 3, 0.0) }; | ||
277 | switch (thread_cancel(L, lane, op, secs, force, forcekill_timeout)) | ||
277 | { | 278 | { |
278 | bool const force = lua_toboolean( L, 2) ? true : false; // false if nothing there | 279 | case CancelResult::Timeout: |
279 | double forcekill_timeout = luaL_optnumber( L, 3, 0.0); | 280 | lua_pushboolean(L, 0); |
280 | 281 | lua_pushstring(L, "timeout"); | |
281 | switch( thread_cancel( L, s, op, secs, force, forcekill_timeout)) | 282 | return 2; |
282 | { | 283 | |
283 | case CancelResult::Timeout: | 284 | case CancelResult::Cancelled: |
284 | lua_pushboolean( L, 0); | 285 | lua_pushboolean(L, 1); |
285 | lua_pushstring( L, "timeout"); | 286 | push_thread_status(L, lane); |
286 | return 2; | 287 | return 2; |
287 | 288 | ||
288 | case CancelResult::Cancelled: | 289 | case CancelResult::Killed: |
289 | lua_pushboolean( L, 1); | 290 | lua_pushboolean(L, 1); |
290 | push_thread_status( L, s); | 291 | push_thread_status(L, lane); |
291 | return 2; | 292 | return 2; |
292 | |||
293 | case CancelResult::Killed: | ||
294 | lua_pushboolean( L, 1); | ||
295 | push_thread_status( L, s); | ||
296 | return 2; | ||
297 | } | ||
298 | } | 293 | } |
299 | // should never happen, only here to prevent the compiler from complaining of "not all control paths returning a value" | 294 | // should never happen, only here to prevent the compiler from complaining of "not all control paths returning a value" |
300 | return 0; | 295 | return 0; |