aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBenoit Germain <b n t DOT g e r m a i n AT g m a i l DOT c o m>2013-11-29 20:33:46 +0100
committerBenoit Germain <b n t DOT g e r m a i n AT g m a i l DOT c o m>2013-11-29 20:33:46 +0100
commitff74281fc94cda26b2d0a7fc2424f24fe2488718 (patch)
tree6e8aa44d300ccd5da451d02c08cee98090328b60 /src
parentb4cd90c9e9a7898775d173df2267d1860dcbc699 (diff)
downloadlanes-ff74281fc94cda26b2d0a7fc2424f24fe2488718.tar.gz
lanes-ff74281fc94cda26b2d0a7fc2424f24fe2488718.tar.bz2
lanes-ff74281fc94cda26b2d0a7fc2424f24fe2488718.zip
supposedly improved pthread support
* bumped version to 3.7.3 * set pthread thread cancel type to PTHREAD_CANCEL_ASYNCHRONOUS * lane_h:cancel() accepts a 3rd timeout argument used when waiting for actual thread termination (hitting the timeout raises an error) * added PROPAGATE_ALLOCF macro to select state creation mode (lua_newstate or luaL_newstate)
Diffstat (limited to 'src')
-rw-r--r--src/keeper.c9
-rw-r--r--src/lanes.c68
-rw-r--r--src/threading.c12
-rw-r--r--src/threading.h12
-rw-r--r--src/tools.c9
-rw-r--r--src/tools.h11
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)
567char const* init_keepers( lua_State* L) 567char 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
55char const* VERSION = "3.7.2"; 55char 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
1200static cancel_result thread_cancel( struct s_lane *s, double secs, bool_t force) 1200static 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
1771static 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//---
1762static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) 1782static 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])
2251LUAG_FUNC( thread_cancel) 2274LUAG_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
256void THREAD_KILL( THREAD_T *ref ); 265void THREAD_KILL( THREAD_T* ref);
257void THREAD_SETNAME( char const* _name); 266void THREAD_SETNAME( char const* _name);
267void 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_)
570lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char const* libs) 570lua_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
46extern char const* debugspew_indent; 57extern char const* debugspew_indent;