diff options
author | Benoit 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 |
---|---|---|
committer | Benoit 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 |
commit | ff74281fc94cda26b2d0a7fc2424f24fe2488718 (patch) | |
tree | 6e8aa44d300ccd5da451d02c08cee98090328b60 /src/lanes.c | |
parent | b4cd90c9e9a7898775d173df2267d1860dcbc699 (diff) | |
download | lanes-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/lanes.c')
-rw-r--r-- | src/lanes.c | 68 |
1 files changed, 47 insertions, 21 deletions
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" |