diff options
Diffstat (limited to 'src/cancel.c')
-rw-r--r-- | src/cancel.c | 117 |
1 files changed, 83 insertions, 34 deletions
diff --git a/src/cancel.c b/src/cancel.c index 11e100d..8ce00c8 100644 --- a/src/cancel.c +++ b/src/cancel.c | |||
@@ -77,12 +77,13 @@ LUAG_FUNC( cancel_test) | |||
77 | // ################################################################################################ | 77 | // ################################################################################################ |
78 | // ################################################################################################ | 78 | // ################################################################################################ |
79 | 79 | ||
80 | void cancel_hook( lua_State* L, lua_Debug* ar) | 80 | static void cancel_hook( lua_State* L, lua_Debug* ar) |
81 | { | 81 | { |
82 | (void)ar; | 82 | (void)ar; |
83 | DEBUGSPEW_CODE( fprintf( stderr, "cancel_hook\n")); | 83 | DEBUGSPEW_CODE( fprintf( stderr, "cancel_hook\n")); |
84 | if( cancel_test( L) != CANCEL_NONE) | 84 | if( cancel_test( L) != CANCEL_NONE) |
85 | { | 85 | { |
86 | lua_sethook( L, NULL, 0, 0); | ||
86 | cancel_error( L); | 87 | cancel_error( L); |
87 | } | 88 | } |
88 | } | 89 | } |
@@ -110,10 +111,10 @@ void cancel_hook( lua_State* L, lua_Debug* ar) | |||
110 | 111 | ||
111 | // ################################################################################################ | 112 | // ################################################################################################ |
112 | 113 | ||
113 | static cancel_result thread_cancel_soft( Lane* s, bool_t wake_lindas_) | 114 | static cancel_result thread_cancel_soft( Lane* s, double secs_, bool_t wake_lindas_) |
114 | { | 115 | { |
115 | s->cancel_request = CANCEL_SOFT; // it's now signaled to stop | 116 | s->cancel_request = CANCEL_SOFT; // it's now signaled to stop |
116 | // 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 |
117 | 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 |
118 | { | 119 | { |
119 | SIGNAL_T *waiting_on = s->waiting_on; | 120 | SIGNAL_T *waiting_on = s->waiting_on; |
@@ -122,8 +123,8 @@ static cancel_result thread_cancel_soft( Lane* s, bool_t wake_lindas_) | |||
122 | SIGNAL_ALL( waiting_on); | 123 | SIGNAL_ALL( waiting_on); |
123 | } | 124 | } |
124 | } | 125 | } |
125 | // say we succeeded though | 126 | |
126 | return CR_Cancelled; | 127 | return THREAD_WAIT( &s->thread, secs_, &s->done_signal, &s->done_lock, &s->status) ? CR_Cancelled : CR_Timeout; |
127 | } | 128 | } |
128 | 129 | ||
129 | // ################################################################################################ | 130 | // ################################################################################################ |
@@ -163,9 +164,9 @@ static cancel_result thread_cancel_hard( lua_State* L, Lane* s, double secs_, bo | |||
163 | (void) waitkill_timeout_; // unused | 164 | (void) waitkill_timeout_; // unused |
164 | (void) L; // unused | 165 | (void) L; // unused |
165 | #endif // THREADAPI == THREADAPI_PTHREAD | 166 | #endif // THREADAPI == THREADAPI_PTHREAD |
166 | s->mstatus = KILLED; // mark 'gc' to wait for it | 167 | s->mstatus = KILLED; // mark 'gc' to wait for it |
167 | // note that s->status value must remain to whatever it was at the time of the kill | 168 | // note that s->status value must remain to whatever it was at the time of the kill |
168 | // because we need to know if we can lua_close() the Lua State or not. | 169 | // because we need to know if we can lua_close() the Lua State or not. |
169 | result = CR_Killed; | 170 | result = CR_Killed; |
170 | } | 171 | } |
171 | return result; | 172 | return result; |
@@ -173,7 +174,7 @@ static cancel_result thread_cancel_hard( lua_State* L, Lane* s, double secs_, bo | |||
173 | 174 | ||
174 | // ################################################################################################ | 175 | // ################################################################################################ |
175 | 176 | ||
176 | cancel_result thread_cancel( lua_State* L, Lane* s, double secs_, bool_t force_, double waitkill_timeout_) | 177 | cancel_result thread_cancel( lua_State* L, Lane* s, CancelOp op_, double secs_, bool_t force_, double waitkill_timeout_) |
177 | { | 178 | { |
178 | // remember that lanes are not transferable: only one thread can cancel a lane, so no multithreading issue here | 179 | // remember that lanes are not transferable: only one thread can cancel a lane, so no multithreading issue here |
179 | // We can read 's->status' without locks, but not wait for it (if Posix no PTHREAD_TIMEDJOIN) | 180 | // We can read 's->status' without locks, but not wait for it (if Posix no PTHREAD_TIMEDJOIN) |
@@ -190,9 +191,9 @@ cancel_result thread_cancel( lua_State* L, Lane* s, double secs_, bool_t force_, | |||
190 | 191 | ||
191 | // signal the linda the wake up the thread so that it can react to the cancel query | 192 | // signal the linda the wake up the thread so that it can react to the cancel query |
192 | // let us hope we never land here with a pointer on a linda that has been destroyed... | 193 | // let us hope we never land here with a pointer on a linda that has been destroyed... |
193 | if( secs_ < 0.0) | 194 | if( op_ == CO_Soft) |
194 | { | 195 | { |
195 | return thread_cancel_soft( s, force_); | 196 | return thread_cancel_soft( s, secs_, force_); |
196 | } | 197 | } |
197 | 198 | ||
198 | return thread_cancel_hard( L, s, secs_, force_, waitkill_timeout_); | 199 | return thread_cancel_hard( L, s, secs_, force_, waitkill_timeout_); |
@@ -201,49 +202,97 @@ cancel_result thread_cancel( lua_State* L, Lane* s, double secs_, bool_t force_, | |||
201 | // ################################################################################################ | 202 | // ################################################################################################ |
202 | // ################################################################################################ | 203 | // ################################################################################################ |
203 | 204 | ||
204 | // lane_h:cancel( [timeout] [, force [, forcekill_timeout]]) | 205 | // > 0: the mask |
206 | // = 0: soft | ||
207 | // < 0: hard | ||
208 | static CancelOp which_op( lua_State* L, int idx_) | ||
209 | { | ||
210 | if( lua_type( L, idx_) == LUA_TSTRING) | ||
211 | { | ||
212 | CancelOp op = CO_Invalid; | ||
213 | char const* str = lua_tostring( L, idx_); | ||
214 | if( strcmp( str, "soft") == 0) | ||
215 | { | ||
216 | op = CO_Soft; | ||
217 | } | ||
218 | else if( strcmp( str, "count") == 0) | ||
219 | { | ||
220 | op = CO_Count; | ||
221 | } | ||
222 | else if( strcmp( str, "line") == 0) | ||
223 | { | ||
224 | op = CO_Line; | ||
225 | } | ||
226 | else if( strcmp( str, "call") == 0) | ||
227 | { | ||
228 | op = CO_Call; | ||
229 | } | ||
230 | else if( strcmp( str, "ret") == 0) | ||
231 | { | ||
232 | op = CO_Ret; | ||
233 | } | ||
234 | else if( strcmp( str, "hard") == 0) | ||
235 | { | ||
236 | op = CO_Hard; | ||
237 | } | ||
238 | lua_remove( L, idx_); // argument is processed, remove it | ||
239 | if( op == CO_Invalid) | ||
240 | { | ||
241 | luaL_error( L, "invalid hook option %s", str); | ||
242 | } | ||
243 | return op; | ||
244 | } | ||
245 | return CO_Hard; | ||
246 | } | ||
247 | // ################################################################################################ | ||
248 | |||
249 | // bool[,reason] = lane_h:cancel( [mode, hookcount] [, timeout] [, force [, forcekill_timeout]]) | ||
205 | LUAG_FUNC( thread_cancel) | 250 | LUAG_FUNC( thread_cancel) |
206 | { | 251 | { |
207 | Lane* s = lua_toLane( L, 1); | 252 | Lane* s = lua_toLane( L, 1); |
208 | double secs = 0.0; | 253 | double secs = 0.0; |
209 | int force_i = 2; | 254 | CancelOp op = which_op( L, 2); // this removes the op string from the stack |
210 | int forcekill_timeout_i = 3; | ||
211 | 255 | ||
212 | if( lua_isnumber( L, 2)) | 256 | if( op > 0) // hook is requested |
213 | { | 257 | { |
214 | secs = lua_tonumber( L, 2); | 258 | int hook_count = (int) lua_tointeger( L, 2); |
215 | if( secs < 0.0 && lua_gettop( L) > 3) | 259 | lua_remove( L, 2); // argument is processed, remove it |
260 | if( hook_count < 1) | ||
216 | { | 261 | { |
217 | return luaL_error( L, "can't force_kill a soft cancel"); | 262 | return luaL_error( L, "hook count cannot be < 1"); |
218 | } | 263 | } |
219 | // negative timeout and force flag means we want to wake linda-waiting threads | 264 | lua_sethook( s->L, cancel_hook, op, hook_count); |
220 | ++ force_i; | ||
221 | ++ forcekill_timeout_i; | ||
222 | } | 265 | } |
223 | else if( lua_isnil( L, 2)) | 266 | |
267 | if( lua_type( L, 2) == LUA_TNUMBER) | ||
224 | { | 268 | { |
225 | ++ force_i; | 269 | secs = lua_tonumber( L, 2); |
226 | ++ forcekill_timeout_i; | 270 | lua_remove( L, 2); // argument is processed, remove it |
271 | if( secs < 0.0) | ||
272 | { | ||
273 | return luaL_error( L, "cancel timeout cannot be < 0"); | ||
274 | } | ||
227 | } | 275 | } |
228 | 276 | ||
229 | { | 277 | { |
230 | bool_t force = lua_toboolean( L, force_i); // FALSE if nothing there | 278 | bool_t force = lua_toboolean( L, 2); // FALSE if nothing there |
231 | double forcekill_timeout = luaL_optnumber( L, forcekill_timeout_i, 0.0); | 279 | double forcekill_timeout = luaL_optnumber( L, 3, 0.0); |
232 | 280 | ||
233 | switch( thread_cancel( L, s, secs, force, forcekill_timeout)) | 281 | switch( thread_cancel( L, s, op, secs, force, forcekill_timeout)) |
234 | { | 282 | { |
235 | case CR_Timeout: | 283 | case CR_Timeout: |
236 | lua_pushboolean( L, 0); | 284 | lua_pushboolean( L, 0); |
237 | lua_pushstring( L, "timeout"); | 285 | lua_pushstring( L, "timeout"); |
238 | return 2; | 286 | return 2; |
239 | 287 | ||
240 | case CR_Cancelled: | 288 | case CR_Cancelled: |
241 | lua_pushboolean( L, 1); | 289 | lua_pushboolean( L, 1); |
242 | return 1; | 290 | push_thread_status( L, s); |
291 | return 2; | ||
243 | 292 | ||
244 | case CR_Killed: | 293 | case CR_Killed: |
245 | lua_pushboolean( L, 0); | 294 | lua_pushboolean( L, 1); |
246 | lua_pushstring( L, "killed"); | 295 | push_thread_status( L, s); |
247 | return 2; | 296 | return 2; |
248 | } | 297 | } |
249 | } | 298 | } |