From be1e9d37d9809ee55f26d811208fa64ea9b3785a Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Fri, 19 Apr 2019 14:58:25 +0200 Subject: lane:cancel internal code refactorization --- src/lanes.c | 151 +++++++++++++++++++++++++++++------------------------------- src/linda.c | 4 +- 2 files changed, 74 insertions(+), 81 deletions(-) (limited to 'src') diff --git a/src/lanes.c b/src/lanes.c index 90da9bf..abd4171 100644 --- a/src/lanes.c +++ b/src/lanes.c @@ -169,20 +169,6 @@ static DECLARE_CONST_UNIQUE_KEY( FINALIZER_REGKEY, 0x188fccb8bf348e09); struct s_Linda; -#if 1 -# define DEBUG_SIGNAL( msg, signal_ref ) /* */ -#else -# define DEBUG_SIGNAL( msg, signal_ref ) \ - { int i; unsigned char *ptr; char buf[999]; \ - sprintf( buf, ">>> " msg ": %p\t", (signal_ref) ); \ - ptr= (unsigned char *)signal_ref; \ - for( i=0; istatus' without locks, but not wait for it (if Posix no PTHREAD_TIMEDJOIN) - if( s->mstatus == KILLED) + s->cancel_request = CANCEL_SOFT; // it's now signaled to stop + // negative timeout: we don't want to truly abort the lane, we just want it to react to cancel_test() on its own + if( wake_lindas_) // wake the thread so that execution returns from any pending linda operation if desired { - result = CR_Killed; + SIGNAL_T *waiting_on = s->waiting_on; + if( s->status == WAITING && waiting_on != NULL) + { + SIGNAL_ALL( waiting_on); + } } - else if( s->status < DONE) + // say we succeeded though + return CR_Cancelled; +} + +static cancel_result thread_cancel_hard( lua_State* L, Lane* s, double secs_, bool_t force_, double waitkill_timeout_) +{ + cancel_result result; + + s->cancel_request = CANCEL_HARD; // it's now signaled to stop { - // signal the linda the wake up the thread so that it can react to the cancel query - // let us hope we never land here with a pointer on a linda that has been destroyed... - if( secs < 0.0) + SIGNAL_T *waiting_on = s->waiting_on; + if( s->status == WAITING && waiting_on != NULL) { - s->cancel_request = CANCEL_SOFT; // it's now signaled to stop - // negative timeout: we don't want to truly abort the lane, we just want it to react to cancel_test() on its own - if( force) // wake the thread so that execution returns from any pending linda operation if desired - { - SIGNAL_T *waiting_on = s->waiting_on; - if( s->status == WAITING && waiting_on != NULL) - { - SIGNAL_ALL( waiting_on); - } - } - // say we succeeded though - result = CR_Cancelled; + SIGNAL_ALL( waiting_on); } - else - { - s->cancel_request = CANCEL_HARD; // it's now signaled to stop - { - SIGNAL_T *waiting_on = s->waiting_on; - if( s->status == WAITING && waiting_on != NULL) - { - SIGNAL_ALL( waiting_on); - } - } + } - result = THREAD_WAIT( &s->thread, secs, &s->done_signal, &s->done_lock, &s->status) ? CR_Cancelled : CR_Timeout; + result = THREAD_WAIT( &s->thread, secs_, &s->done_signal, &s->done_lock, &s->status) ? CR_Cancelled : CR_Timeout; - if( (result == CR_Timeout) && force) - { - // Killing is asynchronous; we _will_ wait for it to be done at - // GC, to make sure the data structure can be released (alternative - // would be use of "cancellation cleanup handlers" that at least - // PThread seems to have). - // - THREAD_KILL( &s->thread); + if( (result == CR_Timeout) && force_) + { + // Killing is asynchronous; we _will_ wait for it to be done at + // GC, to make sure the data structure can be released (alternative + // would be use of "cancellation cleanup handlers" that at least + // PThread seems to have). + // + THREAD_KILL( &s->thread); #if THREADAPI == THREADAPI_PTHREAD - // pthread: make sure the thread is really stopped! - // note that this may block forever if the lane doesn't call a cancellation point and pthread doesn't honor PTHREAD_CANCEL_ASYNCHRONOUS - result = THREAD_WAIT( &s->thread, waitkill_timeout_, &s->done_signal, &s->done_lock, &s->status); - if( result == CR_Timeout) - { - return luaL_error( L, "force-killed lane failed to terminate within %f second%s", waitkill_timeout_, waitkill_timeout_ > 1 ? "s" : ""); - } + // pthread: make sure the thread is really stopped! + // note that this may block forever if the lane doesn't call a cancellation point and pthread doesn't honor PTHREAD_CANCEL_ASYNCHRONOUS + result = THREAD_WAIT( &s->thread, waitkill_timeout_, &s->done_signal, &s->done_lock, &s->status); + if( result == CR_Timeout) + { + return luaL_error( L, "force-killed lane failed to terminate within %f second%s", waitkill_timeout_, waitkill_timeout_ > 1 ? "s" : ""); + } #else - (void) waitkill_timeout_; // unused - (void) L; // unused + (void) waitkill_timeout_; // unused + (void) L; // unused #endif // THREADAPI == THREADAPI_PTHREAD - s->mstatus = KILLED; // mark 'gc' to wait for it - // note that s->status value must remain to whatever it was at the time of the kill - // because we need to know if we can lua_close() the Lua State or not. - result = CR_Killed; - } - } + s->mstatus = KILLED; // mark 'gc' to wait for it + // note that s->status value must remain to whatever it was at the time of the kill + // because we need to know if we can lua_close() the Lua State or not. + result = CR_Killed; } - else + return result; +} + +static cancel_result thread_cancel( lua_State* L, Lane* s, double secs_, bool_t force_, double waitkill_timeout_) +{ + // remember that lanes are not transferable: only one thread can cancel a lane, so no multithreading issue here + // We can read 's->status' without locks, but not wait for it (if Posix no PTHREAD_TIMEDJOIN) + if( s->mstatus == KILLED) + { + return CR_Killed; + } + + if( s->status >= DONE) { // say "ok" by default, including when lane is already done - result = CR_Cancelled; + return CR_Cancelled; } - return result; + + // signal the linda the wake up the thread so that it can react to the cancel query + // let us hope we never land here with a pointer on a linda that has been destroyed... + if( secs_ < 0.0) + { + return thread_cancel_soft( L, s, force_); + } + + return thread_cancel_hard( L, s, secs_, force_, waitkill_timeout_); } - // - // Protects modifying the selfdestruct chain +// +// Protects modifying the selfdestruct chain #define SELFDESTRUCT_END ((Lane*)(-1)) - // - // The chain is ended by '(Lane*)(-1)', not NULL: - // 'selfdestruct_first -> ... -> ... -> (-1)' +// +// The chain is ended by '(Lane*)(-1)', not NULL: +// 'selfdestruct_first -> ... -> ... -> (-1)' /* * Add the lane to selfdestruct chain; the ones still running at the end of the diff --git a/src/linda.c b/src/linda.c index 69f41b6..150649d 100644 --- a/src/linda.c +++ b/src/linda.c @@ -245,7 +245,7 @@ LUAG_FUNC( linda_send) { case CANCEL_SOFT: // if user wants to soft-cancel, the call returns lanes.cancel_error - push_unique_key( L, CANCEL_ERROR); + push_unique_key( L, CANCEL_ERROR); return 1; case CANCEL_HARD: @@ -400,7 +400,7 @@ LUAG_FUNC( linda_receive) { case CANCEL_SOFT: // if user wants to soft-cancel, the call returns CANCEL_ERROR - push_unique_key( L, CANCEL_ERROR); + push_unique_key( L, CANCEL_ERROR); return 1; case CANCEL_HARD: -- cgit v1.2.3-55-g6feb