aboutsummaryrefslogtreecommitdiff
path: root/src/cancel.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cancel.c')
-rw-r--r--src/cancel.c117
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
80void cancel_hook( lua_State* L, lua_Debug* ar) 80static 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
113static cancel_result thread_cancel_soft( Lane* s, bool_t wake_lindas_) 114static 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
176cancel_result thread_cancel( lua_State* L, Lane* s, double secs_, bool_t force_, double waitkill_timeout_) 177cancel_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
208static 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]])
205LUAG_FUNC( thread_cancel) 250LUAG_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 }