aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES8
-rw-r--r--docs/index.html6
-rw-r--r--src/lanes.c207
-rw-r--r--tests/basic.lua9
4 files changed, 127 insertions, 103 deletions
diff --git a/CHANGES b/CHANGES
index 3639295..d1c4913 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,13 @@
1CHANGES: 1CHANGES:
2 2
3CHANGE 92: BGe 20-Jan-14
4 * version 3.8.1
5 * new function lane:get_debug_threadname()
6 * Fix invalid memory accesses when fetching the name of a joined lane with lanes:threads() (because its lua_State is closed)
7 * use luaL_newmetatable() to create the metatable for lane objects
8 * prevent malicious code from crashing by calling lane methods without passing the lane as first argument (raise an error instead)
9 * set_debug_threadname() is no longer registered in the function lookup databases because it holds a C pointer as upvalue and it might crash if used maliciously
10
3CHANGE 91: BGe 20-Jan-14 11CHANGE 91: BGe 20-Jan-14
4 * version 3.8.0 12 * version 3.8.0
5 * linda:set() accepts multiple values to set in the specified slot 13 * linda:set() accepts multiple values to set in the specified slot
diff --git a/docs/index.html b/docs/index.html
index da37cef..7078b13 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 20-Jan-14, and applies to version <tt>3.8.0</tt>. 73 This document was revised on 20-Jan-14, and applies to version <tt>3.8.1</tt>.
74 </p> 74 </p>
75 </font> 75 </font>
76 </center> 76 </center>
@@ -630,7 +630,9 @@
630 </table> 630 </table>
631 631
632<p> 632<p>
633 Each lane also gets a function <tt>set_debug_threadname()</tt> that it can use anytime to do as the name says. Supported debuggers are Microsoft Visual Studio (for the C side) and Decoda (for the Lua side). 633 Each lane also gets a global function <tt>set_debug_threadname()</tt> that it can use anytime to do as the name says. Supported debuggers are Microsoft Visual Studio (for the C side) and Decoda (for the Lua side).
634 <br/>
635 Starting with version 3.8.1, the lane has a new method <tt>lane:get_debug_threadname()</tt> that gives access to that name from the caller side (returns <tt>"&lt;unnamed&gt;"</tt> if unset, <tt>"&lt;closed&gt;"</tt> if the internal Lua state is closed).
634</p> 636</p>
635 637
636<p> 638<p>
diff --git a/src/lanes.c b/src/lanes.c
index f62c39f..604e43d 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -52,7 +52,7 @@
52 * ... 52 * ...
53 */ 53 */
54 54
55char const* VERSION = "3.8.0"; 55char const* VERSION = "3.8.1";
56 56
57/* 57/*
58=============================================================================== 58===============================================================================
@@ -176,14 +176,14 @@ struct s_lane
176 // M: sets to NORMAL, if issued a kill changes to KILLED 176 // M: sets to NORMAL, if issued a kill changes to KILLED
177 // S: not used 177 // S: not used
178 178
179 struct s_lane * volatile selfdestruct_next; 179 struct s_lane* volatile selfdestruct_next;
180 // 180 //
181 // M: sets to non-NULL if facing lane handle '__gc' cycle but the lane 181 // M: sets to non-NULL if facing lane handle '__gc' cycle but the lane
182 // is still running 182 // is still running
183 // S: cleans up after itself if non-NULL at lane exit 183 // S: cleans up after itself if non-NULL at lane exit
184 184
185#if HAVE_LANE_TRACKING 185#if HAVE_LANE_TRACKING
186 struct s_lane * volatile tracking_next; 186 struct s_lane* volatile tracking_next;
187#endif // HAVE_LANE_TRACKING 187#endif // HAVE_LANE_TRACKING
188 // 188 //
189 // For tracking only 189 // For tracking only
@@ -193,10 +193,10 @@ struct s_lane
193// 'struct s_lane' are malloc/free'd and the handle only carries a pointer. 193// 'struct s_lane' are malloc/free'd and the handle only carries a pointer.
194// This is not deep userdata since the handle's not portable among lanes. 194// This is not deep userdata since the handle's not portable among lanes.
195// 195//
196#define lua_toLane( L, i) (*((struct s_lane**) lua_touserdata( L, i))) 196#define lua_toLane( L, i) (*((struct s_lane**) luaL_checkudata( L, i, "Lane")))
197 197
198#define CANCEL_TEST_KEY ((void*)get_lane) // used as registry key 198#define CANCEL_TEST_KEY ((void*)get_lane_from_registry) // used as registry key
199static inline struct s_lane* get_lane( lua_State* L) 199static inline struct s_lane* get_lane_from_registry( lua_State* L)
200{ 200{
201 struct s_lane* s; 201 struct s_lane* s;
202 STACK_GROW( L, 1); 202 STACK_GROW( L, 1);
@@ -220,7 +220,7 @@ static inline struct s_lane* get_lane( lua_State* L)
220*/ 220*/
221static inline enum e_cancel_request cancel_test( lua_State* L) 221static inline enum e_cancel_request cancel_test( lua_State* L)
222{ 222{
223 struct s_lane* const s = get_lane( L); 223 struct s_lane* const s = get_lane_from_registry( L);
224 // 's' is NULL for the original main state (and no-one can cancel that) 224 // 's' is NULL for the original main state (and no-one can cancel that)
225 return s ? s->cancel_request : CANCEL_NONE; 225 return s ? s->cancel_request : CANCEL_NONE;
226} 226}
@@ -317,7 +317,7 @@ struct s_lane* volatile tracking_first = NULL; // will change to TRACKING_END if
317 * Add the lane to tracking chain; the ones still running at the end of the 317 * Add the lane to tracking chain; the ones still running at the end of the
318 * whole process will be cancelled. 318 * whole process will be cancelled.
319 */ 319 */
320static void tracking_add( struct s_lane *s) 320static void tracking_add( struct s_lane* s)
321{ 321{
322 322
323 MUTEX_LOCK( &tracking_cs); 323 MUTEX_LOCK( &tracking_cs);
@@ -333,7 +333,7 @@ static void tracking_add( struct s_lane *s)
333/* 333/*
334 * A free-running lane has ended; remove it from tracking chain 334 * A free-running lane has ended; remove it from tracking chain
335 */ 335 */
336static bool_t tracking_remove( struct s_lane *s ) 336static bool_t tracking_remove( struct s_lane* s)
337{ 337{
338 bool_t found = FALSE; 338 bool_t found = FALSE;
339 MUTEX_LOCK( &tracking_cs); 339 MUTEX_LOCK( &tracking_cs);
@@ -344,7 +344,7 @@ static bool_t tracking_remove( struct s_lane *s )
344 // 344 //
345 if (s->tracking_next != NULL) 345 if (s->tracking_next != NULL)
346 { 346 {
347 struct s_lane **ref= (struct s_lane **) &tracking_first; 347 struct s_lane** ref= (struct s_lane**) &tracking_first;
348 348
349 while( *ref != TRACKING_END) 349 while( *ref != TRACKING_END)
350 { 350 {
@@ -355,7 +355,7 @@ static bool_t tracking_remove( struct s_lane *s )
355 found = TRUE; 355 found = TRUE;
356 break; 356 break;
357 } 357 }
358 ref = (struct s_lane **) &((*ref)->tracking_next); 358 ref = (struct s_lane**) &((*ref)->tracking_next);
359 } 359 }
360 assert( found); 360 assert( found);
361 } 361 }
@@ -502,7 +502,7 @@ LUAG_FUNC( linda_send)
502 502
503 { 503 {
504 enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings 504 enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings
505 struct s_lane* const s = get_lane( L); 505 struct s_lane* const s = get_lane_from_registry( L);
506 if( s != NULL) 506 if( s != NULL)
507 { 507 {
508 cancel = s->cancel_request; // testing here causes no delays 508 cancel = s->cancel_request; // testing here causes no delays
@@ -664,7 +664,7 @@ LUAG_FUNC( linda_receive)
664 664
665 { 665 {
666 enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings 666 enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings
667 struct s_lane* const s = get_lane( L); 667 struct s_lane* const s = get_lane_from_registry( L);
668 if( s != NULL) 668 if( s != NULL)
669 { 669 {
670 cancel = s->cancel_request; // testing here causes no delays 670 cancel = s->cancel_request; // testing here causes no delays
@@ -1342,7 +1342,7 @@ static MUTEX_T selfdestruct_cs;
1342 // 1342 //
1343 // Protects modifying the selfdestruct chain 1343 // Protects modifying the selfdestruct chain
1344 1344
1345#define SELFDESTRUCT_END ((struct s_lane *)(-1)) 1345#define SELFDESTRUCT_END ((struct s_lane*)(-1))
1346 // 1346 //
1347 // The chain is ended by '(struct s_lane*)(-1)', not NULL: 1347 // The chain is ended by '(struct s_lane*)(-1)', not NULL:
1348 // 'selfdestruct_first -> ... -> ... -> (-1)' 1348 // 'selfdestruct_first -> ... -> ... -> (-1)'
@@ -1357,8 +1357,8 @@ int volatile selfdestructing_count = 0;
1357 * Add the lane to selfdestruct chain; the ones still running at the end of the 1357 * Add the lane to selfdestruct chain; the ones still running at the end of the
1358 * whole process will be cancelled. 1358 * whole process will be cancelled.
1359 */ 1359 */
1360static void selfdestruct_add( struct s_lane *s ) { 1360static void selfdestruct_add( struct s_lane* s)
1361 1361{
1362 MUTEX_LOCK( &selfdestruct_cs ); 1362 MUTEX_LOCK( &selfdestruct_cs );
1363 { 1363 {
1364 assert( s->selfdestruct_next == NULL ); 1364 assert( s->selfdestruct_next == NULL );
@@ -1372,7 +1372,7 @@ static void selfdestruct_add( struct s_lane *s ) {
1372/* 1372/*
1373 * A free-running lane has ended; remove it from selfdestruct chain 1373 * A free-running lane has ended; remove it from selfdestruct chain
1374 */ 1374 */
1375static bool_t selfdestruct_remove( struct s_lane *s ) 1375static bool_t selfdestruct_remove( struct s_lane* s)
1376{ 1376{
1377 bool_t found = FALSE; 1377 bool_t found = FALSE;
1378 MUTEX_LOCK( &selfdestruct_cs ); 1378 MUTEX_LOCK( &selfdestruct_cs );
@@ -1382,7 +1382,7 @@ static bool_t selfdestruct_remove( struct s_lane *s )
1382 // cancel/kill). 1382 // cancel/kill).
1383 // 1383 //
1384 if (s->selfdestruct_next != NULL) { 1384 if (s->selfdestruct_next != NULL) {
1385 struct s_lane **ref= (struct s_lane **) &selfdestruct_first; 1385 struct s_lane** ref= (struct s_lane**) &selfdestruct_first;
1386 1386
1387 while( *ref != SELFDESTRUCT_END ) { 1387 while( *ref != SELFDESTRUCT_END ) {
1388 if (*ref == s) { 1388 if (*ref == s) {
@@ -1393,7 +1393,7 @@ static bool_t selfdestruct_remove( struct s_lane *s )
1393 found= TRUE; 1393 found= TRUE;
1394 break; 1394 break;
1395 } 1395 }
1396 ref= (struct s_lane **) &((*ref)->selfdestruct_next); 1396 ref= (struct s_lane**) &((*ref)->selfdestruct_next);
1397 } 1397 }
1398 assert( found ); 1398 assert( found );
1399 } 1399 }
@@ -1747,6 +1747,7 @@ static int lane_error( lua_State* L)
1747 1747
1748LUAG_FUNC( set_debug_threadname) 1748LUAG_FUNC( set_debug_threadname)
1749{ 1749{
1750 // C s_lane structure is a light userdata upvalue
1750 struct s_lane* s = lua_touserdata( L, lua_upvalueindex( 1)); 1751 struct s_lane* s = lua_touserdata( L, lua_upvalueindex( 1));
1751 luaL_checktype( L, -1, LUA_TSTRING); // "name" 1752 luaL_checktype( L, -1, LUA_TSTRING); // "name"
1752 // store a hidden reference in the registry to make sure the string is kept around even if a lane decides to manually change the "decoda_name" global... 1753 // store a hidden reference in the registry to make sure the string is kept around even if a lane decides to manually change the "decoda_name" global...
@@ -1761,6 +1762,14 @@ LUAG_FUNC( set_debug_threadname)
1761 return 0; 1762 return 0;
1762} 1763}
1763 1764
1765LUAG_FUNC( get_debug_threadname)
1766{
1767 struct s_lane* const s = lua_toLane( L, 1);
1768 luaL_argcheck( L, lua_gettop( L) == 1, 2, "too many arguments");
1769 lua_pushstring( L, s->debug_name ? s->debug_name : "<unnamed>");
1770 return 1;
1771}
1772
1764LUAG_FUNC( set_thread_priority) 1773LUAG_FUNC( set_thread_priority)
1765{ 1774{
1766 int const prio = luaL_checkint( L, 1); 1775 int const prio = luaL_checkint( L, 1);
@@ -1820,11 +1829,11 @@ static void thread_cleanup_handler( void* opaque)
1820#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR 1829#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
1821 1830
1822//--- 1831//---
1823static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) 1832static THREAD_RETURN_T THREAD_CALLCONV lane_main( void* vs)
1824{ 1833{
1825 struct s_lane *s= (struct s_lane *)vs; 1834 struct s_lane* s = (struct s_lane*) vs;
1826 int rc, rc2; 1835 int rc, rc2;
1827 lua_State*L= s->L; 1836 lua_State* L = s->L;
1828#if HAVE_LANE_TRACKING 1837#if HAVE_LANE_TRACKING
1829 if( tracking_first) 1838 if( tracking_first)
1830 { 1839 {
@@ -1833,7 +1842,7 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1833#endif // HAVE_LANE_TRACKING 1842#endif // HAVE_LANE_TRACKING
1834 THREAD_MAKE_ASYNCH_CANCELLABLE(); 1843 THREAD_MAKE_ASYNCH_CANCELLABLE();
1835 THREAD_CLEANUP_PUSH( thread_cleanup_handler, s); 1844 THREAD_CLEANUP_PUSH( thread_cleanup_handler, s);
1836 s->status= RUNNING; // PENDING -> RUNNING 1845 s->status = RUNNING; // PENDING -> RUNNING
1837 1846
1838 // Tie "set_finalizer()" to the state 1847 // Tie "set_finalizer()" to the state
1839 // 1848 //
@@ -1842,10 +1851,9 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1842 lua_setglobal( L, "set_finalizer"); 1851 lua_setglobal( L, "set_finalizer");
1843 1852
1844 // Tie "set_debug_threadname()" to the state 1853 // Tie "set_debug_threadname()" to the state
1845 // 1854 // But don't register it in the lookup database because of the s_lane pointer upvalue
1846 lua_pushlightuserdata( L, s); 1855 lua_pushlightuserdata( L, s);
1847 lua_pushcclosure( L, LG_set_debug_threadname, 1); 1856 lua_pushcclosure( L, LG_set_debug_threadname, 1);
1848 populate_func_lookup_table( L, -1, "set_debug_threadname");
1849 lua_setglobal( L, "set_debug_threadname" ); 1857 lua_setglobal( L, "set_debug_threadname" );
1850 1858
1851 // Tie "cancel_test()" to the state 1859 // Tie "cancel_test()" to the state
@@ -1862,7 +1870,7 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1862 lua_setglobal( L, "set_error_reporting"); 1870 lua_setglobal( L, "set_error_reporting");
1863 1871
1864 STACK_GROW( L, 1 ); 1872 STACK_GROW( L, 1 );
1865 lua_pushcfunction( L, lane_error ); 1873 lua_pushcfunction( L, lane_error);
1866 lua_insert( L, 1 ); 1874 lua_insert( L, 1 );
1867 1875
1868 // [1]: error handler 1876 // [1]: error handler
@@ -1933,6 +1941,8 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1933 // 1941 //
1934 lua_close( s->L); 1942 lua_close( s->L);
1935 s->L = L = 0; 1943 s->L = L = 0;
1944 // debug_name is a pointer to an interned string, that no longer exists when the state is closed
1945 s->debug_name = "<closed>";
1936 1946
1937 lane_cleanup( s); 1947 lane_cleanup( s);
1938 MUTEX_LOCK( &selfdestruct_cs); 1948 MUTEX_LOCK( &selfdestruct_cs);
@@ -2314,54 +2324,47 @@ LUAG_FUNC( thread_gc)
2314// lane_h:cancel( [timeout] [, force [, forcekill_timeout]]) 2324// lane_h:cancel( [timeout] [, force [, forcekill_timeout]])
2315LUAG_FUNC( thread_cancel) 2325LUAG_FUNC( thread_cancel)
2316{ 2326{
2317 if( lua_gettop( L) < 1 || lua_type( L, 1) != LUA_TUSERDATA) 2327 struct s_lane* s = lua_toLane( L, 1);
2328 double secs = 0.0;
2329 int force_i = 2;
2330 int forcekill_timeout_i = 3;
2331
2332 if( lua_isnumber( L, 2))
2318 { 2333 {
2319 return luaL_error( L, "invalid argument #1, did you use ':' as you should?"); 2334 secs = lua_tonumber( L, 2);
2335 if( secs < 0.0 && lua_gettop( L) > 3)
2336 {
2337 return luaL_error( L, "can't force_kill a soft cancel");
2338 }
2339 // negative timeout and force flag means we want to wake linda-waiting threads
2340 ++ force_i;
2341 ++ forcekill_timeout_i;
2320 } 2342 }
2321 else 2343 else if( lua_isnil( L, 2))
2322 { 2344 {
2323 struct s_lane* s = lua_toLane( L, 1); 2345 ++ force_i;
2324 double secs = 0.0; 2346 ++ forcekill_timeout_i;
2325 int force_i = 2; 2347 }
2326 int forcekill_timeout_i = 3;
2327 2348
2328 if( lua_isnumber( L, 2)) 2349 {
2329 { 2350 bool_t force = lua_toboolean( L, force_i); // FALSE if nothing there
2330 secs = lua_tonumber( L, 2); 2351 double forcekill_timeout = luaL_optnumber( L, forcekill_timeout_i, 0.0);
2331 if( secs < 0.0 && lua_gettop( L) > 3)
2332 {
2333 return luaL_error( L, "can't force_kill a soft cancel");
2334 }
2335 // negative timeout and force flag means we want to wake linda-waiting threads
2336 ++ force_i;
2337 ++ forcekill_timeout_i;
2338 }
2339 else if( lua_isnil( L, 2))
2340 {
2341 ++ force_i;
2342 ++ forcekill_timeout_i;
2343 }
2344 2352
2353 switch( thread_cancel( L, s, secs, force, forcekill_timeout))
2345 { 2354 {
2346 bool_t force = lua_toboolean( L, force_i); // FALSE if nothing there 2355 case CR_Timeout:
2347 double forcekill_timeout = luaL_optnumber( L, forcekill_timeout_i, 0.0); 2356 lua_pushboolean( L, 0);
2348 2357 lua_pushstring( L, "timeout");
2349 switch( thread_cancel( L, s, secs, force, forcekill_timeout)) 2358 return 2;
2350 {
2351 case CR_Timeout:
2352 lua_pushboolean( L, 0);
2353 lua_pushstring( L, "timeout");
2354 return 2;
2355 2359
2356 case CR_Cancelled: 2360 case CR_Cancelled:
2357 lua_pushboolean( L, 1); 2361 lua_pushboolean( L, 1);
2358 return 1; 2362 return 1;
2359 2363
2360 case CR_Killed: 2364 case CR_Killed:
2361 lua_pushboolean( L, 0); 2365 lua_pushboolean( L, 0);
2362 lua_pushstring( L, "killed"); 2366 lua_pushstring( L, "killed");
2363 return 2; 2367 return 2;
2364 }
2365 } 2368 }
2366 } 2369 }
2367 // should never happen, only here to prevent the compiler from complaining of "not all control paths returning a value" 2370 // should never happen, only here to prevent the compiler from complaining of "not all control paths returning a value"
@@ -2378,26 +2381,26 @@ LUAG_FUNC( thread_cancel)
2378// / "error" finished at an error, error value is there 2381// / "error" finished at an error, error value is there
2379// / "cancelled" execution cancelled by M (state gone) 2382// / "cancelled" execution cancelled by M (state gone)
2380// 2383//
2381static char const * thread_status_string( struct s_lane *s) 2384static char const * thread_status_string( struct s_lane* s)
2382{ 2385{
2383 enum e_status st = s->status; // read just once (volatile) 2386 enum e_status st = s->status; // read just once (volatile)
2384 char const * str = 2387 char const* str =
2385 (s->mstatus == KILLED) ? "killed" : // new to v3.3.0! 2388 (s->mstatus == KILLED) ? "killed" : // new to v3.3.0!
2386 (st==PENDING) ? "pending" : 2389 (st == PENDING) ? "pending" :
2387 (st==RUNNING) ? "running" : // like in 'co.status()' 2390 (st == RUNNING) ? "running" : // like in 'co.status()'
2388 (st==WAITING) ? "waiting" : 2391 (st == WAITING) ? "waiting" :
2389 (st==DONE) ? "done" : 2392 (st == DONE) ? "done" :
2390 (st==ERROR_ST) ? "error" : 2393 (st == ERROR_ST) ? "error" :
2391 (st==CANCELLED) ? "cancelled" : NULL; 2394 (st == CANCELLED) ? "cancelled" : NULL;
2392 return str; 2395 return str;
2393} 2396}
2394 2397
2395static int push_thread_status( lua_State*L, struct s_lane *s) 2398static int push_thread_status( lua_State* L, struct s_lane* s)
2396{ 2399{
2397 char const * const str = thread_status_string( s); 2400 char const* const str = thread_status_string( s);
2398 ASSERT_L( str); 2401 ASSERT_L( str);
2399 2402
2400 lua_pushstring( L, str ); 2403 lua_pushstring( L, str);
2401 return 1; 2404 return 1;
2402} 2405}
2403 2406
@@ -2413,8 +2416,8 @@ static int push_thread_status( lua_State*L, struct s_lane *s)
2413LUAG_FUNC( thread_join) 2416LUAG_FUNC( thread_join)
2414{ 2417{
2415 struct s_lane* const s = lua_toLane( L, 1); 2418 struct s_lane* const s = lua_toLane( L, 1);
2416 double wait_secs= luaL_optnumber(L,2,-1.0); 2419 double wait_secs = luaL_optnumber( L, 2, -1.0);
2417 lua_State*L2= s->L; 2420 lua_State* L2 = s->L;
2418 int ret; 2421 int ret;
2419 bool_t done; 2422 bool_t done;
2420 2423
@@ -2467,6 +2470,8 @@ LUAG_FUNC( thread_join)
2467 ASSERT_L( FALSE ); ret= 0; 2470 ASSERT_L( FALSE ); ret= 0;
2468 } 2471 }
2469 lua_close( L2); 2472 lua_close( L2);
2473 // debug_name is a pointer to an interned string, that no longer exists when the state is closed
2474 s->debug_name = "<closed>";
2470 } 2475 }
2471 s->L = 0; 2476 s->L = 0;
2472 2477
@@ -2487,7 +2492,7 @@ LUAG_FUNC( thread_index)
2487 int const UD = 1; 2492 int const UD = 1;
2488 int const KEY = 2; 2493 int const KEY = 2;
2489 int const USR = 3; 2494 int const USR = 3;
2490 struct s_lane *s = lua_toLane( L, UD); 2495 struct s_lane* const s = lua_toLane( L, UD);
2491 ASSERT_L( lua_gettop( L) == 2); 2496 ASSERT_L( lua_gettop( L) == 2);
2492 2497
2493 STACK_GROW( L, 8); // up to 8 positions are needed in case of error propagation 2498 STACK_GROW( L, 8); // up to 8 positions are needed in case of error propagation
@@ -2956,28 +2961,32 @@ LUAG_FUNC( configure)
2956 STACK_MID( L, 1); 2961 STACK_MID( L, 1);
2957 2962
2958 // prepare the metatable for threads 2963 // prepare the metatable for threads
2959 // contains keys: { __gc, __index, cached_error, cached_tostring, cancel, join } 2964 // contains keys: { __gc, __index, cached_error, cached_tostring, cancel, join, get_debug_threadname }
2960 // 2965 //
2961 lua_newtable( L); // settings M mt 2966 if( luaL_newmetatable( L, "Lane")) // settings M mt
2962 lua_pushcfunction( L, LG_thread_gc); // settings M mt LG_thread_gc 2967 {
2963 lua_setfield( L, -2, "__gc"); // settings M mt 2968 lua_pushcfunction( L, LG_thread_gc); // settings M mt LG_thread_gc
2964 lua_pushcfunction( L, LG_thread_index); // settings M mt LG_thread_index 2969 lua_setfield( L, -2, "__gc"); // settings M mt
2965 lua_setfield( L, -2, "__index"); // settings M mt 2970 lua_pushcfunction( L, LG_thread_index); // settings M mt LG_thread_index
2966 lua_getglobal( L, "error"); // settings M mt error 2971 lua_setfield( L, -2, "__index"); // settings M mt
2967 ASSERT_L( lua_isfunction( L, -1)); 2972 lua_getglobal( L, "error"); // settings M mt error
2968 lua_setfield( L, -2, "cached_error"); // settings M mt 2973 ASSERT_L( lua_isfunction( L, -1));
2969 lua_getglobal( L, "tostring"); // settings M mt tostring 2974 lua_setfield( L, -2, "cached_error"); // settings M mt
2970 ASSERT_L( lua_isfunction( L, -1)); 2975 lua_getglobal( L, "tostring"); // settings M mt tostring
2971 lua_setfield( L, -2, "cached_tostring"); // settings M mt 2976 ASSERT_L( lua_isfunction( L, -1));
2972 lua_pushcfunction( L, LG_thread_join); // settings M mt LG_thread_join 2977 lua_setfield( L, -2, "cached_tostring"); // settings M mt
2973 lua_setfield( L, -2, "join"); // settings M mt 2978 lua_pushcfunction( L, LG_thread_join); // settings M mt LG_thread_join
2974 lua_pushcfunction( L, LG_thread_cancel); // settings M mt LG_thread_cancel 2979 lua_setfield( L, -2, "join"); // settings M mt
2975 lua_setfield( L, -2, "cancel"); // settings M mt 2980 lua_pushcfunction( L, LG_get_debug_threadname); // settings M mt LG_get_debug_threadname
2976 lua_pushliteral( L, "Lane"); // settings M mt "Lane" 2981 lua_setfield( L, -2, "get_debug_threadname"); // settings M mt
2977 lua_setfield( L, -2, "__metatable"); // settings M mt 2982 lua_pushcfunction( L, LG_thread_cancel); // settings M mt LG_thread_cancel
2983 lua_setfield( L, -2, "cancel"); // settings M mt
2984 lua_pushliteral( L, "Lane"); // settings M mt "Lane"
2985 lua_setfield( L, -2, "__metatable"); // settings M mt
2986 }
2978 2987
2979 lua_pushcclosure( L, LG_thread_new, 1); // settings M LG_thread_new 2988 lua_pushcclosure( L, LG_thread_new, 1); // settings M LG_thread_new
2980 lua_setfield(L, -2, "thread_new"); // settings M 2989 lua_setfield( L, -2, "thread_new"); // settings M
2981 2990
2982 // we can't register 'lanes.require' normally because we want to create an upvalued closure 2991 // we can't register 'lanes.require' normally because we want to create an upvalued closure
2983 lua_getglobal( L, "require"); // settings M require 2992 lua_getglobal( L, "require"); // settings M require
diff --git a/tests/basic.lua b/tests/basic.lua
index 1f4eb1e..5b0d8a7 100644
--- a/tests/basic.lua
+++ b/tests/basic.lua
@@ -413,6 +413,8 @@ PRINT( "\n\n", "---=== :join test ===---", "\n\n")
413 413
414local S= lanes_gen( "table", 414local S= lanes_gen( "table",
415 function(arg) 415 function(arg)
416 set_debug_threadname "join test lane"
417 set_finalizer( function() end)
416 aux= {} 418 aux= {}
417 for i, v in ipairs(arg) do 419 for i, v in ipairs(arg) do
418 table.insert (aux, 1, v) 420 table.insert (aux, 1, v)
@@ -422,11 +424,14 @@ local S= lanes_gen( "table",
422end ) 424end )
423 425
424h= S { 12, 13, 14 } -- execution starts, h[1..3] will get the return values 426h= S { 12, 13, 14 } -- execution starts, h[1..3] will get the return values
425 427-- wait a bit so that the lane hasa chance to set its debug name
428linda:receive(0.5, "gloupti")
429print( "joining with '" .. h:get_debug_threadname() .. "'")
426local a,b,c,d= h:join() 430local a,b,c,d= h:join()
427if h.status == "error" then 431if h.status == "error" then
428 print( "h error: " , a, b, c, d) 432 print( h:get_debug_threadname(), "error: " , a, b, c, d)
429else 433else
434 print( h:get_debug_threadname(), a,b,c,d)
430 assert(a==14) 435 assert(a==14)
431 assert(b==13) 436 assert(b==13)
432 assert(c==12) 437 assert(c==12)