aboutsummaryrefslogtreecommitdiff
path: root/src/cancel.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/cancel.cpp117
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*/
56static inline CancelRequest cancel_test(lua_State* L) 56static 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
114static CancelResult thread_cancel_soft(Lane* s, double secs_, bool wake_lindas_) 114static 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
132static CancelResult thread_cancel_hard(lua_State* L, Lane* s, double secs_, bool force_, double waitkill_timeout_) 132static 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
177CancelResult thread_cancel(lua_State* L, Lane* s, CancelOp op_, double secs_, bool force_, double waitkill_timeout_) 175CancelResult 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]])
250LUAG_FUNC( thread_cancel) 248LUAG_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;