aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES6
-rw-r--r--docs/index.html6
-rw-r--r--src/lanes.c413
3 files changed, 218 insertions, 207 deletions
diff --git a/CHANGES b/CHANGES
index 7bda6f3..3a7ff89 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,11 @@
1CHANGES: 1CHANGES:
2 2
3CHANGE 108: BGe 20-Mar-14
4 * bumped version to 3.9.4
5 * set_finalizer throws an error if provided finalizer isn't a function
6 * fix error handling when the error doesn't generate an error handler call (IOW, all errors but LUA_ERRRUN)
7 * provide callstack if LUA_ERRRUN occurs inside a finalizer
8
3CHANGE 107: BGe 19-Mar-14 9CHANGE 107: BGe 19-Mar-14
4 * Make sure we don't mutex-wrap require() more than once, just in case 10 * Make sure we don't mutex-wrap require() more than once, just in case
5 11
diff --git a/docs/index.html b/docs/index.html
index c4a6441..da5da71 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -70,7 +70,7 @@
70 </p> 70 </p>
71 71
72 <p> 72 <p>
73 This document was revised on 27-Feb-14, and applies to version <tt>3.9.3</tt>. 73 This document was revised on 20-Mar-14, and applies to version <tt>3.9.4</tt>.
74 </p> 74 </p>
75 </font> 75 </font>
76 </center> 76 </center>
@@ -253,6 +253,10 @@
253 At the same time, <tt>configure()</tt> itself will be replaced by another function that raises an error if called again with differing arguments, if any. 253 At the same time, <tt>configure()</tt> itself will be replaced by another function that raises an error if called again with differing arguments, if any.
254</p> 254</p>
255<p> 255<p>
256 Also, once Lanes is initialized, <tt>require()</tt> is replaced by another one that wraps it inside a mutex, both in the main state and in all created lanes. This prevents multiple thread-unsafe module initializations from several lanes to occur simultaneously.
257 It remains to be seen whether this is actually useful or not: If a module is already threadsafe, protecting its initialization isn't useful. And if it is not, any parallel operation may crash without Lanes being able to do anything about it.
258</p>
259<p>
256 <b>IMPORTANT NOTE:</b> Starting with version 3.7.0, only the first occurence of <tt>require "lanes"</tt> must be followed by a call to <tt>.configure()</tt>. From this point, a simple <tt>require "lanes"</tt> will do wherever you need to require lanes again. 260 <b>IMPORTANT NOTE:</b> Starting with version 3.7.0, only the first occurence of <tt>require "lanes"</tt> must be followed by a call to <tt>.configure()</tt>. From this point, a simple <tt>require "lanes"</tt> will do wherever you need to require lanes again.
257</p> 261</p>
258 262
diff --git a/src/lanes.c b/src/lanes.c
index 6b3264a..9e79f64 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -52,7 +52,7 @@
52 * ... 52 * ...
53 */ 53 */
54 54
55char const* VERSION = "3.9.3"; 55char const* VERSION = "3.9.4";
56 56
57/* 57/*
58=============================================================================== 58===============================================================================
@@ -293,26 +293,29 @@ struct s_Linda;
293* Returns: TRUE if a table was pushed 293* Returns: TRUE if a table was pushed
294* FALSE if no table found, not created, and nothing pushed 294* FALSE if no table found, not created, and nothing pushed
295*/ 295*/
296static bool_t push_registry_table( lua_State*L, void *key, bool_t create ) { 296static bool_t push_registry_table( lua_State* L, void* key, bool_t create)
297 297{
298 STACK_GROW(L,3); 298 STACK_GROW( L, 3);
299 299 STACK_CHECK( L);
300 lua_pushlightuserdata( L, key ); 300 lua_pushlightuserdata( L, key); // key
301 lua_gettable( L, LUA_REGISTRYINDEX ); 301 lua_gettable( L, LUA_REGISTRYINDEX); // t?
302 302
303 if (lua_isnil(L,-1)) { 303 if( lua_isnil( L, -1)) // nil?
304 lua_pop(L,1); 304 {
305 305 lua_pop( L, 1); //
306 if (!create) return FALSE; // nothing pushed 306
307 307 if( !create)
308 lua_newtable(L); 308 {
309 lua_pushlightuserdata( L, key ); 309 return FALSE;
310 lua_pushvalue(L,-2); // duplicate of the table 310 }
311 lua_settable( L, LUA_REGISTRYINDEX ); 311
312 312 lua_newtable(L); // t
313 // [-1]: table that's also bound in registry 313 lua_pushlightuserdata( L, key); // t key
314 } 314 lua_pushvalue( L, -2); // t key t
315 return TRUE; // table pushed 315 lua_rawset( L, LUA_REGISTRYINDEX); // t
316 }
317 STACK_END( L, 1);
318 return TRUE; // table pushed
316} 319}
317 320
318#if HAVE_LANE_TRACKING 321#if HAVE_LANE_TRACKING
@@ -1281,20 +1284,18 @@ LUAG_FUNC( linda)
1281// Add a function that will be called when exiting the lane, either via 1284// Add a function that will be called when exiting the lane, either via
1282// normal return or an error. 1285// normal return or an error.
1283// 1286//
1284LUAG_FUNC( set_finalizer ) 1287LUAG_FUNC( set_finalizer)
1285{ 1288{
1286 STACK_GROW(L,3); 1289 luaL_argcheck( L, lua_isfunction( L, 1), 1, "finalizer should be a function");
1287 1290 luaL_argcheck( L, lua_gettop( L) == 1, 1, "too many arguments");
1288 // Get the current finalizer table (if any) 1291 // Get the current finalizer table (if any)
1289 // 1292 push_registry_table( L, FINALIZER_REG_KEY, TRUE /*do create if none*/); // finalizer {finalisers}
1290 push_registry_table( L, FINALIZER_REG_KEY, TRUE /*do create if none*/ ); 1293 STACK_GROW( L, 2);
1291 1294 lua_pushinteger( L, lua_rawlen( L, -1) + 1); // finalizer {finalisers} idx
1292 lua_pushinteger( L, lua_rawlen(L,-1)+1 ); 1295 lua_pushvalue( L, 1); // finalizer {finalisers} idx finalizer
1293 lua_pushvalue( L, 1 ); // copy of the function 1296 lua_rawset( L, -3); // finalizer {finalisers}
1294 lua_settable( L, -3 ); 1297 lua_pop( L, 2); //
1295 1298 return 0;
1296 lua_pop(L,1);
1297 return 0;
1298} 1299}
1299 1300
1300 1301
@@ -1311,14 +1312,15 @@ LUAG_FUNC( set_finalizer )
1311// 1312//
1312// TBD: should we add stack trace on failing finalizer, wouldn't be hard.. 1313// TBD: should we add stack trace on failing finalizer, wouldn't be hard..
1313// 1314//
1315static void push_stack_trace( lua_State* L, int rc_, int stk_base_);
1316
1314static int run_finalizers( lua_State* L, int lua_rc) 1317static int run_finalizers( lua_State* L, int lua_rc)
1315{ 1318{
1316 int error_index, finalizers_index; 1319 int finalizers_index;
1317 int n; 1320 int n;
1318 int err_handler_index = 0; 1321 int err_handler_index = 0;
1319 int rc = 0; // [err_msg {stack_trace}]? 1322 int rc = LUA_OK; // ...
1320 1323 if( !push_registry_table( L, FINALIZER_REG_KEY, FALSE)) // ... finalizers?
1321 if( !push_registry_table( L, FINALIZER_REG_KEY, FALSE)) // [err_msg {stack_trace}]? {func [, ...]}?
1322 { 1324 {
1323 return 0; // no finalizers 1325 return 0; // no finalizers
1324 } 1326 }
@@ -1328,51 +1330,58 @@ static int run_finalizers( lua_State* L, int lua_rc)
1328 finalizers_index = lua_gettop( L); 1330 finalizers_index = lua_gettop( L);
1329 1331
1330#if ERROR_FULL_STACK 1332#if ERROR_FULL_STACK
1331 lua_pushcfunction( L, lane_error); // [err_msg {stack_trace}]? {func [, ...]}? lane_error 1333 lua_pushcfunction( L, lane_error); // ... finalizers lane_error
1332 err_handler_index = lua_gettop( L); 1334 err_handler_index = lua_gettop( L);
1333#endif // ERROR_FULL_STACK 1335#endif // ERROR_FULL_STACK
1334 error_index = (lua_rc != LUA_OK) ? finalizers_index - (1 + ERROR_FULL_STACK) : 0;
1335 1336
1336 for( n = (int) lua_rawlen( L, finalizers_index); n > 0; -- n) 1337 for( n = (int) lua_rawlen( L, finalizers_index); n > 0; -- n)
1337 { 1338 {
1338 int args = 0; 1339 int args = 0;
1339 lua_pushinteger( L, n); // [err_msg {stack_trace}]? {func [, ...]}? lane_error n 1340 lua_pushinteger( L, n); // ... finalizers lane_error n
1340 lua_gettable( L, finalizers_index); // [err_msg {stack_trace}]? {func [, ...]}? lane_error finalizer 1341 lua_rawget( L, finalizers_index); // ... finalizers lane_error finalizer
1341 ASSERT_L( lua_isfunction( L, -1)); 1342 ASSERT_L( lua_isfunction( L, -1));
1342 if( error_index) 1343 if( lua_rc != LUA_OK) // we have an error message and an optional stack trace at the bottom of the stack
1343 { 1344 {
1344 //char const* err_msg = lua_tostring( L, error_index); 1345 ASSERT_L( finalizers_index == 2 || finalizers_index == 3);
1345 lua_pushvalue( L, error_index); // [err_msg {stack_trace}]? {func [, ...]}? lane_error finalizer err_msg 1346 //char const* err_msg = lua_tostring( L, 1);
1346#if ERROR_FULL_STACK 1347 lua_pushvalue( L, 1); // ... finalizers lane_error finalizer err_msg
1347 lua_pushvalue( L, error_index + 1); // [err_msg {stack_trace}]? {func [, ...]}? lane_error finalizer err_msg {stack_trace} 1348 // note we don't always have a stack trace for example when CANCEL_ERROR, or when we got an error that doesn't call our handler, such as LUA_ERRMEM
1348#endif // ERROR_FULL_STACK 1349 if( finalizers_index == 3)
1349 args = 1 + ERROR_FULL_STACK; 1350 {
1351 lua_pushvalue( L, 2); // ... finalizers lane_error finalizer err_msg stack_trace
1352 }
1353 args = finalizers_index - 1;
1350 } 1354 }
1351 1355
1352 rc = lua_pcall( L, args, 0, err_handler_index); // [err_msg {stack_trace}]? {func [, ...]}? lane_error err_msg2? 1356 // if no error from the main body, finlizer doesn't receive any argument, else it gets the error message and optional stack trace
1353 // 1357 rc = lua_pcall( L, args, 0, err_handler_index); // ... finalizers lane_error err_msg2?
1354 // LUA_ERRRUN / LUA_ERRMEM
1355
1356 if( rc != LUA_OK) 1358 if( rc != LUA_OK)
1357 { 1359 {
1358#if ERROR_FULL_STACK 1360 push_stack_trace( L, rc, lua_gettop( L));
1359 lua_pushlightuserdata( L, STACK_TRACE_KEY); // [err_msg {stack_trace}]? {func [, ...]}? lane_error err_msg2 STACK_TRACE_KEY
1360 lua_gettable( L, LUA_REGISTRYINDEX); // [err_msg {stack_trace}]? {func [, ...]}? lane_error err_msg2 {stack_trace2}
1361#endif // ERROR_FULL_STACK
1362
1363 // If one finalizer fails, don't run the others. Return this 1361 // If one finalizer fails, don't run the others. Return this
1364 // as the 'real' error, replacing what we could have had (or not) 1362 // as the 'real' error, replacing what we could have had (or not)
1365 // from the actual code. 1363 // from the actual code.
1366 //
1367 break; 1364 break;
1368 } 1365 }
1366 // no error, proceed to next finalizer // ... finalizers lane_error
1369 } 1367 }
1370 1368
1371 // remove error handler function (if any) and finalizers table from the stack 1369 if( rc != LUA_OK)
1372#if ERROR_FULL_STACK 1370 {
1373 lua_remove( L, err_handler_index); // [err_msg {stack_trace}]? {func [, ...]}? err_msg2 {stack_trace2} 1371 // ERROR_FULL_STACK accounts for the presence of lane_error on the stack
1374#endif // ERROR_FULL_STACK 1372 int nb_err_slots = lua_gettop( L) - finalizers_index - ERROR_FULL_STACK;
1375 lua_remove( L, finalizers_index); // [err_msg {stack_trace}]? err_msg2 {stack_trace2} 1373 // a finalizer generated an error, this is what we leave of the stack
1374 for( n = nb_err_slots; n > 0; -- n)
1375 {
1376 lua_replace( L, n);
1377 }
1378 // leave on the stack only the error and optional stack trace produced by the error in the finalizer
1379 lua_settop( L, nb_err_slots);
1380 }
1381 else // no error from the finalizers, make sure only the original return values from the lane body remain on the stack
1382 {
1383 lua_settop( L, finalizers_index - 1);
1384 }
1376 1385
1377 return rc; 1386 return rc;
1378} 1387}
@@ -1896,6 +1905,40 @@ static int lane_error( lua_State* L)
1896} 1905}
1897#endif // ERROR_FULL_STACK 1906#endif // ERROR_FULL_STACK
1898 1907
1908static void push_stack_trace( lua_State* L, int rc_, int stk_base_)
1909{
1910 // Lua 5.1 error handler is limited to one return value; it stored the stack trace in the registry
1911 switch( rc_)
1912 {
1913 case LUA_OK: // no error, body return values are on the stack
1914 break;
1915
1916 case LUA_ERRRUN: // cancellation or a runtime error
1917#if ERROR_FULL_STACK // when ERROR_FULL_STACK, we installed a handler
1918 {
1919 // fetch the call stack table from the registry where the handler stored it
1920 STACK_GROW( L, 1);
1921 lua_pushlightuserdata( L, STACK_TRACE_KEY); // err STACK_TRACE_KEY
1922 // yields nil if no stack was generated (in case of cancellation for example)
1923 lua_gettable( L, LUA_REGISTRYINDEX); // err trace|nil
1924
1925 // For cancellation the error message is CANCEL_ERROR, and a stack trace isn't placed
1926 // For other errors, the message should be a string, and we should have a stack trace table
1927 ASSERT_L( (lua_istable( L, 1 + stk_base_) && lua_type( L, stk_base_) == LUA_TSTRING) || (lua_touserdata( L, stk_base_) == CANCEL_ERROR));
1928 // Just leaving the stack trace table on the stack is enough to get it through to the master.
1929 break;
1930 }
1931#endif // fall through if not ERROR_FULL_STACK
1932
1933 case LUA_ERRMEM: // memory allocation error (handler not called)
1934 case LUA_ERRERR: // error while running the error handler (if any, for example an out-of-memory condition)
1935 default:
1936 // we should have a single value which is either a string (the error message) or CANCEL_ERROR
1937 ASSERT_L( (lua_gettop( L) == stk_base_) && ((lua_type( L, stk_base_) == LUA_TSTRING) || (lua_touserdata( L, stk_base_) == CANCEL_ERROR)));
1938 break;
1939 }
1940}
1941
1899LUAG_FUNC( set_debug_threadname) 1942LUAG_FUNC( set_debug_threadname)
1900{ 1943{
1901 // C s_lane structure is a light userdata upvalue 1944 // C s_lane structure is a light userdata upvalue
@@ -1979,152 +2022,107 @@ static void thread_cleanup_handler( void* opaque)
1979} 2022}
1980#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR 2023#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
1981 2024
1982//---
1983static THREAD_RETURN_T THREAD_CALLCONV lane_main( void* vs) 2025static THREAD_RETURN_T THREAD_CALLCONV lane_main( void* vs)
1984{ 2026{
1985 struct s_lane* s = (struct s_lane*) vs; 2027 struct s_lane* s = (struct s_lane*) vs;
1986 int rc, rc2; 2028 int rc, rc2;
1987 lua_State* L = s->L; 2029 lua_State* L = s->L;
1988 DEBUGSPEW_CODE( struct s_Universe* U = get_universe( L)); 2030 // Called with the lane function and arguments on the stack
2031 int const nargs = lua_gettop( L) - 1;
2032 DEBUGSPEW_CODE( struct s_Universe* U = get_universe( L));
1989#if HAVE_LANE_TRACKING 2033#if HAVE_LANE_TRACKING
1990 if( s->U->tracking_first) 2034 if( s->U->tracking_first)
1991 { 2035 {
1992 tracking_add( s); 2036 tracking_add( s);
1993 } 2037 }
1994#endif // HAVE_LANE_TRACKING 2038#endif // HAVE_LANE_TRACKING
1995 THREAD_MAKE_ASYNCH_CANCELLABLE(); 2039 THREAD_MAKE_ASYNCH_CANCELLABLE();
1996 THREAD_CLEANUP_PUSH( thread_cleanup_handler, s); 2040 THREAD_CLEANUP_PUSH( thread_cleanup_handler, s);
1997 s->status = RUNNING; // PENDING -> RUNNING 2041 s->status = RUNNING; // PENDING -> RUNNING
1998 2042
1999 // Tie "set_finalizer()" to the state 2043 // Tie "set_finalizer()" to the state
2000 // 2044 lua_pushcfunction( L, LG_set_finalizer);
2001 lua_pushcfunction( L, LG_set_finalizer ); 2045 populate_func_lookup_table( L, -1, "set_finalizer");
2002 populate_func_lookup_table( L, -1, "set_finalizer"); 2046 lua_setglobal( L, "set_finalizer");
2003 lua_setglobal( L, "set_finalizer"); 2047
2004 2048 // Tie "set_debug_threadname()" to the state
2005 // Tie "set_debug_threadname()" to the state 2049 // But don't register it in the lookup database because of the s_lane pointer upvalue
2006 // But don't register it in the lookup database because of the s_lane pointer upvalue 2050 lua_pushlightuserdata( L, s);
2007 lua_pushlightuserdata( L, s); 2051 lua_pushcclosure( L, LG_set_debug_threadname, 1);
2008 lua_pushcclosure( L, LG_set_debug_threadname, 1); 2052 lua_setglobal( L, "set_debug_threadname" );
2009 lua_setglobal( L, "set_debug_threadname" ); 2053
2010 2054 // Tie "cancel_test()" to the state
2011 // Tie "cancel_test()" to the state 2055 lua_pushcfunction( L, LG_cancel_test);
2012 // 2056 populate_func_lookup_table( L, -1, "cancel_test");
2013 lua_pushcfunction( L, LG_cancel_test); 2057 lua_setglobal( L, "cancel_test");
2014 populate_func_lookup_table( L, -1, "cancel_test");
2015 lua_setglobal( L, "cancel_test");
2016 2058
2017#if ERROR_FULL_STACK 2059#if ERROR_FULL_STACK
2018 // Tie "set_error_reporting()" to the state 2060 // Tie "set_error_reporting()" to the state
2019 // 2061 lua_pushcfunction( L, LG_set_error_reporting);
2020 lua_pushcfunction( L, LG_set_error_reporting); 2062 populate_func_lookup_table( L, -1, "set_error_reporting");
2021 populate_func_lookup_table( L, -1, "set_error_reporting"); 2063 lua_setglobal( L, "set_error_reporting");
2022 lua_setglobal( L, "set_error_reporting");
2023
2024 STACK_GROW( L, 1 );
2025 lua_pushcfunction( L, lane_error);
2026 lua_insert( L, 1 );
2027
2028 // [1]: error handler
2029 // [2]: function to run
2030 // [3..top]: parameters
2031 //
2032 rc= lua_pcall( L, lua_gettop(L)-2, LUA_MULTRET, 1 /*error handler*/ );
2033 // 0: no error, body return values are on the stack
2034 // LUA_ERRRUN: cancellation or a runtime error (error pushed on stack)
2035 // LUA_ERRMEM: memory allocation error
2036 // LUA_ERRERR: error while running the error handler (if any)
2037 2064
2038 assert( rc!=LUA_ERRERR ); // since we've authored it 2065 STACK_GROW( L, 1);
2039 2066 lua_pushcfunction( L, lane_error); // func args handler
2040 lua_remove(L,1); // remove error handler 2067 lua_insert( L, 1); // handler func args
2068#endif // ERROR_FULL_STACK
2041 2069
2042 // Lua 5.1 error handler is limited to one return value; taking stack trace via registry 2070 rc = lua_pcall( L, nargs, LUA_MULTRET, ERROR_FULL_STACK); // retvals|err
2043 if( rc != LUA_OK)
2044 {
2045 STACK_GROW(L,1);
2046 lua_pushlightuserdata( L, STACK_TRACE_KEY );
2047 lua_gettable(L, LUA_REGISTRYINDEX); // yields nil if no stack was generated (in case of cancellation for example)
2048 2071
2049 // For cancellation, a stack trace isn't placed 2072#if ERROR_FULL_STACK
2050 // 2073 lua_remove( L, 1); // retvals|error
2051 assert( lua_istable(L,2) || (lua_touserdata(L,1)==CANCEL_ERROR) ); 2074# endif // ERROR_FULL_STACK
2052
2053 // Just leaving the stack trace table on the stack is enough to get
2054 // it through to the master.
2055 }
2056 2075
2057#else // ERROR_FULL_STACK == 0 2076 // in case of error and if it exists, fetch stack trace from registry and push it
2058 // This code does not use 'lane_error' 2077 push_stack_trace( L, rc, 1);
2059 //
2060 // [1]: function to run
2061 // [2..top]: parameters
2062 //
2063 rc = lua_pcall( L, lua_gettop( L) - 1, LUA_MULTRET, 0); // no error handler
2064 // LUA_OK(0): no error
2065 // LUA_ERRRUN(2): a runtime error (error pushed on stack)
2066 // LUA_ERRMEM(4): memory allocation error
2067#endif // ERROR_FULL_STACK
2068 2078
2069 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "Lane %p body: %s (%s)\n" INDENT_END, L, get_errcode_name( rc), (lua_touserdata(L,1)==CANCEL_ERROR) ? "cancelled" : lua_typename( L, lua_type( L, 1)))); 2079 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "Lane %p body: %s (%s)\n" INDENT_END, L, get_errcode_name( rc), (lua_touserdata( L, 1)==CANCEL_ERROR) ? "cancelled" : lua_typename( L, lua_type( L, 1))));
2070 //STACK_DUMP(L); 2080 //STACK_DUMP(L);
2071 // Call finalizers, if the script has set them up. 2081 // Call finalizers, if the script has set them up.
2072 // 2082 //
2073 rc2 = run_finalizers( L, rc); 2083 rc2 = run_finalizers( L, rc);
2074 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "Lane %p finalizer: %s\n" INDENT_END, L, get_errcode_name( rc2))); 2084 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "Lane %p finalizer: %s\n" INDENT_END, L, get_errcode_name( rc2)));
2075 if( rc2 != LUA_OK) // Error within a finalizer! 2085 if( rc2 != LUA_OK) // Error within a finalizer!
2076 { 2086 {
2077 rc = rc2; // we're overruling the earlier script error or normal return 2087 // the finalizer generated an error, and left its own error message [and stack trace] on the stack
2078 // the finalizer generated an error, the error message [and stack trace] are pushed on the stack 2088 rc = rc2; // we're overruling the earlier script error or normal return
2079 // remove the rest so that only the error message [and stack trace] remain on the stack 2089 }
2080#if ERROR_FULL_STACK 2090 s->waiting_on = NULL; // just in case
2081 lua_insert( L, 1); 2091 if( selfdestruct_remove( s)) // check and remove (under lock!)
2082 lua_insert( L, 1); 2092 {
2083 lua_settop( L, 2); 2093 // We're a free-running thread and no-one's there to clean us up.
2084#else // ERROR_FULL_STACK == 0 2094 //
2085 lua_insert( L, 1); 2095 lua_close( s->L);
2086 lua_settop( L, 1);
2087#endif // ERROR_FULL_STACK
2088 }
2089 s->waiting_on = NULL; // just in case
2090 if( selfdestruct_remove( s)) // check and remove (under lock!)
2091 {
2092 // We're a free-running thread and no-one's there to clean us up.
2093 //
2094 lua_close( s->L);
2095 2096
2096 MUTEX_LOCK( &s->U->selfdestruct_cs); 2097 MUTEX_LOCK( &s->U->selfdestruct_cs);
2097 // done with lua_close(), terminal shutdown sequence may proceed 2098 // done with lua_close(), terminal shutdown sequence may proceed
2098 -- s->U->selfdestructing_count; 2099 -- s->U->selfdestructing_count;
2099 MUTEX_UNLOCK( &s->U->selfdestruct_cs); 2100 MUTEX_UNLOCK( &s->U->selfdestruct_cs);
2100 2101
2101 lane_cleanup( s); // s is freed at this point 2102 lane_cleanup( s); // s is freed at this point
2102 } 2103 }
2103 else 2104 else
2104 { 2105 {
2105 // leave results (1..top) or error message + stack trace (1..2) on the stack - master will copy them 2106 // leave results (1..top) or error message + stack trace (1..2) on the stack - master will copy them
2106 2107
2107 enum e_status st= 2108 enum e_status st = (rc == 0) ? DONE : (lua_touserdata( L, 1) == CANCEL_ERROR) ? CANCELLED : ERROR_ST;
2108 (rc==0) ? DONE
2109 : (lua_touserdata(L,1)==CANCEL_ERROR) ? CANCELLED
2110 : ERROR_ST;
2111 2109
2112 // Posix no PTHREAD_TIMEDJOIN: 2110 // Posix no PTHREAD_TIMEDJOIN:
2113 // 'done_lock' protects the -> DONE|ERROR_ST|CANCELLED state change 2111 // 'done_lock' protects the -> DONE|ERROR_ST|CANCELLED state change
2114 // 2112 //
2115#if THREADWAIT_METHOD == THREADWAIT_CONDVAR 2113#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
2116 MUTEX_LOCK( &s->done_lock); 2114 MUTEX_LOCK( &s->done_lock);
2117 { 2115 {
2118#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR 2116#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
2119 s->status = st; 2117 s->status = st;
2120#if THREADWAIT_METHOD == THREADWAIT_CONDVAR 2118#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
2121 SIGNAL_ONE( &s->done_signal); // wake up master (while 's->done_lock' is on) 2119 SIGNAL_ONE( &s->done_signal); // wake up master (while 's->done_lock' is on)
2122 } 2120 }
2123 MUTEX_UNLOCK( &s->done_lock); 2121 MUTEX_UNLOCK( &s->done_lock);
2124#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR 2122#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
2125 } 2123 }
2126 THREAD_CLEANUP_POP( FALSE); 2124 THREAD_CLEANUP_POP( FALSE);
2127 return 0; // ignored 2125 return 0; // ignored
2128} 2126}
2129 2127
2130// --- If a client wants to transfer stuff of a given module from the current state to another Lane, the module must be required 2128// --- If a client wants to transfer stuff of a given module from the current state to another Lane, the module must be required
@@ -2312,11 +2310,12 @@ LUAG_FUNC( thread_new)
2312 DEBUGSPEW_CODE( -- U->debugspew_indent_depth); 2310 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
2313 } 2311 }
2314 2312
2313
2314 STACK_CHECK( L);
2315 STACK_CHECK( L2);
2315 ASSERT_L( lua_gettop( L2) == 0); 2316 ASSERT_L( lua_gettop( L2) == 0);
2316 2317
2317 // Lane main function 2318 // Lane main function
2318 //
2319 STACK_CHECK( L);
2320 if( lua_type( L, 1) == LUA_TFUNCTION) 2319 if( lua_type( L, 1) == LUA_TFUNCTION)
2321 { 2320 {
2322 int res; 2321 int res;
@@ -2340,7 +2339,7 @@ LUAG_FUNC( thread_new)
2340 } 2339 }
2341 } 2340 }
2342 2341
2343 ASSERT_L( lua_gettop( L2) == 1); 2342 STACK_MID( L2, 1);
2344 ASSERT_L( lua_isfunction( L2, 1)); 2343 ASSERT_L( lua_isfunction( L2, 1));
2345 2344
2346 // revive arguments 2345 // revive arguments
@@ -2359,8 +2358,7 @@ LUAG_FUNC( thread_new)
2359 } 2358 }
2360 STACK_MID( L, 0); 2359 STACK_MID( L, 0);
2361 2360
2362 ASSERT_L( (uint_t)lua_gettop( L2) == 1 + args); 2361 STACK_END( L2, 1 + args);
2363 ASSERT_L( lua_isfunction( L2, 1));
2364 2362
2365 // 's' is allocated from heap, not Lua, since its life span may surpass 2363 // 's' is allocated from heap, not Lua, since its life span may surpass
2366 // the handle's (if free running thread) 2364 // the handle's (if free running thread)
@@ -2616,20 +2614,19 @@ LUAG_FUNC( thread_join)
2616 double wait_secs = luaL_optnumber( L, 2, -1.0); 2614 double wait_secs = luaL_optnumber( L, 2, -1.0);
2617 lua_State* L2 = s->L; 2615 lua_State* L2 = s->L;
2618 int ret; 2616 int ret;
2619 bool_t done; 2617 bool_t done = THREAD_ISNULL( s->thread) || THREAD_WAIT( &s->thread, wait_secs, &s->done_signal, &s->done_lock, &s->status);
2620
2621 done = THREAD_ISNULL( s->thread) || THREAD_WAIT( &s->thread, wait_secs, &s->done_signal, &s->done_lock, &s->status);
2622 if( !done || !L2) 2618 if( !done || !L2)
2623 { 2619 {
2624 return 0; // timeout: pushes none, leaves 'L2' alive 2620 return 0; // timeout: pushes none, leaves 'L2' alive
2625 } 2621 }
2626 2622
2623 STACK_CHECK( L);
2627 // Thread is DONE/ERROR_ST/CANCELLED; all ours now 2624 // Thread is DONE/ERROR_ST/CANCELLED; all ours now
2628 2625
2629 if( s->mstatus == KILLED) // OS thread was killed if thread_cancel was forced 2626 if( s->mstatus == KILLED) // OS thread was killed if thread_cancel was forced
2630 { 2627 {
2631 // in that case, even if the thread was killed while DONE/ERROR_ST/CANCELLED, ignore regular return values 2628 // in that case, even if the thread was killed while DONE/ERROR_ST/CANCELLED, ignore regular return values
2632 STACK_GROW( L, 1); 2629 STACK_GROW( L, 2);
2633 lua_pushnil( L); 2630 lua_pushnil( L);
2634 lua_pushliteral( L, "killed"); 2631 lua_pushliteral( L, "killed");
2635 ret = 2; 2632 ret = 2;
@@ -2654,13 +2651,17 @@ LUAG_FUNC( thread_join)
2654 break; 2651 break;
2655 2652
2656 case ERROR_ST: 2653 case ERROR_ST:
2657 STACK_GROW( L, 1);
2658 lua_pushnil( L);
2659 if( luaG_inter_move( U, L2, L, 1 + ERROR_FULL_STACK, eLM_LaneBody) != 0) // error message at [-2], stack trace at [-1]
2660 { 2654 {
2661 return luaL_error( L, "tried to copy unsupported types"); 2655 int const n = lua_gettop( L2);
2656 STACK_GROW( L, 3);
2657 lua_pushnil( L);
2658 // even when ERROR_FULL_STACK, if the error is not LUA_ERRRUN, the handler wasn't called, and we only have 1 error message on the stack ...
2659 if( luaG_inter_move( U, L2, L, n, eLM_LaneBody) != 0) // nil "err" [trace]
2660 {
2661 return luaL_error( L, "tried to copy unsupported types: %s", lua_tostring( L, -n));
2662 }
2663 ret = 1 + n;
2662 } 2664 }
2663 ret = 2 + ERROR_FULL_STACK;
2664 break; 2665 break;
2665 2666
2666 case CANCELLED: 2667 case CANCELLED:
@@ -2675,7 +2676,7 @@ LUAG_FUNC( thread_join)
2675 lua_close( L2); 2676 lua_close( L2);
2676 } 2677 }
2677 s->L = 0; 2678 s->L = 0;
2678 2679 STACK_END( L, ret);
2679 return ret; 2680 return ret;
2680} 2681}
2681 2682