From f741cac68de584f2e16507b2b84fc734ffcc3bb6 Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Mon, 17 Dec 2012 11:29:34 +0100 Subject: Fixed lane tracking feature --- src/lanes.c | 192 ++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 128 insertions(+), 64 deletions(-) (limited to 'src') diff --git a/src/lanes.c b/src/lanes.c index 161de59..b8f7eed 100644 --- a/src/lanes.c +++ b/src/lanes.c @@ -169,6 +169,12 @@ struct s_lane { // M: sets to non-NULL if facing lane handle '__gc' cycle but the lane // is still running // S: cleans up after itself if non-NULL at lane exit + +#if HAVE_LANE_TRACKING + struct s_lane * volatile tracking_next; +#endif // HAVE_LANE_TRACKING + // + // For tracking only }; static bool_t cancel_test( lua_State*L ); @@ -233,6 +239,91 @@ static bool_t push_registry_table( lua_State*L, void *key, bool_t create ) { return TRUE; // table pushed } +#if HAVE_LANE_TRACKING + +static MUTEX_T tracking_cs; +struct s_lane* volatile tracking_first = NULL; // will change to TRACKING_END if we want to activate tracking + +// The chain is ended by '(struct s_lane*)(-1)', not NULL: +// 'tracking_first -> ... -> ... -> (-1)' +#define TRACKING_END ((struct s_lane *)(-1)) + +/* + * Add the lane to tracking chain; the ones still running at the end of the + * whole process will be cancelled. + */ +static void tracking_add( struct s_lane *s) +{ + + MUTEX_LOCK( &tracking_cs); + { + assert( s->tracking_next == NULL); + + s->tracking_next = tracking_first; + tracking_first = s; + } + MUTEX_UNLOCK( &tracking_cs); +} + +/* + * A free-running lane has ended; remove it from tracking chain + */ +static bool_t tracking_remove( struct s_lane *s ) +{ + bool_t found = FALSE; + MUTEX_LOCK( &tracking_cs); + { + // Make sure (within the MUTEX) that we actually are in the chain + // still (at process exit they will remove us from chain and then + // cancel/kill). + // + if (s->tracking_next != NULL) + { + struct s_lane **ref= (struct s_lane **) &tracking_first; + + while( *ref != TRACKING_END) + { + if( *ref == s) + { + *ref = s->tracking_next; + s->tracking_next = NULL; + found = TRUE; + break; + } + ref = (struct s_lane **) &((*ref)->tracking_next); + } + assert( found); + } + } + MUTEX_UNLOCK( &tracking_cs); + return found; +} + +#endif // HAVE_LANE_TRACKING + +//--- +// low-level cleanup + +static void lane_cleanup( struct s_lane* s) +{ + // Clean up after a (finished) thread + // +#if THREADWAIT_METHOD == THREADWAIT_CONDVAR + SIGNAL_FREE( &s->done_signal); + MUTEX_FREE( &s->done_lock); +#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR + +#if HAVE_LANE_TRACKING + if( tracking_first) + { + // Lane was cleaned up, no need to handle at process termination + tracking_remove( s); + } +#endif // HAVE_LANE_TRACKING + + free( s); +} + /* * ############################################################################################### * ############################################ Linda ############################################ @@ -843,27 +934,27 @@ static void linda_id( lua_State*L, char const * const which) lua_pushlightuserdata( L, s ); } - else if (strcmp( which, "delete" )==0) + else if( strcmp( which, "delete" ) == 0) { - struct s_Keeper *K; - struct s_Linda *s= lua_touserdata(L,1); - ASSERT_L(s); + struct s_Keeper* K; + struct s_Linda* l= lua_touserdata( L, 1); + ASSERT_L( l); /* Clean associated structures in the keeper state. */ - K= keeper_acquire(s); + K = keeper_acquire( l); if( K && K->L) // can be NULL if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup) { - keeper_call( K->L, KEEPER_API( clear), L, s, 0 ); + keeper_call( K->L, KEEPER_API( clear), L, l, 0); keeper_release( K); } /* There aren't any lanes waiting on these lindas, since all proxies * have been gc'ed. Right? */ - SIGNAL_FREE( &s->read_happened ); - SIGNAL_FREE( &s->write_happened ); - free(s); + SIGNAL_FREE( &l->read_happened); + SIGNAL_FREE( &l->write_happened); + free( l); } else if (strcmp( which, "metatable" )==0) { @@ -1126,12 +1217,12 @@ static MUTEX_T selfdestruct_cs; // The chain is ended by '(struct s_lane*)(-1)', not NULL: // 'selfdestruct_first -> ... -> ... -> (-1)' -struct s_lane * volatile selfdestruct_first= SELFDESTRUCT_END; +struct s_lane* volatile selfdestruct_first = SELFDESTRUCT_END; /* -* Add the lane to selfdestruct chain; the ones still running at the end of the -* whole process will be cancelled. -*/ + * Add the lane to selfdestruct chain; the ones still running at the end of the + * whole process will be cancelled. + */ static void selfdestruct_add( struct s_lane *s ) { MUTEX_LOCK( &selfdestruct_cs ); @@ -1145,8 +1236,8 @@ static void selfdestruct_add( struct s_lane *s ) { } /* -* A free-running lane has ended; remove it from selfdestruct chain -*/ + * A free-running lane has ended; remove it from selfdestruct chain + */ static bool_t selfdestruct_remove( struct s_lane *s ) { bool_t found = FALSE; @@ -1310,11 +1401,7 @@ static int selfdestruct_gc( lua_State*L) #endif // THREADAPI == THREADAPI_PTHREAD } // NO lua_close() in this case because we don't know where execution of the state was interrupted -#if THREADWAIT_METHOD == THREADWAIT_CONDVAR - SIGNAL_FREE( &s->done_signal); - MUTEX_FREE( &s->done_lock); -#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR - free( s); + lane_cleanup( s); s = next_s; n++; } @@ -1567,10 +1654,6 @@ LUAG_FUNC( set_debug_threadname) return 0; } -#if HAVE_LANE_TRACKING -static bool_t GTrackLanes = FALSE; -#endif // HAVE_LANE_TRACKING - //--- static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) { @@ -1579,11 +1662,9 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) lua_State*L= s->L; #if HAVE_LANE_TRACKING - if( GTrackLanes) + if( tracking_first) { - // If we track lanes, we add them right now to the list so that its traversal hits all known lanes - // (else we get only the still running lanes for which GC was called, IOW not accessible anymore from a script) - selfdestruct_add( s); + tracking_add( s); } #endif // HAVE_LANE_TRACKING @@ -1684,11 +1765,7 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) lua_close( s->L ); s->L = L = 0; - #if THREADWAIT_METHOD == THREADWAIT_CONDVAR - SIGNAL_FREE( &s->done_signal); - MUTEX_FREE( &s->done_lock); - #endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR - free(s); + lane_cleanup( s); } else @@ -1955,6 +2032,9 @@ LUAG_FUNC( thread_new ) #endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR s->mstatus= NORMAL; s->selfdestruct_next= NULL; +#if HAVE_LANE_TRACKING + s->tracking_next = NULL; +#endif // HAVE_LANE_TRACKING // Set metatable for the userdata // @@ -2024,14 +2104,9 @@ LUAG_FUNC( thread_gc) } else if( s->status < DONE) { -#if HAVE_LANE_TRACKING - if( !GTrackLanes) -#endif // HAVE_LANE_TRACKING - { - // still running: will have to be cleaned up later - selfdestruct_add( s); - assert( s->selfdestruct_next); - } + // still running: will have to be cleaned up later + selfdestruct_add( s); + assert( s->selfdestruct_next); return 0; } @@ -2042,22 +2117,8 @@ LUAG_FUNC( thread_gc) s->L = 0; } -#if HAVE_LANE_TRACKING - if( GTrackLanes) - { - // Lane was cleaned up, no need to handle at process termination - selfdestruct_remove( s); - } -#endif // HAVE_LANE_TRACKING - // Clean up after a (finished) thread - // -#if THREADWAIT_METHOD == THREADWAIT_CONDVAR - SIGNAL_FREE( &s->done_signal); - MUTEX_FREE( &s->done_lock); -#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR - - free( s); + lane_cleanup( s); return 0; } @@ -2381,12 +2442,12 @@ LUAG_FUNC( threads) int const top = lua_gettop( L); // List _all_ still running threads // - MUTEX_LOCK( &selfdestruct_cs); - if( selfdestruct_first != SELFDESTRUCT_END) + MUTEX_LOCK( &tracking_cs); + if( tracking_first && tracking_first != TRACKING_END) { - struct s_lane* s = selfdestruct_first; + struct s_lane* s = tracking_first; lua_newtable( L); // {} - while( s != SELFDESTRUCT_END) + while( s != TRACKING_END) { if( s->debug_name) lua_pushstring( L, s->debug_name); // {} "name" @@ -2394,10 +2455,10 @@ LUAG_FUNC( threads) lua_pushfstring( L, "Lane %p", s); // {} "name" push_thread_status( L, s); // {} "name" "status" lua_rawset( L, -3); // {} - s = s->selfdestruct_next; + s = s->tracking_next; } } - MUTEX_UNLOCK( &selfdestruct_cs); + MUTEX_UNLOCK( &tracking_cs); return lua_gettop( L) - top; } #endif // HAVE_LANE_TRACKING @@ -2499,7 +2560,7 @@ static void init_once_LOCKED( lua_State* L, volatile DEEP_PRELUDE** timer_deep_r #endif #if HAVE_LANE_TRACKING - GTrackLanes = _track_lanes; + tracking_first = _track_lanes ? TRACKING_END : NULL; #endif // HAVE_LANE_TRACKING // Locks for 'tools.c' inc/dec counters @@ -2513,9 +2574,12 @@ static void init_once_LOCKED( lua_State* L, volatile DEEP_PRELUDE** timer_deep_r serialize_require( L ); - // Selfdestruct chain handling + // Linked chains handling // MUTEX_INIT( &selfdestruct_cs ); +#if HAVE_LANE_TRACKING + MUTEX_INIT( &tracking_cs); +#endif // HAVE_LANE_TRACKING //--- // Linux needs SCHED_RR to change thread priorities, and that is only -- cgit v1.2.3-55-g6feb