diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/keeper.c | 9 | ||||
| -rw-r--r-- | src/lanes.c | 68 | ||||
| -rw-r--r-- | src/threading.c | 12 | ||||
| -rw-r--r-- | src/threading.h | 12 | ||||
| -rw-r--r-- | src/tools.c | 9 | ||||
| -rw-r--r-- | src/tools.h | 11 |
6 files changed, 89 insertions, 32 deletions
diff --git a/src/keeper.c b/src/keeper.c index 8da3c08..99f510b 100644 --- a/src/keeper.c +++ b/src/keeper.c | |||
| @@ -567,8 +567,7 @@ void close_keepers( void) | |||
| 567 | char const* init_keepers( lua_State* L) | 567 | char const* init_keepers( lua_State* L) |
| 568 | { | 568 | { |
| 569 | int i; | 569 | int i; |
| 570 | void* allocUD; | 570 | PROPAGATE_ALLOCF_PREP( L); |
| 571 | lua_Alloc allocF = lua_getallocf( L, &allocUD); | ||
| 572 | 571 | ||
| 573 | STACK_CHECK( L); | 572 | STACK_CHECK( L); |
| 574 | lua_getfield( L, 1, "nb_keepers"); | 573 | lua_getfield( L, 1, "nb_keepers"); |
| @@ -580,10 +579,10 @@ char const* init_keepers( lua_State* L) | |||
| 580 | GKeepers = malloc( GNbKeepers * sizeof( struct s_Keeper)); | 579 | GKeepers = malloc( GNbKeepers * sizeof( struct s_Keeper)); |
| 581 | for( i = 0; i < GNbKeepers; ++ i) | 580 | for( i = 0; i < GNbKeepers; ++ i) |
| 582 | { | 581 | { |
| 583 | lua_State* K = lua_newstate( allocF, allocUD); | 582 | lua_State* K = PROPAGATE_ALLOCF_ALLOC(); |
| 584 | if( K == NULL) | 583 | if( K == NULL) |
| 585 | { | 584 | { |
| 586 | (void) luaL_error( L, "'lua_newstate()' failed while creating keeper state; out of memory"); | 585 | (void) luaL_error( L, "init_keepers() failed while creating keeper state; out of memory"); |
| 587 | } | 586 | } |
| 588 | STACK_CHECK( K); | 587 | STACK_CHECK( K); |
| 589 | 588 | ||
| @@ -627,7 +626,7 @@ struct s_Keeper* keeper_acquire( void const* ptr) | |||
| 627 | * have to cast to unsigned long to avoid compilation warnings about loss of data when converting pointer-to-integer | 626 | * have to cast to unsigned long to avoid compilation warnings about loss of data when converting pointer-to-integer |
| 628 | */ | 627 | */ |
| 629 | unsigned int i = (unsigned int)(((unsigned long)(ptr) >> 3) % GNbKeepers); | 628 | unsigned int i = (unsigned int)(((unsigned long)(ptr) >> 3) % GNbKeepers); |
| 630 | struct s_Keeper* K = &GKeepers[i]; | 629 | struct s_Keeper *K= &GKeepers[i]; |
| 631 | 630 | ||
| 632 | MUTEX_LOCK( &K->lock_); | 631 | MUTEX_LOCK( &K->lock_); |
| 633 | //++ K->count; | 632 | //++ K->count; |
diff --git a/src/lanes.c b/src/lanes.c index 53ed5e4..9e32f9a 100644 --- a/src/lanes.c +++ b/src/lanes.c | |||
| @@ -52,7 +52,7 @@ | |||
| 52 | * ... | 52 | * ... |
| 53 | */ | 53 | */ |
| 54 | 54 | ||
| 55 | char const* VERSION = "3.7.2"; | 55 | char const* VERSION = "3.7.3"; |
| 56 | 56 | ||
| 57 | /* | 57 | /* |
| 58 | =============================================================================== | 58 | =============================================================================== |
| @@ -1197,7 +1197,7 @@ typedef enum | |||
| 1197 | CR_Killed | 1197 | CR_Killed |
| 1198 | } cancel_result; | 1198 | } cancel_result; |
| 1199 | 1199 | ||
| 1200 | static cancel_result thread_cancel( struct s_lane *s, double secs, bool_t force) | 1200 | static cancel_result thread_cancel( lua_State* L, struct s_lane* s, double secs, bool_t force, double waitkill_timeout_) |
| 1201 | { | 1201 | { |
| 1202 | cancel_result result; | 1202 | cancel_result result; |
| 1203 | 1203 | ||
| @@ -1239,6 +1239,15 @@ static cancel_result thread_cancel( struct s_lane *s, double secs, bool_t force) | |||
| 1239 | // PThread seems to have). | 1239 | // PThread seems to have). |
| 1240 | // | 1240 | // |
| 1241 | THREAD_KILL( &s->thread); | 1241 | THREAD_KILL( &s->thread); |
| 1242 | #if THREADAPI == THREADAPI_PTHREAD | ||
| 1243 | // pthread: make sure the thread is really stopped! | ||
| 1244 | // note that this may block forever if the lane doesn't call a cancellation point and pthread doesn't honor PTHREAD_CANCEL_ASYNCHRONOUS | ||
| 1245 | result = THREAD_WAIT( &s->thread, waitkill_timeout_, &s->done_signal, &s->done_lock, &s->status); | ||
| 1246 | if( result == CR_Timeout) | ||
| 1247 | { | ||
| 1248 | return luaL_error( L, "force-killed lane failed to terminate within %f second%s", waitkill_timeout_, waitkill_timeout_ > 1 ? "s" : ""); | ||
| 1249 | } | ||
| 1250 | #endif // THREADAPI == THREADAPI_PTHREAD | ||
| 1242 | s->mstatus = KILLED; // mark 'gc' to wait for it | 1251 | s->mstatus = KILLED; // mark 'gc' to wait for it |
| 1243 | // note that s->status value must remain to whatever it was at the time of the kill | 1252 | // note that s->status value must remain to whatever it was at the time of the kill |
| 1244 | // because we need to know if we can lua_close() the Lua State or not. | 1253 | // because we need to know if we can lua_close() the Lua State or not. |
| @@ -1357,7 +1366,7 @@ static int selfdestruct_gc( lua_State* L) | |||
| 1357 | while( s != SELFDESTRUCT_END) | 1366 | while( s != SELFDESTRUCT_END) |
| 1358 | { | 1367 | { |
| 1359 | // attempt a regular unforced hard cancel with a small timeout | 1368 | // attempt a regular unforced hard cancel with a small timeout |
| 1360 | bool_t cancelled = THREAD_ISNULL( s->thread) || thread_cancel( s, 0.0001, FALSE); | 1369 | bool_t cancelled = THREAD_ISNULL( s->thread) || thread_cancel( L, s, 0.0001, FALSE, 0.0); |
| 1361 | // if we failed, and we know the thread is waiting on a linda | 1370 | // if we failed, and we know the thread is waiting on a linda |
| 1362 | if( cancelled == FALSE && s->status == WAITING && s->waiting_on != NULL) | 1371 | if( cancelled == FALSE && s->status == WAITING && s->waiting_on != NULL) |
| 1363 | { | 1372 | { |
| @@ -1758,6 +1767,17 @@ static char const* get_errcode_name( int _code) | |||
| 1758 | } | 1767 | } |
| 1759 | #endif // USE_DEBUG_SPEW | 1768 | #endif // USE_DEBUG_SPEW |
| 1760 | 1769 | ||
| 1770 | #if THREADWAIT_METHOD == THREADWAIT_CONDVAR // implies THREADAPI == THREADAPI_PTHREAD | ||
| 1771 | static void thread_cleanup_handler( void* opaque) | ||
| 1772 | { | ||
| 1773 | struct s_lane* s= (struct s_lane*) opaque; | ||
| 1774 | MUTEX_LOCK( &s->done_lock); | ||
| 1775 | s->status = CANCELLED; | ||
| 1776 | SIGNAL_ONE( &s->done_signal); // wake up master (while 's->done_lock' is on) | ||
| 1777 | MUTEX_UNLOCK( &s->done_lock); | ||
| 1778 | } | ||
| 1779 | #endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR | ||
| 1780 | |||
| 1761 | //--- | 1781 | //--- |
| 1762 | static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) | 1782 | static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) |
| 1763 | { | 1783 | { |
| @@ -1770,7 +1790,8 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) | |||
| 1770 | tracking_add( s); | 1790 | tracking_add( s); |
| 1771 | } | 1791 | } |
| 1772 | #endif // HAVE_LANE_TRACKING | 1792 | #endif // HAVE_LANE_TRACKING |
| 1773 | 1793 | THREAD_MAKE_ASYNCH_CANCELLABLE(); | |
| 1794 | THREAD_CLEANUP_PUSH( thread_cleanup_handler, s); | ||
| 1774 | s->status= RUNNING; // PENDING -> RUNNING | 1795 | s->status= RUNNING; // PENDING -> RUNNING |
| 1775 | 1796 | ||
| 1776 | // Tie "set_finalizer()" to the state | 1797 | // Tie "set_finalizer()" to the state |
| @@ -1888,7 +1909,7 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) | |||
| 1888 | : ERROR_ST; | 1909 | : ERROR_ST; |
| 1889 | 1910 | ||
| 1890 | // Posix no PTHREAD_TIMEDJOIN: | 1911 | // Posix no PTHREAD_TIMEDJOIN: |
| 1891 | // 'done_lock' protects the -> DONE|ERROR_ST|CANCELLED state change | 1912 | // 'done_lock' protects the -> DONE|ERROR_ST|CANCELLED state change |
| 1892 | // | 1913 | // |
| 1893 | #if THREADWAIT_METHOD == THREADWAIT_CONDVAR | 1914 | #if THREADWAIT_METHOD == THREADWAIT_CONDVAR |
| 1894 | MUTEX_LOCK( &s->done_lock); | 1915 | MUTEX_LOCK( &s->done_lock); |
| @@ -1901,6 +1922,7 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) | |||
| 1901 | MUTEX_UNLOCK( &s->done_lock); | 1922 | MUTEX_UNLOCK( &s->done_lock); |
| 1902 | #endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR | 1923 | #endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR |
| 1903 | } | 1924 | } |
| 1925 | THREAD_CLEANUP_POP( FALSE); | ||
| 1904 | return 0; // ignored | 1926 | return 0; // ignored |
| 1905 | } | 1927 | } |
| 1906 | 1928 | ||
| @@ -2248,6 +2270,7 @@ LUAG_FUNC( thread_gc) | |||
| 2248 | return 0; | 2270 | return 0; |
| 2249 | } | 2271 | } |
| 2250 | 2272 | ||
| 2273 | // lane_h:cancel( [timeout,] force[, forcekill_timeout]) | ||
| 2251 | LUAG_FUNC( thread_cancel) | 2274 | LUAG_FUNC( thread_cancel) |
| 2252 | { | 2275 | { |
| 2253 | if( lua_gettop( L) < 1 || lua_type( L, 1) != LUA_TUSERDATA) | 2276 | if( lua_gettop( L) < 1 || lua_type( L, 1) != LUA_TUSERDATA) |
| @@ -2258,9 +2281,8 @@ LUAG_FUNC( thread_cancel) | |||
| 2258 | { | 2281 | { |
| 2259 | struct s_lane* s = lua_toLane( L, 1); | 2282 | struct s_lane* s = lua_toLane( L, 1); |
| 2260 | double secs = 0.0; | 2283 | double secs = 0.0; |
| 2261 | uint_t force_i = 2; | 2284 | int force_i = 2; |
| 2262 | cancel_result result; | 2285 | int forcekill_timeout_i = 3; |
| 2263 | bool_t force; | ||
| 2264 | 2286 | ||
| 2265 | if( lua_isnumber( L, 2)) | 2287 | if( lua_isnumber( L, 2)) |
| 2266 | { | 2288 | { |
| @@ -2270,30 +2292,34 @@ LUAG_FUNC( thread_cancel) | |||
| 2270 | return luaL_error( L, "can't force a soft cancel"); | 2292 | return luaL_error( L, "can't force a soft cancel"); |
| 2271 | } | 2293 | } |
| 2272 | ++ force_i; | 2294 | ++ force_i; |
| 2295 | ++ forcekill_timeout_i; | ||
| 2273 | } | 2296 | } |
| 2274 | else if( lua_isnil( L, 2)) | 2297 | else if( lua_isnil( L, 2)) |
| 2275 | { | 2298 | { |
| 2276 | ++ force_i; | 2299 | ++ force_i; |
| 2300 | ++ forcekill_timeout_i; | ||
| 2277 | } | 2301 | } |
| 2278 | 2302 | ||
| 2279 | force = lua_toboolean( L, force_i); // FALSE if nothing there | ||
| 2280 | |||
| 2281 | result = thread_cancel( s, secs, force); | ||
| 2282 | switch( result) | ||
| 2283 | { | 2303 | { |
| 2304 | bool_t force = lua_toboolean( L, force_i); // FALSE if nothing there | ||
| 2305 | double forcekill_timeout = luaL_optnumber( L, forcekill_timeout_i, 0.0); | ||
| 2306 | |||
| 2307 | switch( thread_cancel( L, s, secs, force, forcekill_timeout)) | ||
| 2308 | { | ||
| 2284 | case CR_Timeout: | 2309 | case CR_Timeout: |
| 2285 | lua_pushboolean( L, 0); | 2310 | lua_pushboolean( L, 0); |
| 2286 | lua_pushstring( L, "timeout"); | 2311 | lua_pushstring( L, "timeout"); |
| 2287 | return 2; | 2312 | return 2; |
| 2288 | 2313 | ||
| 2289 | case CR_Cancelled: | 2314 | case CR_Cancelled: |
| 2290 | lua_pushboolean( L, 1); | 2315 | lua_pushboolean( L, 1); |
| 2291 | return 1; | 2316 | return 1; |
| 2292 | 2317 | ||
| 2293 | case CR_Killed: | 2318 | case CR_Killed: |
| 2294 | lua_pushboolean( L, 0); | 2319 | lua_pushboolean( L, 0); |
| 2295 | lua_pushstring( L, "killed"); | 2320 | lua_pushstring( L, "killed"); |
| 2296 | return 2; | 2321 | return 2; |
| 2322 | } | ||
| 2297 | } | 2323 | } |
| 2298 | } | 2324 | } |
| 2299 | // should never happen, only here to prevent the compiler from complaining of "not all control paths returning a value" | 2325 | // should never happen, only here to prevent the compiler from complaining of "not all control paths returning a value" |
diff --git a/src/threading.c b/src/threading.c index 63c39ae..ad5b473 100644 --- a/src/threading.c +++ b/src/threading.c | |||
| @@ -330,6 +330,8 @@ bool_t THREAD_WAIT_IMPL( THREAD_T *ref, double secs) | |||
| 330 | *ref= NULL; | 330 | *ref= NULL; |
| 331 | } | 331 | } |
| 332 | 332 | ||
| 333 | void THREAD_MAKE_ASYNCH_CANCELLABLE() {} // nothing to do for windows threads, we can cancel them anytime we want | ||
| 334 | |||
| 333 | #if !defined __GNUC__ | 335 | #if !defined __GNUC__ |
| 334 | //see http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx | 336 | //see http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx |
| 335 | #define MS_VC_EXCEPTION 0x406D1388 | 337 | #define MS_VC_EXCEPTION 0x406D1388 |
| @@ -896,11 +898,19 @@ bool_t THREAD_WAIT( THREAD_T *ref, double secs , SIGNAL_T *signal_ref, MUTEX_T * | |||
| 896 | #endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR | 898 | #endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR |
| 897 | return done; | 899 | return done; |
| 898 | } | 900 | } |
| 899 | // | 901 | // |
| 900 | void THREAD_KILL( THREAD_T *ref ) { | 902 | void THREAD_KILL( THREAD_T *ref ) { |
| 901 | pthread_cancel( *ref ); | 903 | pthread_cancel( *ref ); |
| 902 | } | 904 | } |
| 903 | 905 | ||
| 906 | void THREAD_MAKE_ASYNCH_CANCELLABLE() | ||
| 907 | { | ||
| 908 | // that's the default, but just in case... | ||
| 909 | pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); | ||
| 910 | // we want cancellation to take effect immediately if possible, instead of waiting for a cancellation point (which is the default) | ||
| 911 | pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL); | ||
| 912 | } | ||
| 913 | |||
| 904 | void THREAD_SETNAME( char const* _name) | 914 | void THREAD_SETNAME( char const* _name) |
| 905 | { | 915 | { |
| 906 | // exact API to set the thread name is platform-dependant | 916 | // exact API to set the thread name is platform-dependant |
diff --git a/src/threading.h b/src/threading.h index aa34248..4b28ce8 100644 --- a/src/threading.h +++ b/src/threading.h | |||
| @@ -194,10 +194,16 @@ bool_t SIGNAL_WAIT( SIGNAL_T *ref, MUTEX_T *mu, time_d timeout ); | |||
| 194 | # define THREAD_PRIO_MIN (-3) | 194 | # define THREAD_PRIO_MIN (-3) |
| 195 | # define THREAD_PRIO_MAX (+3) | 195 | # define THREAD_PRIO_MAX (+3) |
| 196 | 196 | ||
| 197 | #define THREAD_CLEANUP_PUSH( cb_, val_) | ||
| 198 | #define THREAD_CLEANUP_POP( execute_) | ||
| 199 | |||
| 197 | #else // THREADAPI == THREADAPI_PTHREAD | 200 | #else // THREADAPI == THREADAPI_PTHREAD |
| 198 | /* Platforms that have a timed 'pthread_join()' can get away with a simpler | 201 | /* Platforms that have a timed 'pthread_join()' can get away with a simpler |
| 199 | * implementation. Others will use a condition variable. | 202 | * implementation. Others will use a condition variable. |
| 200 | */ | 203 | */ |
| 204 | #if defined __WINPTHREADS_VERSION | ||
| 205 | #define USE_PTHREAD_TIMEDJOIN | ||
| 206 | #endif // __WINPTHREADS_VERSION | ||
| 201 | # ifdef USE_PTHREAD_TIMEDJOIN | 207 | # ifdef USE_PTHREAD_TIMEDJOIN |
| 202 | # ifdef PLATFORM_OSX | 208 | # ifdef PLATFORM_OSX |
| 203 | # error "No 'pthread_timedjoin()' on this system" | 209 | # error "No 'pthread_timedjoin()' on this system" |
| @@ -229,6 +235,9 @@ bool_t SIGNAL_WAIT( SIGNAL_T *ref, MUTEX_T *mu, time_d timeout ); | |||
| 229 | # define THREAD_PRIO_MIN (-2) | 235 | # define THREAD_PRIO_MIN (-2) |
| 230 | # define THREAD_PRIO_MAX (+2) | 236 | # define THREAD_PRIO_MAX (+2) |
| 231 | # endif | 237 | # endif |
| 238 | |||
| 239 | #define THREAD_CLEANUP_PUSH( cb_, val_) pthread_cleanup_push( cb_, val_) | ||
| 240 | #define THREAD_CLEANUP_POP( execute_) pthread_cleanup_pop( execute_) | ||
| 232 | #endif // THREADAPI == THREADAPI_WINDOWS | 241 | #endif // THREADAPI == THREADAPI_WINDOWS |
| 233 | 242 | ||
| 234 | /* | 243 | /* |
| @@ -253,7 +262,8 @@ bool_t THREAD_WAIT_IMPL( THREAD_T *ref, double secs, SIGNAL_T *signal_ref, MUTEX | |||
| 253 | #define THREAD_WAIT THREAD_WAIT_IMPL | 262 | #define THREAD_WAIT THREAD_WAIT_IMPL |
| 254 | #endif // // THREADWAIT_METHOD == THREADWAIT_CONDVAR | 263 | #endif // // THREADWAIT_METHOD == THREADWAIT_CONDVAR |
| 255 | 264 | ||
| 256 | void THREAD_KILL( THREAD_T *ref ); | 265 | void THREAD_KILL( THREAD_T* ref); |
| 257 | void THREAD_SETNAME( char const* _name); | 266 | void THREAD_SETNAME( char const* _name); |
| 267 | void THREAD_MAKE_ASYNCH_CANCELLABLE(); | ||
| 258 | 268 | ||
| 259 | #endif // __threading_h__ | 269 | #endif // __threading_h__ |
diff --git a/src/tools.c b/src/tools.c index 754605b..b5f2f4b 100644 --- a/src/tools.c +++ b/src/tools.c | |||
| @@ -570,13 +570,14 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* name_) | |||
| 570 | lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char const* libs) | 570 | lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char const* libs) |
| 571 | { | 571 | { |
| 572 | // reuse alloc function from the originating state | 572 | // reuse alloc function from the originating state |
| 573 | void* allocUD; | 573 | #if PROPAGATE_ALLOCF |
| 574 | lua_Alloc allocF = lua_getallocf( _from, &allocUD); | 574 | PROPAGATE_ALLOCF_PREP( _from); |
| 575 | lua_State* L = lua_newstate( allocF, allocUD); | 575 | #endif // PROPAGATE_ALLOCF |
| 576 | lua_State* L = PROPAGATE_ALLOCF_ALLOC(); | ||
| 576 | 577 | ||
| 577 | if( L == NULL) | 578 | if( L == NULL) |
| 578 | { | 579 | { |
| 579 | (void) luaL_error( _from, "'lua_newstate()' failed; out of memory"); | 580 | (void) luaL_error( _from, "luaG_newstate() failed while creating state; out of memory"); |
| 580 | } | 581 | } |
| 581 | 582 | ||
| 582 | // we'll need this everytime we transfer some C function from/to this state | 583 | // we'll need this everytime we transfer some C function from/to this state |
diff --git a/src/tools.h b/src/tools.h index e984ec2..19dca70 100644 --- a/src/tools.h +++ b/src/tools.h | |||
| @@ -41,6 +41,17 @@ void luaL_requiref (lua_State* L, const char* modname, lua_CFunction openf, int | |||
| 41 | #define luaG_registerlibfuncs( L, _funcs) luaL_setfuncs( L, _funcs, 0) | 41 | #define luaG_registerlibfuncs( L, _funcs) luaL_setfuncs( L, _funcs, 0) |
| 42 | #endif // LUA_VERSION_NUM == 502 | 42 | #endif // LUA_VERSION_NUM == 502 |
| 43 | 43 | ||
| 44 | // For some reason, LuaJIT 64bits doesn't support lua_newstate() | ||
| 45 | // If you build specifically for this situation, change value to 0 | ||
| 46 | #define PROPAGATE_ALLOCF 1 | ||
| 47 | #if PROPAGATE_ALLOCF | ||
| 48 | #define PROPAGATE_ALLOCF_PREP( L) void* allocUD; lua_Alloc allocF = lua_getallocf( L, &allocUD) | ||
| 49 | #define PROPAGATE_ALLOCF_ALLOC() lua_newstate( allocF, allocUD) | ||
| 50 | #else // PROPAGATE_ALLOCF | ||
| 51 | #define PROPAGATE_ALLOCF_PREP( L) | ||
| 52 | #define PROPAGATE_ALLOCF_ALLOC() luaL_newstate() | ||
| 53 | #endif // PROPAGATE_ALLOCF | ||
| 54 | |||
| 44 | #define USE_DEBUG_SPEW 0 | 55 | #define USE_DEBUG_SPEW 0 |
| 45 | #if USE_DEBUG_SPEW | 56 | #if USE_DEBUG_SPEW |
| 46 | extern char const* debugspew_indent; | 57 | extern char const* debugspew_indent; |
