From 87431bcc0ece1eaf9305593223bb0c5145004044 Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Mon, 14 Nov 2011 19:41:28 +0100 Subject: * removed packagepath and packagecpath options, replaced by a package table, whose fields path, cpath, loaders, preload are transfered * code cleanup to facilitate transition between WIN32 and PTHREAD impleentations * tentative fix for desinit crashes when free running lanes are killed at process shutdown --- src/lanes.c | 161 +++++++++++++++++++++++++------------------------------- src/lanes.lua | 13 ++--- src/threading.c | 54 +++++++++---------- src/threading.h | 55 +++++++++++++------ 4 files changed, 141 insertions(+), 142 deletions(-) (limited to 'src') diff --git a/src/lanes.c b/src/lanes.c index aef1015..40af6c0 100644 --- a/src/lanes.c +++ b/src/lanes.c @@ -139,7 +139,7 @@ struct s_lane { // M: sets to FALSE, flags TRUE for cancel request // S: reads to see if cancel is requested -#if !( (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) ) +#if THREADWAIT_METHOD == THREADWAIT_CONDVAR SIGNAL_T done_signal_; // // M: Waited upon at lane ending (if Posix with no PTHREAD_TIMEDJOIN) @@ -149,7 +149,7 @@ struct s_lane { // // Lock required by 'done_signal' condition variable, protecting // lane status changes to DONE/ERROR_ST/CANCELLED. -#endif +#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR volatile enum { NORMAL, // normal master side state @@ -1150,9 +1150,17 @@ static int selfdestruct_atexit( lua_State *L) { struct s_lane *next_s= s->selfdestruct_next; s->selfdestruct_next= NULL; // detach from selfdestruct chain - if( s->thread) // can be NULL if previous 'soft' termination succeeded + if( !THREAD_ISNULL( s->thread)) // can be NULL if previous 'soft' termination succeeded + { THREAD_KILL( &s->thread); + // make sure the thread is really stopped! + THREAD_WAIT( &s->thread, -1, &s->done_signal_, &s->done_lock_, &s->status); + } // 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); s = next_s; n++; @@ -1374,11 +1382,7 @@ LUAG_FUNC( set_debug_threadname) } //--- -#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) - static THREAD_RETURN_T __stdcall lane_main( void *vs ) -#else - static THREAD_RETURN_T lane_main( void *vs ) -#endif +static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) { struct s_lane *s= (struct s_lane *)vs; int rc, rc2; @@ -1475,13 +1479,15 @@ LUAG_FUNC( set_debug_threadname) lua_close( s->L ); s->L = L = 0; - #if !( (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) ) - SIGNAL_FREE( &s->done_signal_ ); - MUTEX_FREE( &s->done_lock_ ); - #endif + #if THREADWAIT_METHOD == THREADWAIT_CONDVAR + SIGNAL_FREE( &s->done_signal_); + MUTEX_FREE( &s->done_lock_); + #endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR free(s); - } else { + } + else + { // leave results (1..top) or error message + stack trace (1..2) on the stack - master will copy them enum e_status st= @@ -1492,16 +1498,16 @@ LUAG_FUNC( set_debug_threadname) // Posix no PTHREAD_TIMEDJOIN: // 'done_lock' protects the -> DONE|ERROR_ST|CANCELLED state change // - #if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) - s->status= st; - #else - MUTEX_LOCK( &s->done_lock_ ); +#if THREADWAIT_METHOD == THREADWAIT_CONDVAR + MUTEX_LOCK( &s->done_lock_); { - s->status= st; - SIGNAL_ONE( &s->done_signal_ ); // wake up master (while 's->done_lock' is on) +#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR + s->status = st; +#if THREADWAIT_METHOD == THREADWAIT_CONDVAR + SIGNAL_ONE( &s->done_signal_); // wake up master (while 's->done_lock' is on) } - MUTEX_UNLOCK( &s->done_lock_ ); - #endif + MUTEX_UNLOCK( &s->done_lock_); +#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR } return 0; // ignored } @@ -1512,7 +1518,7 @@ LUAG_FUNC( set_debug_threadname) // [cancelstep_uint=0], // [prio_int=0], // [globals_tbl], -// [packagepath], +// [package_tbl], // [required], // [... args ...] ) // @@ -1553,11 +1559,10 @@ LUAG_FUNC( thread_new ) uint_t cs= luaG_optunsigned( L, 3,0); int prio= (int)luaL_optinteger( L, 4,0); uint_t glob= luaG_isany(L,5) ? 5:0; - uint_t ppath = luaG_isany(L,6) ? 6:0; - uint_t pcpath = luaG_isany(L,7) ? 7:0; - uint_t required = luaG_isany(L,8) ? 8:0; + uint_t package = luaG_isany(L,6) ? 6:0; + uint_t required = luaG_isany(L,7) ? 7:0; -#define FIXED_ARGS (8) +#define FIXED_ARGS (7) uint_t args= lua_gettop(L) - FIXED_ARGS; if (prio < THREAD_PRIO_MIN || prio > THREAD_PRIO_MAX) @@ -1588,46 +1593,35 @@ LUAG_FUNC( thread_new ) ASSERT_L( lua_gettop(L2) == 0); // package.path + STACK_CHECK(L) STACK_CHECK(L2) - if( ppath) - { - if (lua_type(L,ppath) != LUA_TSTRING) - luaL_error( L, "expected packagepath as string, got %s", luaG_typename(L,ppath)); - lua_getglobal( L2, "package"); - if( lua_isnil( L2, -1)) // package library not loaded: do nothing - { - lua_pop( L2, 1); - } - else - { - lua_pushvalue( L, ppath); - luaG_inter_move( L, L2, 1); // moves the new path to L2 - lua_setfield( L2, -2, "path"); // set package.path - lua_pop( L2, 1); - } - } - STACK_END(L2,0) - - // package.cpath - STACK_CHECK(L2) - if( pcpath) + if( package) { - if (lua_type(L,pcpath) != LUA_TSTRING) - luaL_error( L, "expected packagecpath as string, got %s", luaG_typename(L,pcpath)); + if (lua_type(L,package) != LUA_TTABLE) + luaL_error( L, "expected package as table, got %s", luaG_typename(L,package)); lua_getglobal( L2, "package"); - if( lua_isnil( L2, -1)) // // package library not loaded: do nothing + if( !lua_isnil( L2, -1)) // package library not loaded: do nothing { - lua_pop( L2, 1); - } - else - { - lua_pushvalue( L, pcpath); - luaG_inter_move( L, L2, 1); // moves the new cpath to L2 - lua_setfield( L2, -2, "cpath"); // set package.cpath - lua_pop( L2, 1); + int i; + char const *entries[] = { "path", "cpath", "preload", "loaders", NULL}; + for( i = 0; entries[i]; ++ i) + { + lua_getfield( L, package, entries[i]); + if( lua_isnil( L, -1)) + { + lua_pop( L, 1); + } + else + { + luaG_inter_move( L, L2, 1); // moves the entry to L2 + lua_setfield( L2, -2, entries[i]); // set package[entries[i]] + } + } } + lua_pop( L2, 1); } STACK_END(L2,0) + STACK_END(L,0) // modules to require in the target lane *before* the function is transfered! @@ -1738,10 +1732,10 @@ LUAG_FUNC( thread_new ) s->waiting_on = NULL; s->cancel_request= FALSE; -#if !( (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) ) - MUTEX_INIT( &s->done_lock_ ); - SIGNAL_INIT( &s->done_signal_ ); -#endif +#if THREADWAIT_METHOD == THREADWAIT_CONDVAR + MUTEX_INIT( &s->done_lock_); + SIGNAL_INIT( &s->done_signal_); +#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR s->mstatus= NORMAL; s->selfdestruct_next= NULL; @@ -1813,6 +1807,7 @@ LUAG_FUNC( thread_gc ) { // Make sure a kill has proceeded, before cleaning up the data structure. // + // NO lua_close() in this case because we don't know where execution of the state was interrupted // If not doing 'THREAD_WAIT()' we should close the Lua state here // (can it be out of order, since we killed the lane abruptly?) // @@ -1821,11 +1816,7 @@ LUAG_FUNC( thread_gc ) s->L = 0; #else // 0 DEBUGEXEC(fprintf( stderr, "** Joining with a killed thread (needs testing) **" )); -#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) - THREAD_WAIT( &s->thread, -1 ); -#else - THREAD_WAIT( &s->thread, &s->done_signal_, &s->done_lock_, &s->status, -1 ); -#endif + THREAD_WAIT( &s->thread, -1, &s->done_signal_, &s->done_lock_, &s->status); DEBUGEXEC(fprintf( stderr, "** Joined ok **" )); #endif // 0 } @@ -1837,12 +1828,12 @@ LUAG_FUNC( thread_gc ) // Clean up after a (finished) thread // -#if (! ((defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN))) - SIGNAL_FREE( &s->done_signal_ ); - MUTEX_FREE( &s->done_lock_ ); -#endif +#if THREADWAIT_METHOD == THREADWAIT_CONDVAR + SIGNAL_FREE( &s->done_signal_); + MUTEX_FREE( &s->done_lock_); +#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR - free(s); + free( s); return 0; } @@ -1871,6 +1862,7 @@ static bool_t thread_cancel( struct s_lane *s, double secs, bool_t force) // if( s->status < DONE) { + s->cancel_request = TRUE; // 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... //MUTEX_LOCK( &selfdestruct_cs ); @@ -1882,13 +1874,7 @@ static bool_t thread_cancel( struct s_lane *s, double secs, bool_t force) } } //MUTEX_UNLOCK( &selfdestruct_cs ); - s->cancel_request = TRUE; // it's now signalled to stop - done= -#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) - THREAD_WAIT( &s->thread, secs); -#else - THREAD_WAIT( &s->thread, &s->done_signal_, &s->done_lock_, &s->status, secs); -#endif + done = THREAD_WAIT( &s->thread, secs, &s->done_signal_, &s->done_lock_, &s->status); if ((!done) && force) { @@ -1986,12 +1972,7 @@ LUAG_FUNC( thread_join ) int ret; bool_t done; - done = (s->thread == 0) || -#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) - THREAD_WAIT( &s->thread, wait_secs ); -#else - THREAD_WAIT( &s->thread, &s->done_signal_, &s->done_lock_, &s->status, wait_secs); -#endif + done = THREAD_ISNULL( s->thread) || THREAD_WAIT( &s->thread, wait_secs, &s->done_signal_, &s->done_lock_, &s->status); if (!done || !L2) return 0; // timeout: pushes none, leaves 'L2' alive @@ -2365,7 +2346,7 @@ LUAG_FUNC( configure ) * there is no problem. But if the host is multithreaded, we need to lock around the * initializations. */ -#ifdef PLATFORM_WIN32 +#if THREADAPI == THREADAPI_WINDOWS { static volatile int /*bool*/ go_ahead; // = 0 if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0) @@ -2378,7 +2359,7 @@ LUAG_FUNC( configure ) while( !go_ahead ) { Sleep(1); } // changes threads } } -#else +#else // THREADAPI == THREADAPI_PTHREAD if( s_initCount == 0) { static pthread_mutex_t my_lock= PTHREAD_MUTEX_INITIALIZER; @@ -2394,7 +2375,7 @@ LUAG_FUNC( configure ) } pthread_mutex_unlock(&my_lock); } -#endif +#endif // THREADAPI == THREADAPI_PTHREAD assert( timer_deep != 0 ); // Create main module interface table @@ -2453,7 +2434,7 @@ LUAG_FUNC( configure ) int #if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) __declspec(dllexport) -#endif +#endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) luaopen_lanes( lua_State *L ) { // Create main module interface table diff --git a/src/lanes.lua b/src/lanes.lua index 005ce28..6ba0ef3 100644 --- a/src/lanes.lua +++ b/src/lanes.lua @@ -214,7 +214,7 @@ local function gen( ... ) end end - local prio, cs, g_tbl, packagepath, packagecpath, required + local prio, cs, g_tbl, package_tbl, required for k,v in pairs(opt) do if k=="priority" then prio= v @@ -224,10 +224,8 @@ local function gen( ... ) type(v)=="number" and v or error( "Bad cancelstep: "..tostring(v), lev ) elseif k=="globals" then g_tbl= v - elseif k=="packagepath" then - packagepath = (type( v) == "string") and v or error( "Bad packagepath: " .. tostring( v), lev) - elseif k=="packagecpath" then - packagecpath = (type( v) == "string") and v or error( "Bad packagecpath: " .. tostring( v), lev) + elseif k=="package" then + package_tbl = (type( v) == "table") and v or error( "Bad package: " .. tostring( v), lev) elseif k=="required" then required= (type( v) == "table") and v or error( "Bad required: " .. tostring( v), lev) --.. @@ -236,12 +234,11 @@ local function gen( ... ) end end - if not packagepath then packagepath = package.path end - if not packagecpath then packagecpath = package.cpath end + if not package_tbl then package_tbl = package end -- Lane generator -- return function(...) - return thread_new( func, libs, cs, prio, g_tbl, packagepath, packagecpath, required, ...) -- args + return thread_new( func, libs, cs, prio, g_tbl, package_tbl, required, ...) -- args end end diff --git a/src/threading.c b/src/threading.c index 22d18d4..8966dc6 100644 --- a/src/threading.c +++ b/src/threading.c @@ -41,9 +41,9 @@ THE SOFTWARE. #include "threading.h" #include "lua.h" -#if !((defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)) +#if THREADAPI == THREADAPI_PTHREAD # include -#endif +#endif // THREADAPI == THREADAPI_PTHREAD #if defined(PLATFORM_LINUX) || defined(PLATFORM_CYGWIN) @@ -71,7 +71,7 @@ THE SOFTWARE. * FAIL is for unexpected API return values - essentially programming * error in _this_ code. */ -#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) +#if THREADAPI == THREADAPI_WINDOWS static void FAIL( const char *funcname, int rc ) { fprintf( stderr, "%s() failed! (%d)\n", funcname, rc ); #ifdef _MSC_VER @@ -79,7 +79,7 @@ static void FAIL( const char *funcname, int rc ) { #endif // _MSC_VER abort(); } -#endif +#endif // THREADAPI == THREADAPI_WINDOWS /* @@ -90,7 +90,7 @@ static void FAIL( const char *funcname, int rc ) { */ time_d now_secs(void) { -#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) +#if THREADAPI == THREADAPI_WINDOWS /* * Windows FILETIME values are "100-nanosecond intervals since * January 1, 1601 (UTC)" (MSDN). Well, we'd want Unix Epoch as @@ -145,7 +145,7 @@ time_d now_secs(void) { // <= 2.0.2 code return (double)(uli.QuadPart - uli_epoch.QuadPart) / 10000000.0; # endif -#else +#else // THREADAPI == THREADAPI_PTHREAD struct timeval tv; // { // time_t tv_sec; /* seconds since Jan. 1, 1970 */ @@ -156,7 +156,7 @@ time_d now_secs(void) { assert( rc==0 ); return ((double)tv.tv_sec) + ((tv.tv_usec)/1000) / 1000.0; -#endif +#endif // THREADAPI THREADAPI_PTHREAD } @@ -168,7 +168,7 @@ time_d SIGNAL_TIMEOUT_PREPARE( double secs ) { } -#if !((defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)) +#if THREADAPI == THREADAPI_PTHREAD /* * Prepare 'abs_secs' kind of timeout to 'timespec' format */ @@ -187,7 +187,7 @@ static void prepare_timeout( struct timespec *ts, time_d abs_secs ) { ts->tv_sec = ts->tv_sec + 1; } } -#endif +#endif // THREADAPI == THREADAPI_PTHREAD /*---=== Threading ===---*/ @@ -230,7 +230,7 @@ static void prepare_timeout( struct timespec *ts, time_d abs_secs ) { # endif #endif -#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) +#if THREADAPI == THREADAPI_WINDOWS // void MUTEX_INIT( MUTEX_T *ref ) { *ref= CreateMutex( NULL /*security attr*/, FALSE /*not locked*/, NULL ); @@ -282,7 +282,8 @@ static void prepare_timeout( struct timespec *ts, time_d abs_secs ) { *ref= h; } // - bool_t THREAD_WAIT( THREAD_T *ref, double secs ) { +bool_t THREAD_WAIT_IMPL( THREAD_T *ref, double secs) +{ DWORD ms = (secs<0.0) ? INFINITE : (DWORD)((secs*1000.0)+0.5); DWORD rc= WaitForSingleObject( *ref, ms /*timeout*/ ); @@ -373,7 +374,7 @@ static void prepare_timeout( struct timespec *ts, time_d abs_secs ) { if (!PulseEvent( *ref )) FAIL( "PulseEvent", GetLastError() ); } -#else +#else // THREADAPI == THREADAPI_PTHREAD // PThread (Linux, OS X, ...) // // On OS X, user processes seem to be able to change priorities. @@ -652,7 +653,7 @@ static void prepare_timeout( struct timespec *ts, time_d abs_secs ) { } } // - /* + /* * Wait for a thread to finish. * * 'mu_ref' is a lock we should use for the waiting; initially unlocked. @@ -660,11 +661,7 @@ static void prepare_timeout( struct timespec *ts, time_d abs_secs ) { * * Returns TRUE for succesful wait, FALSE for timed out */ -#ifdef PTHREAD_TIMEDJOIN - bool_t THREAD_WAIT( THREAD_T *ref, double secs ) -#else - bool_t THREAD_WAIT( THREAD_T *ref, SIGNAL_T *signal_ref, MUTEX_T *mu_ref, volatile enum e_status *st_ref, double secs ) -#endif +bool_t THREAD_WAIT( THREAD_T *ref, double secs , SIGNAL_T *signal_ref, MUTEX_T *mu_ref, volatile enum e_status *st_ref) { struct timespec ts_store; const struct timespec *timeout= NULL; @@ -672,16 +669,17 @@ static void prepare_timeout( struct timespec *ts, time_d abs_secs ) { // Do timeout counting before the locks // -#ifdef PTHREAD_TIMEDJOIN - if (secs>=0.0) { -#else - if (secs>0.0) { -#endif +#if THREADWAIT_METHOD == THREADWAIT_TIMEOUT + if (secs>=0.0) +#else // THREADWAIT_METHOD == THREADWAIT_CONDVAR + if (secs>0.0) +#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR + { prepare_timeout( &ts_store, now_secs()+secs ); timeout= &ts_store; } -#ifdef PTHREAD_TIMEDJOIN +#if THREADWAIT_METHOD == THREADWAIT_TIMEOUT /* Thread is joinable */ if (!timeout) { @@ -694,7 +692,7 @@ static void prepare_timeout( struct timespec *ts, time_d abs_secs ) { } done= rc==0; } -#else +#else // THREADWAIT_METHOD == THREADWAIT_CONDVAR /* Since we've set the thread up as PTHREAD_CREATE_DETACHED, we cannot * join with it. Use the cond.var. */ @@ -718,13 +716,13 @@ static void prepare_timeout( struct timespec *ts, time_d abs_secs ) { done= *st_ref >= DONE; // DONE|ERROR_ST|CANCELLED MUTEX_UNLOCK( mu_ref ); -#endif +#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR return done; - } + } // void THREAD_KILL( THREAD_T *ref ) { pthread_cancel( *ref ); } -#endif +#endif // THREADAPI == THREADAPI_PTHREAD static const lua_Alloc alloc_f= 0; diff --git a/src/threading.h b/src/threading.h index 4a83229..7387764 100644 --- a/src/threading.h +++ b/src/threading.h @@ -1,8 +1,8 @@ /* * THREADING.H */ -#ifndef THREADING_H -#define THREADING_H +#ifndef __threading_h__ +#define __threading_h__ 1 /* Platform detection */ @@ -45,11 +45,19 @@ typedef unsigned int uint_t; */ enum e_status { PENDING, RUNNING, WAITING, DONE, ERROR_ST, CANCELLED }; +#define THREADAPI_WINDOWS 1 +#define THREADAPI_PTHREAD 2 + +#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) +#define THREADAPI THREADAPI_WINDOWS +#else // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) +#define THREADAPI THREADAPI_PTHREAD +#endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) /*---=== Locks & Signals ===--- */ -#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) +#if THREADAPI == THREADAPI_WINDOWS #define WIN32_LEAN_AND_MEAN // 'SignalObjectAndWait' needs this (targets Windows 2000 and above) #define _WIN32_WINNT 0x0400 @@ -68,12 +76,13 @@ enum e_status { PENDING, RUNNING, WAITING, DONE, ERROR_ST, CANCELLED }; void MUTEX_LOCK( MUTEX_T *ref ); void MUTEX_UNLOCK( MUTEX_T *ref ); - typedef unsigned THREAD_RETURN_T; + typedef unsigned int THREAD_RETURN_T; #define SIGNAL_T HANDLE #define YIELD() Sleep(0) -#else + #define THREAD_CALLCONV __stdcall +#else // THREADAPI == THREADAPI_PTHREAD // PThread (Linux, OS X, ...) // #include @@ -114,7 +123,8 @@ enum e_status { PENDING, RUNNING, WAITING, DONE, ERROR_ST, CANCELLED }; #else #define YIELD() pthread_yield() #endif -#endif + #define THREAD_CALLCONV +#endif //THREADAPI == THREADAPI_PTHREAD void SIGNAL_INIT( SIGNAL_T *ref ); void SIGNAL_FREE( SIGNAL_T *ref ); @@ -136,9 +146,10 @@ bool_t SIGNAL_WAIT( SIGNAL_T *ref, MUTEX_T *mu, time_d timeout ); /*---=== Threading ===--- */ -#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) +#if THREADAPI == THREADAPI_WINDOWS typedef HANDLE THREAD_T; +# define THREAD_ISNULL( _h) (_h == 0) // void THREAD_CREATE( THREAD_T *ref, THREAD_RETURN_T (__stdcall *func)( void * ), @@ -147,7 +158,7 @@ bool_t SIGNAL_WAIT( SIGNAL_T *ref, MUTEX_T *mu, time_d timeout ); # define THREAD_PRIO_MIN (-3) # define THREAD_PRIO_MAX (+3) -#else +#else // THREADAPI == THREADAPI_PTHREAD /* Platforms that have a timed 'pthread_join()' can get away with a simpler * implementation. Others will use a condition variable. */ @@ -161,6 +172,7 @@ bool_t SIGNAL_WAIT( SIGNAL_T *ref, MUTEX_T *mu, time_d timeout ); # endif typedef pthread_t THREAD_T; +# define THREAD_ISNULL( _h) 0 // pthread_t may be a structure: never 'null' by itself void THREAD_CREATE( THREAD_T *ref, THREAD_RETURN_T (*func)( void * ), @@ -178,19 +190,30 @@ bool_t SIGNAL_WAIT( SIGNAL_T *ref, MUTEX_T *mu, time_d timeout ); # define THREAD_PRIO_MIN (-2) # define THREAD_PRIO_MAX (+2) # endif -#endif +#endif // THREADAPI == THREADAPI_WINDOWS /* * Win32 and PTHREAD_TIMEDJOIN allow waiting for a thread with a timeout. * Posix without PTHREAD_TIMEDJOIN needs to use a condition variable approach. */ -#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) - bool_t THREAD_WAIT( THREAD_T *ref, double secs ); -#else - bool_t THREAD_WAIT( THREAD_T *ref, SIGNAL_T *signal_ref, MUTEX_T *mu_ref, volatile enum e_status *st_ref, double secs ); -#endif +#define THREADWAIT_TIMEOUT 1 +#define THREADWAIT_CONDVAR 2 + +#if THREADAPI == THREADAPI_WINDOWS || (defined PTHREAD_TIMEDJOIN) +#define THREADWAIT_METHOD THREADWAIT_TIMEOUT +#else // THREADAPI == THREADAPI_WINDOWS || (defined PTHREAD_TIMEDJOIN) +#define THREADWAIT_METHOD THREADWAIT_CONDVAR +#endif // THREADAPI == THREADAPI_WINDOWS || (defined PTHREAD_TIMEDJOIN) + + +#if THREADWAIT_METHOD == THREADWAIT_TIMEOUT +bool_t THREAD_WAIT_IMPL( THREAD_T *ref, double secs); +#define THREAD_WAIT( a, b, c, d, e) THREAD_WAIT_IMPL( a, b) +#else // THREADWAIT_METHOD == THREADWAIT_CONDVAR +bool_t THREAD_WAIT_IMPL( THREAD_T *ref, double secs, SIGNAL_T *signal_ref, MUTEX_T *mu_ref, volatile enum e_status *st_ref); +#define THREAD_WAIT THREAD_WAIT_IMPL +#endif // // THREADWAIT_METHOD == THREADWAIT_CONDVAR void THREAD_KILL( THREAD_T *ref ); -#endif - // THREADING_H +#endif // __threading_h__ -- cgit v1.2.3-55-g6feb