aboutsummaryrefslogtreecommitdiff
path: root/src/lanes.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lanes.c')
-rw-r--r--src/lanes.c2886
1 files changed, 1443 insertions, 1443 deletions
diff --git a/src/lanes.c b/src/lanes.c
index e697bf5..c5b6c4f 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -113,16 +113,16 @@ THE SOFTWARE.
113// intern the debug name in the specified lua state so that the pointer remains valid when the lane's state is closed 113// intern the debug name in the specified lua state so that the pointer remains valid when the lane's state is closed
114static void securize_debug_threadname( lua_State* L, Lane* s) 114static void securize_debug_threadname( lua_State* L, Lane* s)
115{ 115{
116 STACK_CHECK( L, 0); 116 STACK_CHECK( L, 0);
117 STACK_GROW( L, 3); 117 STACK_GROW( L, 3);
118 lua_getiuservalue( L, 1, 1); 118 lua_getiuservalue( L, 1, 1);
119 lua_newtable( L); 119 lua_newtable( L);
120 // Lua 5.1 can't do 's->debug_name = lua_pushstring( L, s->debug_name);' 120 // Lua 5.1 can't do 's->debug_name = lua_pushstring( L, s->debug_name);'
121 lua_pushstring( L, s->debug_name); 121 lua_pushstring( L, s->debug_name);
122 s->debug_name = lua_tostring( L, -1); 122 s->debug_name = lua_tostring( L, -1);
123 lua_rawset( L, -3); 123 lua_rawset( L, -3);
124 lua_pop( L, 1); 124 lua_pop( L, 1);
125 STACK_END( L, 0); 125 STACK_END( L, 0);
126} 126}
127 127
128#if ERROR_FULL_STACK 128#if ERROR_FULL_STACK
@@ -154,24 +154,24 @@ struct s_Linda;
154*/ 154*/
155static bool_t push_registry_table( lua_State* L, UniqueKey key, bool_t create) 155static bool_t push_registry_table( lua_State* L, UniqueKey key, bool_t create)
156{ 156{
157 STACK_GROW( L, 3); 157 STACK_GROW( L, 3);
158 STACK_CHECK( L, 0); 158 STACK_CHECK( L, 0);
159 159
160 REGISTRY_GET( L, key); // ? 160 REGISTRY_GET( L, key); // ?
161 if( lua_isnil( L, -1)) // nil? 161 if( lua_isnil( L, -1)) // nil?
162 { 162 {
163 lua_pop( L, 1); // 163 lua_pop( L, 1); //
164 164
165 if( !create) 165 if( !create)
166 { 166 {
167 return FALSE; 167 return FALSE;
168 } 168 }
169 169
170 lua_newtable( L); // t 170 lua_newtable( L); // t
171 REGISTRY_SET( L, key, lua_pushvalue( L, -2)); 171 REGISTRY_SET( L, key, lua_pushvalue( L, -2));
172 } 172 }
173 STACK_END( L, 1); 173 STACK_END( L, 1);
174 return TRUE; // table pushed 174 return TRUE; // table pushed
175} 175}
176 176
177#if HAVE_LANE_TRACKING 177#if HAVE_LANE_TRACKING
@@ -187,14 +187,14 @@ static bool_t push_registry_table( lua_State* L, UniqueKey key, bool_t create)
187static void tracking_add( Lane* s) 187static void tracking_add( Lane* s)
188{ 188{
189 189
190 MUTEX_LOCK( &s->U->tracking_cs); 190 MUTEX_LOCK( &s->U->tracking_cs);
191 { 191 {
192 assert( s->tracking_next == NULL); 192 assert( s->tracking_next == NULL);
193 193
194 s->tracking_next = s->U->tracking_first; 194 s->tracking_next = s->U->tracking_first;
195 s->U->tracking_first = s; 195 s->U->tracking_first = s;
196 } 196 }
197 MUTEX_UNLOCK( &s->U->tracking_cs); 197 MUTEX_UNLOCK( &s->U->tracking_cs);
198} 198}
199 199
200/* 200/*
@@ -202,33 +202,33 @@ static void tracking_add( Lane* s)
202 */ 202 */
203static bool_t tracking_remove( Lane* s) 203static bool_t tracking_remove( Lane* s)
204{ 204{
205 bool_t found = FALSE; 205 bool_t found = FALSE;
206 MUTEX_LOCK( &s->U->tracking_cs); 206 MUTEX_LOCK( &s->U->tracking_cs);
207 { 207 {
208 // Make sure (within the MUTEX) that we actually are in the chain 208 // Make sure (within the MUTEX) that we actually are in the chain
209 // still (at process exit they will remove us from chain and then 209 // still (at process exit they will remove us from chain and then
210 // cancel/kill). 210 // cancel/kill).
211 // 211 //
212 if( s->tracking_next != NULL) 212 if( s->tracking_next != NULL)
213 { 213 {
214 Lane** ref = (Lane**) &s->U->tracking_first; 214 Lane** ref = (Lane**) &s->U->tracking_first;
215 215
216 while( *ref != TRACKING_END) 216 while( *ref != TRACKING_END)
217 { 217 {
218 if( *ref == s) 218 if( *ref == s)
219 { 219 {
220 *ref = s->tracking_next; 220 *ref = s->tracking_next;
221 s->tracking_next = NULL; 221 s->tracking_next = NULL;
222 found = TRUE; 222 found = TRUE;
223 break; 223 break;
224 } 224 }
225 ref = (Lane**) &((*ref)->tracking_next); 225 ref = (Lane**) &((*ref)->tracking_next);
226 } 226 }
227 assert( found); 227 assert( found);
228 } 228 }
229 } 229 }
230 MUTEX_UNLOCK( &s->U->tracking_cs); 230 MUTEX_UNLOCK( &s->U->tracking_cs);
231 return found; 231 return found;
232} 232}
233 233
234#endif // HAVE_LANE_TRACKING 234#endif // HAVE_LANE_TRACKING
@@ -238,22 +238,22 @@ static bool_t tracking_remove( Lane* s)
238 238
239static void lane_cleanup( Lane* s) 239static void lane_cleanup( Lane* s)
240{ 240{
241 // Clean up after a (finished) thread 241 // Clean up after a (finished) thread
242 // 242 //
243#if THREADWAIT_METHOD == THREADWAIT_CONDVAR 243#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
244 SIGNAL_FREE( &s->done_signal); 244 SIGNAL_FREE( &s->done_signal);
245 MUTEX_FREE( &s->done_lock); 245 MUTEX_FREE( &s->done_lock);
246#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR 246#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
247 247
248#if HAVE_LANE_TRACKING 248#if HAVE_LANE_TRACKING
249 if( s->U->tracking_first != NULL) 249 if( s->U->tracking_first != NULL)
250 { 250 {
251 // Lane was cleaned up, no need to handle at process termination 251 // Lane was cleaned up, no need to handle at process termination
252 tracking_remove( s); 252 tracking_remove( s);
253 } 253 }
254#endif // HAVE_LANE_TRACKING 254#endif // HAVE_LANE_TRACKING
255 255
256 free( s); 256 free( s);
257} 257}
258 258
259/* 259/*
@@ -272,16 +272,16 @@ static void lane_cleanup( Lane* s)
272// 272//
273LUAG_FUNC( set_finalizer) 273LUAG_FUNC( set_finalizer)
274{ 274{
275 luaL_argcheck( L, lua_isfunction( L, 1), 1, "finalizer should be a function"); 275 luaL_argcheck( L, lua_isfunction( L, 1), 1, "finalizer should be a function");
276 luaL_argcheck( L, lua_gettop( L) == 1, 1, "too many arguments"); 276 luaL_argcheck( L, lua_gettop( L) == 1, 1, "too many arguments");
277 // Get the current finalizer table (if any) 277 // Get the current finalizer table (if any)
278 push_registry_table( L, FINALIZER_REGKEY, TRUE /*do create if none*/); // finalizer {finalisers} 278 push_registry_table( L, FINALIZER_REGKEY, TRUE /*do create if none*/); // finalizer {finalisers}
279 STACK_GROW( L, 2); 279 STACK_GROW( L, 2);
280 lua_pushinteger( L, lua_rawlen( L, -1) + 1); // finalizer {finalisers} idx 280 lua_pushinteger( L, lua_rawlen( L, -1) + 1); // finalizer {finalisers} idx
281 lua_pushvalue( L, 1); // finalizer {finalisers} idx finalizer 281 lua_pushvalue( L, 1); // finalizer {finalisers} idx finalizer
282 lua_rawset( L, -3); // finalizer {finalisers} 282 lua_rawset( L, -3); // finalizer {finalisers}
283 lua_pop( L, 2); // 283 lua_pop( L, 2); //
284 return 0; 284 return 0;
285} 285}
286 286
287 287
@@ -302,74 +302,74 @@ static void push_stack_trace( lua_State* L, int rc_, int stk_base_);
302 302
303static int run_finalizers( lua_State* L, int lua_rc) 303static int run_finalizers( lua_State* L, int lua_rc)
304{ 304{
305 int finalizers_index; 305 int finalizers_index;
306 int n; 306 int n;
307 int err_handler_index = 0; 307 int err_handler_index = 0;
308 int rc = LUA_OK; // ... 308 int rc = LUA_OK; // ...
309 if( !push_registry_table( L, FINALIZER_REGKEY, FALSE)) // ... finalizers? 309 if( !push_registry_table( L, FINALIZER_REGKEY, FALSE)) // ... finalizers?
310 { 310 {
311 return 0; // no finalizers 311 return 0; // no finalizers
312 } 312 }
313 313
314 STACK_GROW( L, 5); 314 STACK_GROW( L, 5);
315 315
316 finalizers_index = lua_gettop( L); 316 finalizers_index = lua_gettop( L);
317 317
318#if ERROR_FULL_STACK 318#if ERROR_FULL_STACK
319 lua_pushcfunction( L, lane_error); // ... finalizers lane_error 319 lua_pushcfunction( L, lane_error); // ... finalizers lane_error
320 err_handler_index = lua_gettop( L); 320 err_handler_index = lua_gettop( L);
321#endif // ERROR_FULL_STACK 321#endif // ERROR_FULL_STACK
322 322
323 for( n = (int) lua_rawlen( L, finalizers_index); n > 0; -- n) 323 for( n = (int) lua_rawlen( L, finalizers_index); n > 0; -- n)
324 { 324 {
325 int args = 0; 325 int args = 0;
326 lua_pushinteger( L, n); // ... finalizers lane_error n 326 lua_pushinteger( L, n); // ... finalizers lane_error n
327 lua_rawget( L, finalizers_index); // ... finalizers lane_error finalizer 327 lua_rawget( L, finalizers_index); // ... finalizers lane_error finalizer
328 ASSERT_L( lua_isfunction( L, -1)); 328 ASSERT_L( lua_isfunction( L, -1));
329 if( lua_rc != LUA_OK) // we have an error message and an optional stack trace at the bottom of the stack 329 if( lua_rc != LUA_OK) // we have an error message and an optional stack trace at the bottom of the stack
330 { 330 {
331 ASSERT_L( finalizers_index == 2 || finalizers_index == 3); 331 ASSERT_L( finalizers_index == 2 || finalizers_index == 3);
332 //char const* err_msg = lua_tostring( L, 1); 332 //char const* err_msg = lua_tostring( L, 1);
333 lua_pushvalue( L, 1); // ... finalizers lane_error finalizer err_msg 333 lua_pushvalue( L, 1); // ... finalizers lane_error finalizer err_msg
334 // 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 334 // 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
335 if( finalizers_index == 3) 335 if( finalizers_index == 3)
336 { 336 {
337 lua_pushvalue( L, 2); // ... finalizers lane_error finalizer err_msg stack_trace 337 lua_pushvalue( L, 2); // ... finalizers lane_error finalizer err_msg stack_trace
338 } 338 }
339 args = finalizers_index - 1; 339 args = finalizers_index - 1;
340 } 340 }
341 341
342 // if no error from the main body, finalizer doesn't receive any argument, else it gets the error message and optional stack trace 342 // if no error from the main body, finalizer doesn't receive any argument, else it gets the error message and optional stack trace
343 rc = lua_pcall( L, args, 0, err_handler_index); // ... finalizers lane_error err_msg2? 343 rc = lua_pcall( L, args, 0, err_handler_index); // ... finalizers lane_error err_msg2?
344 if( rc != LUA_OK) 344 if( rc != LUA_OK)
345 { 345 {
346 push_stack_trace( L, rc, lua_gettop( L)); 346 push_stack_trace( L, rc, lua_gettop( L));
347 // If one finalizer fails, don't run the others. Return this 347 // If one finalizer fails, don't run the others. Return this
348 // as the 'real' error, replacing what we could have had (or not) 348 // as the 'real' error, replacing what we could have had (or not)
349 // from the actual code. 349 // from the actual code.
350 break; 350 break;
351 } 351 }
352 // no error, proceed to next finalizer // ... finalizers lane_error 352 // no error, proceed to next finalizer // ... finalizers lane_error
353 } 353 }
354 354
355 if( rc != LUA_OK) 355 if( rc != LUA_OK)
356 { 356 {
357 // ERROR_FULL_STACK accounts for the presence of lane_error on the stack 357 // ERROR_FULL_STACK accounts for the presence of lane_error on the stack
358 int nb_err_slots = lua_gettop( L) - finalizers_index - ERROR_FULL_STACK; 358 int nb_err_slots = lua_gettop( L) - finalizers_index - ERROR_FULL_STACK;
359 // a finalizer generated an error, this is what we leave of the stack 359 // a finalizer generated an error, this is what we leave of the stack
360 for( n = nb_err_slots; n > 0; -- n) 360 for( n = nb_err_slots; n > 0; -- n)
361 { 361 {
362 lua_replace( L, n); 362 lua_replace( L, n);
363 } 363 }
364 // leave on the stack only the error and optional stack trace produced by the error in the finalizer 364 // leave on the stack only the error and optional stack trace produced by the error in the finalizer
365 lua_settop( L, nb_err_slots); 365 lua_settop( L, nb_err_slots);
366 } 366 }
367 else // no error from the finalizers, make sure only the original return values from the lane body remain on the stack 367 else // no error from the finalizers, make sure only the original return values from the lane body remain on the stack
368 { 368 {
369 lua_settop( L, finalizers_index - 1); 369 lua_settop( L, finalizers_index - 1);
370 } 370 }
371 371
372 return rc; 372 return rc;
373} 373}
374 374
375/* 375/*
@@ -392,12 +392,12 @@ static int run_finalizers( lua_State* L, int lua_rc)
392 */ 392 */
393static void selfdestruct_add( Lane* s) 393static void selfdestruct_add( Lane* s)
394{ 394{
395 MUTEX_LOCK( &s->U->selfdestruct_cs); 395 MUTEX_LOCK( &s->U->selfdestruct_cs);
396 assert( s->selfdestruct_next == NULL); 396 assert( s->selfdestruct_next == NULL);
397 397
398 s->selfdestruct_next = s->U->selfdestruct_first; 398 s->selfdestruct_next = s->U->selfdestruct_first;
399 s->U->selfdestruct_first= s; 399 s->U->selfdestruct_first= s;
400 MUTEX_UNLOCK( &s->U->selfdestruct_cs); 400 MUTEX_UNLOCK( &s->U->selfdestruct_cs);
401} 401}
402 402
403/* 403/*
@@ -405,35 +405,35 @@ static void selfdestruct_add( Lane* s)
405 */ 405 */
406static bool_t selfdestruct_remove( Lane* s) 406static bool_t selfdestruct_remove( Lane* s)
407{ 407{
408 bool_t found = FALSE; 408 bool_t found = FALSE;
409 MUTEX_LOCK( &s->U->selfdestruct_cs); 409 MUTEX_LOCK( &s->U->selfdestruct_cs);
410 { 410 {
411 // Make sure (within the MUTEX) that we actually are in the chain 411 // Make sure (within the MUTEX) that we actually are in the chain
412 // still (at process exit they will remove us from chain and then 412 // still (at process exit they will remove us from chain and then
413 // cancel/kill). 413 // cancel/kill).
414 // 414 //
415 if( s->selfdestruct_next != NULL) 415 if( s->selfdestruct_next != NULL)
416 { 416 {
417 Lane** ref = (Lane**) &s->U->selfdestruct_first; 417 Lane** ref = (Lane**) &s->U->selfdestruct_first;
418 418
419 while( *ref != SELFDESTRUCT_END ) 419 while( *ref != SELFDESTRUCT_END )
420 { 420 {
421 if( *ref == s) 421 if( *ref == s)
422 { 422 {
423 *ref = s->selfdestruct_next; 423 *ref = s->selfdestruct_next;
424 s->selfdestruct_next = NULL; 424 s->selfdestruct_next = NULL;
425 // the terminal shutdown should wait until the lane is done with its lua_close() 425 // the terminal shutdown should wait until the lane is done with its lua_close()
426 ++ s->U->selfdestructing_count; 426 ++ s->U->selfdestructing_count;
427 found = TRUE; 427 found = TRUE;
428 break; 428 break;
429 } 429 }
430 ref = (Lane**) &((*ref)->selfdestruct_next); 430 ref = (Lane**) &((*ref)->selfdestruct_next);
431 } 431 }
432 assert( found); 432 assert( found);
433 } 433 }
434 } 434 }
435 MUTEX_UNLOCK( &s->U->selfdestruct_cs); 435 MUTEX_UNLOCK( &s->U->selfdestruct_cs);
436 return found; 436 return found;
437} 437}
438 438
439/* 439/*
@@ -441,160 +441,160 @@ static bool_t selfdestruct_remove( Lane* s)
441*/ 441*/
442static int selfdestruct_gc( lua_State* L) 442static int selfdestruct_gc( lua_State* L)
443{ 443{
444 Universe* U = (Universe*) lua_touserdata( L, 1); 444 Universe* U = (Universe*) lua_touserdata( L, 1);
445 445
446 while( U->selfdestruct_first != SELFDESTRUCT_END) // true at most once! 446 while( U->selfdestruct_first != SELFDESTRUCT_END) // true at most once!
447 { 447 {
448 // Signal _all_ still running threads to exit (including the timer thread) 448 // Signal _all_ still running threads to exit (including the timer thread)
449 // 449 //
450 MUTEX_LOCK( &U->selfdestruct_cs); 450 MUTEX_LOCK( &U->selfdestruct_cs);
451 { 451 {
452 Lane* s = U->selfdestruct_first; 452 Lane* s = U->selfdestruct_first;
453 while( s != SELFDESTRUCT_END) 453 while( s != SELFDESTRUCT_END)
454 { 454 {
455 // attempt a regular unforced hard cancel with a small timeout 455 // attempt a regular unforced hard cancel with a small timeout
456 bool_t cancelled = THREAD_ISNULL( s->thread) || thread_cancel( L, s, CO_Hard, 0.0001, FALSE, 0.0); 456 bool_t cancelled = THREAD_ISNULL( s->thread) || thread_cancel( L, s, CO_Hard, 0.0001, FALSE, 0.0);
457 // if we failed, and we know the thread is waiting on a linda 457 // if we failed, and we know the thread is waiting on a linda
458 if( cancelled == FALSE && s->status == WAITING && s->waiting_on != NULL) 458 if( cancelled == FALSE && s->status == WAITING && s->waiting_on != NULL)
459 { 459 {
460 // signal the linda the wake up the thread so that it can react to the cancel query 460 // signal the linda the wake up the thread so that it can react to the cancel query
461 // let us hope we never land here with a pointer on a linda that has been destroyed... 461 // let us hope we never land here with a pointer on a linda that has been destroyed...
462 SIGNAL_T *waiting_on = s->waiting_on; 462 SIGNAL_T *waiting_on = s->waiting_on;
463 //s->waiting_on = NULL; // useful, or not? 463 //s->waiting_on = NULL; // useful, or not?
464 SIGNAL_ALL( waiting_on); 464 SIGNAL_ALL( waiting_on);
465 } 465 }
466 s = s->selfdestruct_next; 466 s = s->selfdestruct_next;
467 } 467 }
468 } 468 }
469 MUTEX_UNLOCK( &U->selfdestruct_cs); 469 MUTEX_UNLOCK( &U->selfdestruct_cs);
470 470
471 // When noticing their cancel, the lanes will remove themselves from 471 // When noticing their cancel, the lanes will remove themselves from
472 // the selfdestruct chain. 472 // the selfdestruct chain.
473 473
474 // TBD: Not sure if Windows (multi core) will require the timed approach, 474 // TBD: Not sure if Windows (multi core) will require the timed approach,
475 // or single Yield. I don't have machine to test that (so leaving 475 // or single Yield. I don't have machine to test that (so leaving
476 // for timed approach). -- AKa 25-Oct-2008 476 // for timed approach). -- AKa 25-Oct-2008
477 477
478 // OS X 10.5 (Intel) needs more to avoid segfaults. 478 // OS X 10.5 (Intel) needs more to avoid segfaults.
479 // 479 //
480 // "make test" is okay. 100's of "make require" are okay. 480 // "make test" is okay. 100's of "make require" are okay.
481 // 481 //
482 // Tested on MacBook Core Duo 2GHz and 10.5.5: 482 // Tested on MacBook Core Duo 2GHz and 10.5.5:
483 // -- AKa 25-Oct-2008 483 // -- AKa 25-Oct-2008
484 // 484 //
485 { 485 {
486 lua_Number const shutdown_timeout = lua_tonumber( L, lua_upvalueindex( 1)); 486 lua_Number const shutdown_timeout = lua_tonumber( L, lua_upvalueindex( 1));
487 double const t_until = now_secs() + shutdown_timeout; 487 double const t_until = now_secs() + shutdown_timeout;
488 488
489 while( U->selfdestruct_first != SELFDESTRUCT_END) 489 while( U->selfdestruct_first != SELFDESTRUCT_END)
490 { 490 {
491 YIELD(); // give threads time to act on their cancel 491 YIELD(); // give threads time to act on their cancel
492 { 492 {
493 // count the number of cancelled thread that didn't have the time to act yet 493 // count the number of cancelled thread that didn't have the time to act yet
494 int n = 0; 494 int n = 0;
495 double t_now = 0.0; 495 double t_now = 0.0;
496 MUTEX_LOCK( &U->selfdestruct_cs); 496 MUTEX_LOCK( &U->selfdestruct_cs);
497 { 497 {
498 Lane* s = U->selfdestruct_first; 498 Lane* s = U->selfdestruct_first;
499 while( s != SELFDESTRUCT_END) 499 while( s != SELFDESTRUCT_END)
500 { 500 {
501 if( s->cancel_request == CANCEL_HARD) 501 if( s->cancel_request == CANCEL_HARD)
502 ++ n; 502 ++ n;
503 s = s->selfdestruct_next; 503 s = s->selfdestruct_next;
504 } 504 }
505 } 505 }
506 MUTEX_UNLOCK( &U->selfdestruct_cs); 506 MUTEX_UNLOCK( &U->selfdestruct_cs);
507 // if timeout elapsed, or we know all threads have acted, stop waiting 507 // if timeout elapsed, or we know all threads have acted, stop waiting
508 t_now = now_secs(); 508 t_now = now_secs();
509 if( n == 0 || (t_now >= t_until)) 509 if( n == 0 || (t_now >= t_until))
510 { 510 {
511 DEBUGSPEW_CODE( fprintf( stderr, "%d uncancelled lane(s) remain after waiting %fs at process end.\n", n, shutdown_timeout - (t_until - t_now))); 511 DEBUGSPEW_CODE( fprintf( stderr, "%d uncancelled lane(s) remain after waiting %fs at process end.\n", n, shutdown_timeout - (t_until - t_now)));
512 break; 512 break;
513 } 513 }
514 } 514 }
515 } 515 }
516 } 516 }
517 517
518 // If some lanes are currently cleaning after themselves, wait until they are done. 518 // If some lanes are currently cleaning after themselves, wait until they are done.
519 // They are no longer listed in the selfdestruct chain, but they still have to lua_close(). 519 // They are no longer listed in the selfdestruct chain, but they still have to lua_close().
520 while( U->selfdestructing_count > 0) 520 while( U->selfdestructing_count > 0)
521 { 521 {
522 YIELD(); 522 YIELD();
523 } 523 }
524 524
525 //--- 525 //---
526 // Kill the still free running threads 526 // Kill the still free running threads
527 // 527 //
528 if( U->selfdestruct_first != SELFDESTRUCT_END) 528 if( U->selfdestruct_first != SELFDESTRUCT_END)
529 { 529 {
530 unsigned int n = 0; 530 unsigned int n = 0;
531 // first thing we did was to raise the linda signals the threads were waiting on (if any) 531 // first thing we did was to raise the linda signals the threads were waiting on (if any)
532 // therefore, any well-behaved thread should be in CANCELLED state 532 // therefore, any well-behaved thread should be in CANCELLED state
533 // these are not running, and the state can be closed 533 // these are not running, and the state can be closed
534 MUTEX_LOCK( &U->selfdestruct_cs); 534 MUTEX_LOCK( &U->selfdestruct_cs);
535 { 535 {
536 Lane* s = U->selfdestruct_first; 536 Lane* s = U->selfdestruct_first;
537 while( s != SELFDESTRUCT_END) 537 while( s != SELFDESTRUCT_END)
538 { 538 {
539 Lane* next_s = s->selfdestruct_next; 539 Lane* next_s = s->selfdestruct_next;
540 s->selfdestruct_next = NULL; // detach from selfdestruct chain 540 s->selfdestruct_next = NULL; // detach from selfdestruct chain
541 if( !THREAD_ISNULL( s->thread)) // can be NULL if previous 'soft' termination succeeded 541 if( !THREAD_ISNULL( s->thread)) // can be NULL if previous 'soft' termination succeeded
542 { 542 {
543 THREAD_KILL( &s->thread); 543 THREAD_KILL( &s->thread);
544#if THREADAPI == THREADAPI_PTHREAD 544#if THREADAPI == THREADAPI_PTHREAD
545 // pthread: make sure the thread is really stopped! 545 // pthread: make sure the thread is really stopped!
546 THREAD_WAIT( &s->thread, -1, &s->done_signal, &s->done_lock, &s->status); 546 THREAD_WAIT( &s->thread, -1, &s->done_signal, &s->done_lock, &s->status);
547#endif // THREADAPI == THREADAPI_PTHREAD 547#endif // THREADAPI == THREADAPI_PTHREAD
548 } 548 }
549 // NO lua_close() in this case because we don't know where execution of the state was interrupted 549 // NO lua_close() in this case because we don't know where execution of the state was interrupted
550 lane_cleanup( s); 550 lane_cleanup( s);
551 s = next_s; 551 s = next_s;
552 ++ n; 552 ++ n;
553 } 553 }
554 U->selfdestruct_first = SELFDESTRUCT_END; 554 U->selfdestruct_first = SELFDESTRUCT_END;
555 } 555 }
556 MUTEX_UNLOCK( &U->selfdestruct_cs); 556 MUTEX_UNLOCK( &U->selfdestruct_cs);
557 557
558 DEBUGSPEW_CODE( fprintf( stderr, "Killed %d lane(s) at process end.\n", n)); 558 DEBUGSPEW_CODE( fprintf( stderr, "Killed %d lane(s) at process end.\n", n));
559 } 559 }
560 } 560 }
561 561
562 // If some lanes are currently cleaning after themselves, wait until they are done. 562 // If some lanes are currently cleaning after themselves, wait until they are done.
563 // They are no longer listed in the selfdestruct chain, but they still have to lua_close(). 563 // They are no longer listed in the selfdestruct chain, but they still have to lua_close().
564 while( U->selfdestructing_count > 0) 564 while( U->selfdestructing_count > 0)
565 { 565 {
566 YIELD(); 566 YIELD();
567 } 567 }
568 568
569 // necessary so that calling free_deep_prelude doesn't crash because linda_id expects a linda lightuserdata at absolute slot 1 569 // necessary so that calling free_deep_prelude doesn't crash because linda_id expects a linda lightuserdata at absolute slot 1
570 lua_settop( L, 0); 570 lua_settop( L, 0);
571 // no need to mutex-protect this as all threads in the universe are gone at that point 571 // no need to mutex-protect this as all threads in the universe are gone at that point
572 if( U->timer_deep != NULL) // test ins case some early internal error prevented Lanes from creating the deep timer 572 if( U->timer_deep != NULL) // test ins case some early internal error prevented Lanes from creating the deep timer
573 { 573 {
574 -- U->timer_deep->refcount; // should be 0 now 574 -- U->timer_deep->refcount; // should be 0 now
575 } 575 free_deep_prelude( L, (DeepPrelude*) U->timer_deep);
576 free_deep_prelude( L, (DeepPrelude*) U->timer_deep); 576 U->timer_deep = NULL;
577 U->timer_deep = NULL; 577 }
578 578
579 close_keepers( U, L); 579 close_keepers( U, L);
580 580
581 // remove the protected allocator, if any 581 // remove the protected allocator, if any
582 cleanup_allocator_function( U, L); 582 cleanup_allocator_function( U, L);
583 583
584#if HAVE_LANE_TRACKING 584#if HAVE_LANE_TRACKING
585 MUTEX_FREE( &U->tracking_cs); 585 MUTEX_FREE( &U->tracking_cs);
586#endif // HAVE_LANE_TRACKING 586#endif // HAVE_LANE_TRACKING
587 // Linked chains handling 587 // Linked chains handling
588 MUTEX_FREE( &U->selfdestruct_cs); 588 MUTEX_FREE( &U->selfdestruct_cs);
589 MUTEX_FREE( &U->require_cs); 589 MUTEX_FREE( &U->require_cs);
590 // Locks for 'tools.c' inc/dec counters 590 // Locks for 'tools.c' inc/dec counters
591 MUTEX_FREE( &U->deep_lock); 591 MUTEX_FREE( &U->deep_lock);
592 MUTEX_FREE( &U->mtid_lock); 592 MUTEX_FREE( &U->mtid_lock);
593 // universe is no longer available (nor necessary) 593 // universe is no longer available (nor necessary)
594 // we need to do this in case some deep userdata objects were created before Lanes was initialized, 594 // we need to do this in case some deep userdata objects were created before Lanes was initialized,
595 // as potentially they will be garbage collected after Lanes at application shutdown 595 // as potentially they will be garbage collected after Lanes at application shutdown
596 universe_store( L, NULL); 596 universe_store( L, NULL);
597 return 0; 597 return 0;
598} 598}
599 599
600 600
@@ -606,23 +606,23 @@ static int selfdestruct_gc( lua_State* L)
606// 606//
607LUAG_FUNC( set_singlethreaded) 607LUAG_FUNC( set_singlethreaded)
608{ 608{
609 uint_t cores = luaG_optunsigned( L, 1, 1); 609 uint_t cores = luaG_optunsigned( L, 1, 1);
610 (void) cores; // prevent "unused" warning 610 (void) cores; // prevent "unused" warning
611 611
612#ifdef PLATFORM_OSX 612#ifdef PLATFORM_OSX
613#ifdef _UTILBINDTHREADTOCPU 613#ifdef _UTILBINDTHREADTOCPU
614 if( cores > 1) 614 if( cores > 1)
615 { 615 {
616 return luaL_error( L, "Limiting to N>1 cores not possible"); 616 return luaL_error( L, "Limiting to N>1 cores not possible");
617 } 617 }
618 // requires 'chudInitialize()' 618 // requires 'chudInitialize()'
619 utilBindThreadToCPU(0); // # of CPU to run on (we cannot limit to 2..N CPUs?) 619 utilBindThreadToCPU(0); // # of CPU to run on (we cannot limit to 2..N CPUs?)
620 return 0; 620 return 0;
621#else 621#else
622 return luaL_error( L, "Not available: compile with _UTILBINDTHREADTOCPU"); 622 return luaL_error( L, "Not available: compile with _UTILBINDTHREADTOCPU");
623#endif 623#endif
624#else 624#else
625 return luaL_error( L, "not implemented"); 625 return luaL_error( L, "not implemented");
626#endif 626#endif
627} 627}
628 628
@@ -650,190 +650,190 @@ static DECLARE_CONST_UNIQUE_KEY( EXTENDED_STACKTRACE_REGKEY, 0x2357c69a7c92c936)
650 650
651LUAG_FUNC( set_error_reporting) 651LUAG_FUNC( set_error_reporting)
652{ 652{
653 bool_t equal; 653 bool_t equal;
654 luaL_checktype( L, 1, LUA_TSTRING); 654 luaL_checktype( L, 1, LUA_TSTRING);
655 lua_pushliteral( L, "extended"); 655 lua_pushliteral( L, "extended");
656 equal = lua_rawequal( L, -1, 1); 656 equal = lua_rawequal( L, -1, 1);
657 lua_pop( L, 1); 657 lua_pop( L, 1);
658 if( equal) 658 if( equal)
659 { 659 {
660 goto done; 660 goto done;
661 } 661 }
662 lua_pushliteral( L, "basic"); 662 lua_pushliteral( L, "basic");
663 equal = !lua_rawequal( L, -1, 1); 663 equal = !lua_rawequal( L, -1, 1);
664 lua_pop( L, 1); 664 lua_pop( L, 1);
665 if( equal) 665 if( equal)
666 { 666 {
667 return luaL_error( L, "unsupported error reporting model"); 667 return luaL_error( L, "unsupported error reporting model");
668 } 668 }
669done: 669done:
670 REGISTRY_SET( L, EXTENDED_STACKTRACE_REGKEY, lua_pushboolean( L, equal)); 670 REGISTRY_SET( L, EXTENDED_STACKTRACE_REGKEY, lua_pushboolean( L, equal));
671 return 0; 671 return 0;
672} 672}
673 673
674static int lane_error( lua_State* L) 674static int lane_error( lua_State* L)
675{ 675{
676 lua_Debug ar; 676 lua_Debug ar;
677 int n; 677 int n;
678 bool_t extended; 678 bool_t extended;
679 679
680 // error message (any type) 680 // error message (any type)
681 STACK_CHECK_ABS( L, 1); // some_error 681 STACK_CHECK_ABS( L, 1); // some_error
682 682
683 // Don't do stack survey for cancelled lanes. 683 // Don't do stack survey for cancelled lanes.
684 // 684 //
685 if( equal_unique_key( L, 1, CANCEL_ERROR)) 685 if( equal_unique_key( L, 1, CANCEL_ERROR))
686 { 686 {
687 return 1; // just pass on 687 return 1; // just pass on
688 } 688 }
689 689
690 STACK_GROW( L, 3); 690 STACK_GROW( L, 3);
691 REGISTRY_GET( L, EXTENDED_STACKTRACE_REGKEY); // some_error basic|extended 691 REGISTRY_GET( L, EXTENDED_STACKTRACE_REGKEY); // some_error basic|extended
692 extended = lua_toboolean( L, -1); 692 extended = lua_toboolean( L, -1);
693 lua_pop( L, 1); // some_error 693 lua_pop( L, 1); // some_error
694 694
695 // Place stack trace at 'registry[lane_error]' for the 'lua_pcall()' 695 // Place stack trace at 'registry[lane_error]' for the 'lua_pcall()'
696 // caller to fetch. This bypasses the Lua 5.1 limitation of only one 696 // caller to fetch. This bypasses the Lua 5.1 limitation of only one
697 // return value from error handler to 'lua_pcall()' caller. 697 // return value from error handler to 'lua_pcall()' caller.
698 698
699 // It's adequate to push stack trace as a table. This gives the receiver 699 // It's adequate to push stack trace as a table. This gives the receiver
700 // of the stack best means to format it to their liking. Also, it allows 700 // of the stack best means to format it to their liking. Also, it allows
701 // us to add more stack info later, if needed. 701 // us to add more stack info later, if needed.
702 // 702 //
703 // table of { "sourcefile.lua:<line>", ... } 703 // table of { "sourcefile.lua:<line>", ... }
704 // 704 //
705 lua_newtable( L); // some_error {} 705 lua_newtable( L); // some_error {}
706 706
707 // Best to start from level 1, but in some cases it might be a C function 707 // Best to start from level 1, but in some cases it might be a C function
708 // and we don't get '.currentline' for that. It's okay - just keep level 708 // and we don't get '.currentline' for that. It's okay - just keep level
709 // and table index growing separate. --AKa 22-Jan-2009 709 // and table index growing separate. --AKa 22-Jan-2009
710 // 710 //
711 for( n = 1; lua_getstack( L, n, &ar); ++ n) 711 for( n = 1; lua_getstack( L, n, &ar); ++ n)
712 { 712 {
713 lua_getinfo( L, extended ? "Sln" : "Sl", &ar); 713 lua_getinfo( L, extended ? "Sln" : "Sl", &ar);
714 if( extended) 714 if( extended)
715 { 715 {
716 lua_newtable( L); // some_error {} {} 716 lua_newtable( L); // some_error {} {}
717 717
718 lua_pushstring( L, ar.source); // some_error {} {} source 718 lua_pushstring( L, ar.source); // some_error {} {} source
719 lua_setfield( L, -2, "source"); // some_error {} {} 719 lua_setfield( L, -2, "source"); // some_error {} {}
720 720
721 lua_pushinteger( L, ar.currentline); // some_error {} {} currentline 721 lua_pushinteger( L, ar.currentline); // some_error {} {} currentline
722 lua_setfield( L, -2, "currentline"); // some_error {} {} 722 lua_setfield( L, -2, "currentline"); // some_error {} {}
723 723
724 lua_pushstring( L, ar.name); // some_error {} {} name 724 lua_pushstring( L, ar.name); // some_error {} {} name
725 lua_setfield( L, -2, "name"); // some_error {} {} 725 lua_setfield( L, -2, "name"); // some_error {} {}
726 726
727 lua_pushstring( L, ar.namewhat); // some_error {} {} namewhat 727 lua_pushstring( L, ar.namewhat); // some_error {} {} namewhat
728 lua_setfield( L, -2, "namewhat"); // some_error {} {} 728 lua_setfield( L, -2, "namewhat"); // some_error {} {}
729 729
730 lua_pushstring( L, ar.what); // some_error {} {} what 730 lua_pushstring( L, ar.what); // some_error {} {} what
731 lua_setfield( L, -2, "what"); // some_error {} {} 731 lua_setfield( L, -2, "what"); // some_error {} {}
732 } 732 }
733 else if( ar.currentline > 0) 733 else if( ar.currentline > 0)
734 { 734 {
735 lua_pushfstring( L, "%s:%d", ar.short_src, ar.currentline); // some_error {} "blah:blah" 735 lua_pushfstring( L, "%s:%d", ar.short_src, ar.currentline); // some_error {} "blah:blah"
736 } 736 }
737 else 737 else
738 { 738 {
739 lua_pushfstring( L, "%s:?", ar.short_src); // some_error {} "blah" 739 lua_pushfstring( L, "%s:?", ar.short_src); // some_error {} "blah"
740 } 740 }
741 lua_rawseti( L, -2, (lua_Integer) n); // some_error {} 741 lua_rawseti( L, -2, (lua_Integer) n); // some_error {}
742 } 742 }
743 743
744 REGISTRY_SET( L, STACKTRACE_REGKEY, lua_insert( L, -2)); // some_error 744 REGISTRY_SET( L, STACKTRACE_REGKEY, lua_insert( L, -2)); // some_error
745 745
746 STACK_END( L, 1); 746 STACK_END( L, 1);
747 return 1; // the untouched error value 747 return 1; // the untouched error value
748} 748}
749#endif // ERROR_FULL_STACK 749#endif // ERROR_FULL_STACK
750 750
751static void push_stack_trace( lua_State* L, int rc_, int stk_base_) 751static void push_stack_trace( lua_State* L, int rc_, int stk_base_)
752{ 752{
753 // Lua 5.1 error handler is limited to one return value; it stored the stack trace in the registry 753 // Lua 5.1 error handler is limited to one return value; it stored the stack trace in the registry
754 switch( rc_) 754 switch( rc_)
755 { 755 {
756 case LUA_OK: // no error, body return values are on the stack 756 case LUA_OK: // no error, body return values are on the stack
757 break; 757 break;
758 758
759 case LUA_ERRRUN: // cancellation or a runtime error 759 case LUA_ERRRUN: // cancellation or a runtime error
760#if ERROR_FULL_STACK // when ERROR_FULL_STACK, we installed a handler 760#if ERROR_FULL_STACK // when ERROR_FULL_STACK, we installed a handler
761 { 761 {
762 STACK_CHECK( L, 0); 762 STACK_CHECK( L, 0);
763 // fetch the call stack table from the registry where the handler stored it 763 // fetch the call stack table from the registry where the handler stored it
764 STACK_GROW( L, 1); 764 STACK_GROW( L, 1);
765 // yields nil if no stack was generated (in case of cancellation for example) 765 // yields nil if no stack was generated (in case of cancellation for example)
766 REGISTRY_GET( L, STACKTRACE_REGKEY); // err trace|nil 766 REGISTRY_GET( L, STACKTRACE_REGKEY); // err trace|nil
767 STACK_END( L, 1); 767 STACK_END( L, 1);
768 768
769 // For cancellation the error message is CANCEL_ERROR, and a stack trace isn't placed 769 // For cancellation the error message is CANCEL_ERROR, and a stack trace isn't placed
770 // For other errors, the message can be whatever was thrown, and we should have a stack trace table 770 // For other errors, the message can be whatever was thrown, and we should have a stack trace table
771 ASSERT_L( lua_type( L, 1 + stk_base_) == (equal_unique_key( L, stk_base_, CANCEL_ERROR) ? LUA_TNIL : LUA_TTABLE)); 771 ASSERT_L( lua_type( L, 1 + stk_base_) == (equal_unique_key( L, stk_base_, CANCEL_ERROR) ? LUA_TNIL : LUA_TTABLE));
772 // Just leaving the stack trace table on the stack is enough to get it through to the master. 772 // Just leaving the stack trace table on the stack is enough to get it through to the master.
773 break; 773 break;
774 } 774 }
775#endif // fall through if not ERROR_FULL_STACK 775#endif // fall through if not ERROR_FULL_STACK
776 776
777 case LUA_ERRMEM: // memory allocation error (handler not called) 777 case LUA_ERRMEM: // memory allocation error (handler not called)
778 case LUA_ERRERR: // error while running the error handler (if any, for example an out-of-memory condition) 778 case LUA_ERRERR: // error while running the error handler (if any, for example an out-of-memory condition)
779 default: 779 default:
780 // we should have a single value which is either a string (the error message) or CANCEL_ERROR 780 // we should have a single value which is either a string (the error message) or CANCEL_ERROR
781 ASSERT_L( (lua_gettop( L) == stk_base_) && ((lua_type( L, stk_base_) == LUA_TSTRING) || equal_unique_key( L, stk_base_, CANCEL_ERROR))); 781 ASSERT_L( (lua_gettop( L) == stk_base_) && ((lua_type( L, stk_base_) == LUA_TSTRING) || equal_unique_key( L, stk_base_, CANCEL_ERROR)));
782 break; 782 break;
783 } 783 }
784} 784}
785 785
786LUAG_FUNC( set_debug_threadname) 786LUAG_FUNC( set_debug_threadname)
787{ 787{
788 DECLARE_CONST_UNIQUE_KEY( hidden_regkey, LG_set_debug_threadname); 788 DECLARE_CONST_UNIQUE_KEY( hidden_regkey, LG_set_debug_threadname);
789 // C s_lane structure is a light userdata upvalue 789 // C s_lane structure is a light userdata upvalue
790 Lane* s = lua_touserdata( L, lua_upvalueindex( 1)); 790 Lane* s = lua_touserdata( L, lua_upvalueindex( 1));
791 luaL_checktype( L, -1, LUA_TSTRING); // "name" 791 luaL_checktype( L, -1, LUA_TSTRING); // "name"
792 lua_settop( L, 1); 792 lua_settop( L, 1);
793 STACK_CHECK_ABS( L, 1); 793 STACK_CHECK_ABS( L, 1);
794 // 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... 794 // 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...
795 REGISTRY_SET( L, hidden_regkey, lua_pushvalue( L, -2)); 795 REGISTRY_SET( L, hidden_regkey, lua_pushvalue( L, -2));
796 STACK_MID( L, 1); 796 STACK_MID( L, 1);
797 s->debug_name = lua_tostring( L, -1); 797 s->debug_name = lua_tostring( L, -1);
798 // keep a direct pointer on the string 798 // keep a direct pointer on the string
799 THREAD_SETNAME( s->debug_name); 799 THREAD_SETNAME( s->debug_name);
800 // to see VM name in Decoda debugger Virtual Machine window 800 // to see VM name in Decoda debugger Virtual Machine window
801 lua_setglobal( L, "decoda_name"); // 801 lua_setglobal( L, "decoda_name"); //
802 STACK_END( L, 0); 802 STACK_END( L, 0);
803 return 0; 803 return 0;
804} 804}
805 805
806LUAG_FUNC( get_debug_threadname) 806LUAG_FUNC( get_debug_threadname)
807{ 807{
808 Lane* const s = lua_toLane( L, 1); 808 Lane* const s = lua_toLane( L, 1);
809 luaL_argcheck( L, lua_gettop( L) == 1, 2, "too many arguments"); 809 luaL_argcheck( L, lua_gettop( L) == 1, 2, "too many arguments");
810 lua_pushstring( L, s->debug_name); 810 lua_pushstring( L, s->debug_name);
811 return 1; 811 return 1;
812} 812}
813 813
814LUAG_FUNC( set_thread_priority) 814LUAG_FUNC( set_thread_priority)
815{ 815{
816 int const prio = (int) luaL_checkinteger( L, 1); 816 int const prio = (int) luaL_checkinteger( L, 1);
817 // public Lanes API accepts a generic range -3/+3 817 // public Lanes API accepts a generic range -3/+3
818 // that will be remapped into the platform-specific scheduler priority scheme 818 // that will be remapped into the platform-specific scheduler priority scheme
819 // On some platforms, -3 is equivalent to -2 and +3 to +2 819 // On some platforms, -3 is equivalent to -2 and +3 to +2
820 if( prio < THREAD_PRIO_MIN || prio > THREAD_PRIO_MAX) 820 if( prio < THREAD_PRIO_MIN || prio > THREAD_PRIO_MAX)
821 { 821 {
822 return luaL_error( L, "priority out of range: %d..+%d (%d)", THREAD_PRIO_MIN, THREAD_PRIO_MAX, prio); 822 return luaL_error( L, "priority out of range: %d..+%d (%d)", THREAD_PRIO_MIN, THREAD_PRIO_MAX, prio);
823 } 823 }
824 THREAD_SET_PRIORITY( prio); 824 THREAD_SET_PRIORITY( prio);
825 return 0; 825 return 0;
826} 826}
827 827
828LUAG_FUNC( set_thread_affinity) 828LUAG_FUNC( set_thread_affinity)
829{ 829{
830 lua_Integer affinity = luaL_checkinteger( L, 1); 830 lua_Integer affinity = luaL_checkinteger( L, 1);
831 if( affinity <= 0) 831 if( affinity <= 0)
832 { 832 {
833 return luaL_error( L, "invalid affinity (%d)", affinity); 833 return luaL_error( L, "invalid affinity (%d)", affinity);
834 } 834 }
835 THREAD_SET_AFFINITY( (unsigned int) affinity); 835 THREAD_SET_AFFINITY( (unsigned int) affinity);
836 return 0; 836 return 0;
837} 837}
838 838
839#if USE_DEBUG_SPEW 839#if USE_DEBUG_SPEW
@@ -841,141 +841,141 @@ LUAG_FUNC( set_thread_affinity)
841// LUA_ERRERR doesn't have the same value 841// LUA_ERRERR doesn't have the same value
842struct errcode_name 842struct errcode_name
843{ 843{
844 int code; 844 int code;
845 char const* name; 845 char const* name;
846}; 846};
847 847
848static struct errcode_name s_errcodes[] = 848static struct errcode_name s_errcodes[] =
849{ 849{
850 { LUA_OK, "LUA_OK"}, 850 { LUA_OK, "LUA_OK"},
851 { LUA_YIELD, "LUA_YIELD"}, 851 { LUA_YIELD, "LUA_YIELD"},
852 { LUA_ERRRUN, "LUA_ERRRUN"}, 852 { LUA_ERRRUN, "LUA_ERRRUN"},
853 { LUA_ERRSYNTAX, "LUA_ERRSYNTAX"}, 853 { LUA_ERRSYNTAX, "LUA_ERRSYNTAX"},
854 { LUA_ERRMEM, "LUA_ERRMEM"}, 854 { LUA_ERRMEM, "LUA_ERRMEM"},
855 { LUA_ERRGCMM, "LUA_ERRGCMM"}, 855 { LUA_ERRGCMM, "LUA_ERRGCMM"},
856 { LUA_ERRERR, "LUA_ERRERR"}, 856 { LUA_ERRERR, "LUA_ERRERR"},
857}; 857};
858static char const* get_errcode_name( int _code) 858static char const* get_errcode_name( int _code)
859{ 859{
860 int i; 860 int i;
861 for( i = 0; i < 7; ++ i) 861 for( i = 0; i < 7; ++ i)
862 { 862 {
863 if( s_errcodes[i].code == _code) 863 if( s_errcodes[i].code == _code)
864 { 864 {
865 return s_errcodes[i].name; 865 return s_errcodes[i].name;
866 } 866 }
867 } 867 }
868 return "<NULL>"; 868 return "<NULL>";
869} 869}
870#endif // USE_DEBUG_SPEW 870#endif // USE_DEBUG_SPEW
871 871
872#if THREADWAIT_METHOD == THREADWAIT_CONDVAR // implies THREADAPI == THREADAPI_PTHREAD 872#if THREADWAIT_METHOD == THREADWAIT_CONDVAR // implies THREADAPI == THREADAPI_PTHREAD
873static void thread_cleanup_handler( void* opaque) 873static void thread_cleanup_handler( void* opaque)
874{ 874{
875 Lane* s= (Lane*) opaque; 875 Lane* s= (Lane*) opaque;
876 MUTEX_LOCK( &s->done_lock); 876 MUTEX_LOCK( &s->done_lock);
877 s->status = CANCELLED; 877 s->status = CANCELLED;
878 SIGNAL_ONE( &s->done_signal); // wake up master (while 's->done_lock' is on) 878 SIGNAL_ONE( &s->done_signal); // wake up master (while 's->done_lock' is on)
879 MUTEX_UNLOCK( &s->done_lock); 879 MUTEX_UNLOCK( &s->done_lock);
880} 880}
881#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR 881#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
882 882
883static THREAD_RETURN_T THREAD_CALLCONV lane_main( void* vs) 883static THREAD_RETURN_T THREAD_CALLCONV lane_main( void* vs)
884{ 884{
885 Lane* s = (Lane*) vs; 885 Lane* s = (Lane*) vs;
886 int rc, rc2; 886 int rc, rc2;
887 lua_State* L = s->L; 887 lua_State* L = s->L;
888 // Called with the lane function and arguments on the stack 888 // Called with the lane function and arguments on the stack
889 int const nargs = lua_gettop( L) - 1; 889 int const nargs = lua_gettop( L) - 1;
890 DEBUGSPEW_CODE( Universe* U = universe_get( L)); 890 DEBUGSPEW_CODE( Universe* U = universe_get( L));
891 THREAD_MAKE_ASYNCH_CANCELLABLE(); 891 THREAD_MAKE_ASYNCH_CANCELLABLE();
892 THREAD_CLEANUP_PUSH( thread_cleanup_handler, s); 892 THREAD_CLEANUP_PUSH( thread_cleanup_handler, s);
893 s->status = RUNNING; // PENDING -> RUNNING 893 s->status = RUNNING; // PENDING -> RUNNING
894 894
895 // Tie "set_finalizer()" to the state 895 // Tie "set_finalizer()" to the state
896 lua_pushcfunction( L, LG_set_finalizer); 896 lua_pushcfunction( L, LG_set_finalizer);
897 populate_func_lookup_table( L, -1, "set_finalizer"); 897 populate_func_lookup_table( L, -1, "set_finalizer");
898 lua_setglobal( L, "set_finalizer"); 898 lua_setglobal( L, "set_finalizer");
899 899
900 // Tie "set_debug_threadname()" to the state 900 // Tie "set_debug_threadname()" to the state
901 // But don't register it in the lookup database because of the s_lane pointer upvalue 901 // But don't register it in the lookup database because of the s_lane pointer upvalue
902 lua_pushlightuserdata( L, s); 902 lua_pushlightuserdata( L, s);
903 lua_pushcclosure( L, LG_set_debug_threadname, 1); 903 lua_pushcclosure( L, LG_set_debug_threadname, 1);
904 lua_setglobal( L, "set_debug_threadname"); 904 lua_setglobal( L, "set_debug_threadname");
905 905
906 // Tie "cancel_test()" to the state 906 // Tie "cancel_test()" to the state
907 lua_pushcfunction( L, LG_cancel_test); 907 lua_pushcfunction( L, LG_cancel_test);
908 populate_func_lookup_table( L, -1, "cancel_test"); 908 populate_func_lookup_table( L, -1, "cancel_test");
909 lua_setglobal( L, "cancel_test"); 909 lua_setglobal( L, "cancel_test");
910 910
911 // this could be done in lane_new before the lane body function is pushed on the stack to avoid unnecessary stack slot shifting around 911 // this could be done in lane_new before the lane body function is pushed on the stack to avoid unnecessary stack slot shifting around
912#if ERROR_FULL_STACK 912#if ERROR_FULL_STACK
913 // Tie "set_error_reporting()" to the state 913 // Tie "set_error_reporting()" to the state
914 lua_pushcfunction( L, LG_set_error_reporting); 914 lua_pushcfunction( L, LG_set_error_reporting);
915 populate_func_lookup_table( L, -1, "set_error_reporting"); 915 populate_func_lookup_table( L, -1, "set_error_reporting");
916 lua_setglobal( L, "set_error_reporting"); 916 lua_setglobal( L, "set_error_reporting");
917 917
918 STACK_GROW( L, 1); 918 STACK_GROW( L, 1);
919 lua_pushcfunction( L, lane_error); // func args handler 919 lua_pushcfunction( L, lane_error); // func args handler
920 lua_insert( L, 1); // handler func args 920 lua_insert( L, 1); // handler func args
921#endif // ERROR_FULL_STACK 921#endif // ERROR_FULL_STACK
922 922
923 rc = lua_pcall( L, nargs, LUA_MULTRET, ERROR_FULL_STACK); // retvals|err 923 rc = lua_pcall( L, nargs, LUA_MULTRET, ERROR_FULL_STACK); // retvals|err
924 924
925#if ERROR_FULL_STACK 925#if ERROR_FULL_STACK
926 lua_remove( L, 1); // retvals|error 926 lua_remove( L, 1); // retvals|error
927# endif // ERROR_FULL_STACK 927# endif // ERROR_FULL_STACK
928 928
929 // in case of error and if it exists, fetch stack trace from registry and push it 929 // in case of error and if it exists, fetch stack trace from registry and push it
930 push_stack_trace( L, rc, 1); // retvals|error [trace] 930 push_stack_trace( L, rc, 1); // retvals|error [trace]
931 931
932 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "Lane %p body: %s (%s)\n" INDENT_END, L, get_errcode_name( rc), equal_unique_key( L, 1, CANCEL_ERROR) ? "cancelled" : lua_typename( L, lua_type( L, 1)))); 932 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "Lane %p body: %s (%s)\n" INDENT_END, L, get_errcode_name( rc), equal_unique_key( L, 1, CANCEL_ERROR) ? "cancelled" : lua_typename( L, lua_type( L, 1))));
933 //STACK_DUMP(L); 933 //STACK_DUMP(L);
934 // Call finalizers, if the script has set them up. 934 // Call finalizers, if the script has set them up.
935 // 935 //
936 rc2 = run_finalizers( L, rc); 936 rc2 = run_finalizers( L, rc);
937 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "Lane %p finalizer: %s\n" INDENT_END, L, get_errcode_name( rc2))); 937 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "Lane %p finalizer: %s\n" INDENT_END, L, get_errcode_name( rc2)));
938 if( rc2 != LUA_OK) // Error within a finalizer! 938 if( rc2 != LUA_OK) // Error within a finalizer!
939 { 939 {
940 // the finalizer generated an error, and left its own error message [and stack trace] on the stack 940 // the finalizer generated an error, and left its own error message [and stack trace] on the stack
941 rc = rc2; // we're overruling the earlier script error or normal return 941 rc = rc2; // we're overruling the earlier script error or normal return
942 } 942 }
943 s->waiting_on = NULL; // just in case 943 s->waiting_on = NULL; // just in case
944 if( selfdestruct_remove( s)) // check and remove (under lock!) 944 if( selfdestruct_remove( s)) // check and remove (under lock!)
945 { 945 {
946 // We're a free-running thread and no-one's there to clean us up. 946 // We're a free-running thread and no-one's there to clean us up.
947 // 947 //
948 lua_close( s->L); 948 lua_close( s->L);
949 949
950 MUTEX_LOCK( &s->U->selfdestruct_cs); 950 MUTEX_LOCK( &s->U->selfdestruct_cs);
951 // done with lua_close(), terminal shutdown sequence may proceed 951 // done with lua_close(), terminal shutdown sequence may proceed
952 -- s->U->selfdestructing_count; 952 -- s->U->selfdestructing_count;
953 MUTEX_UNLOCK( &s->U->selfdestruct_cs); 953 MUTEX_UNLOCK( &s->U->selfdestruct_cs);
954 954
955 lane_cleanup( s); // s is freed at this point 955 lane_cleanup( s); // s is freed at this point
956 } 956 }
957 else 957 else
958 { 958 {
959 // leave results (1..top) or error message + stack trace (1..2) on the stack - master will copy them 959 // leave results (1..top) or error message + stack trace (1..2) on the stack - master will copy them
960 960
961 enum e_status st = (rc == 0) ? DONE : equal_unique_key( L, 1, CANCEL_ERROR) ? CANCELLED : ERROR_ST; 961 enum e_status st = (rc == 0) ? DONE : equal_unique_key( L, 1, CANCEL_ERROR) ? CANCELLED : ERROR_ST;
962 962
963 // Posix no PTHREAD_TIMEDJOIN: 963 // Posix no PTHREAD_TIMEDJOIN:
964 // 'done_lock' protects the -> DONE|ERROR_ST|CANCELLED state change 964 // 'done_lock' protects the -> DONE|ERROR_ST|CANCELLED state change
965 // 965 //
966#if THREADWAIT_METHOD == THREADWAIT_CONDVAR 966#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
967 MUTEX_LOCK( &s->done_lock); 967 MUTEX_LOCK( &s->done_lock);
968 { 968 {
969#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR 969#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
970 s->status = st; 970 s->status = st;
971#if THREADWAIT_METHOD == THREADWAIT_CONDVAR 971#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
972 SIGNAL_ONE( &s->done_signal); // wake up master (while 's->done_lock' is on) 972 SIGNAL_ONE( &s->done_signal); // wake up master (while 's->done_lock' is on)
973 } 973 }
974 MUTEX_UNLOCK( &s->done_lock); 974 MUTEX_UNLOCK( &s->done_lock);
975#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR 975#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
976 } 976 }
977 THREAD_CLEANUP_POP( FALSE); 977 THREAD_CLEANUP_POP( FALSE);
978 return 0; // ignored 978 return 0; // ignored
979} 979}
980 980
981// --- If a client wants to transfer stuff of a given module from the current state to another Lane, the module must be required 981// --- If a client wants to transfer stuff of a given module from the current state to another Lane, the module must be required
@@ -984,20 +984,20 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void* vs)
984// upvalue[1]: _G.require 984// upvalue[1]: _G.require
985LUAG_FUNC( require) 985LUAG_FUNC( require)
986{ 986{
987 char const* name = lua_tostring( L, 1); 987 char const* name = lua_tostring( L, 1);
988 int const nargs = lua_gettop( L); 988 int const nargs = lua_gettop( L);
989 DEBUGSPEW_CODE( Universe* U = universe_get( L)); 989 DEBUGSPEW_CODE( Universe* U = universe_get( L));
990 STACK_CHECK( L, 0); 990 STACK_CHECK( L, 0);
991 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.require %s BEGIN\n" INDENT_END, name)); 991 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.require %s BEGIN\n" INDENT_END, name));
992 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); 992 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
993 lua_pushvalue( L, lua_upvalueindex(1)); // "name" require 993 lua_pushvalue( L, lua_upvalueindex(1)); // "name" require
994 lua_insert( L, 1); // require "name" 994 lua_insert( L, 1); // require "name"
995 lua_call( L, nargs, 1); // module 995 lua_call( L, nargs, 1); // module
996 populate_func_lookup_table( L, -1, name); 996 populate_func_lookup_table( L, -1, name);
997 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.require %s END\n" INDENT_END, name)); 997 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.require %s END\n" INDENT_END, name));
998 DEBUGSPEW_CODE( -- U->debugspew_indent_depth); 998 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
999 STACK_END( L, 0); 999 STACK_END( L, 0);
1000 return 1; 1000 return 1;
1001} 1001}
1002 1002
1003 1003
@@ -1006,20 +1006,20 @@ LUAG_FUNC( require)
1006// lanes.register( "modname", module) 1006// lanes.register( "modname", module)
1007LUAG_FUNC( register) 1007LUAG_FUNC( register)
1008{ 1008{
1009 char const* name = luaL_checkstring( L, 1); 1009 char const* name = luaL_checkstring( L, 1);
1010 int const mod_type = lua_type( L, 2); 1010 int const mod_type = lua_type( L, 2);
1011 // ignore extra parameters, just in case 1011 // ignore extra parameters, just in case
1012 lua_settop( L, 2); 1012 lua_settop( L, 2);
1013 luaL_argcheck( L, (mod_type == LUA_TTABLE) || (mod_type == LUA_TFUNCTION), 2, "unexpected module type"); 1013 luaL_argcheck( L, (mod_type == LUA_TTABLE) || (mod_type == LUA_TFUNCTION), 2, "unexpected module type");
1014 DEBUGSPEW_CODE( Universe* U = universe_get( L)); 1014 DEBUGSPEW_CODE( Universe* U = universe_get( L));
1015 STACK_CHECK( L, 0); // "name" mod_table 1015 STACK_CHECK( L, 0); // "name" mod_table
1016 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.register %s BEGIN\n" INDENT_END, name)); 1016 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.register %s BEGIN\n" INDENT_END, name));
1017 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); 1017 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
1018 populate_func_lookup_table( L, -1, name); 1018 populate_func_lookup_table( L, -1, name);
1019 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.register %s END\n" INDENT_END, name)); 1019 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.register %s END\n" INDENT_END, name));
1020 DEBUGSPEW_CODE( -- U->debugspew_indent_depth); 1020 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
1021 STACK_END( L, 0); 1021 STACK_END( L, 0);
1022 return 0; 1022 return 0;
1023} 1023}
1024 1024
1025// crc64/we of string "GCCB_KEY" generated at http://www.nitrxgen.net/hashgen/ 1025// crc64/we of string "GCCB_KEY" generated at http://www.nitrxgen.net/hashgen/
@@ -1039,247 +1039,247 @@ static DECLARE_CONST_UNIQUE_KEY( GCCB_KEY, 0xcfb1f046ef074e88);
1039// 1039//
1040LUAG_FUNC( lane_new) 1040LUAG_FUNC( lane_new)
1041{ 1041{
1042 lua_State* L2; 1042 lua_State* L2;
1043 Lane* s; 1043 Lane* s;
1044 Lane** ud; 1044 Lane** ud;
1045 1045
1046 char const* libs_str = lua_tostring( L, 2); 1046 char const* libs_str = lua_tostring( L, 2);
1047 int const priority = (int) luaL_optinteger( L, 3, 0); 1047 int const priority = (int) luaL_optinteger( L, 3, 0);
1048 uint_t globals_idx = lua_isnoneornil( L, 4) ? 0 : 4; 1048 uint_t globals_idx = lua_isnoneornil( L, 4) ? 0 : 4;
1049 uint_t package_idx = lua_isnoneornil( L, 5) ? 0 : 5; 1049 uint_t package_idx = lua_isnoneornil( L, 5) ? 0 : 5;
1050 uint_t required_idx = lua_isnoneornil( L, 6) ? 0 : 6; 1050 uint_t required_idx = lua_isnoneornil( L, 6) ? 0 : 6;
1051 uint_t gc_cb_idx = lua_isnoneornil( L, 7) ? 0 : 7; 1051 uint_t gc_cb_idx = lua_isnoneornil( L, 7) ? 0 : 7;
1052 1052
1053#define FIXED_ARGS 7 1053#define FIXED_ARGS 7
1054 int const nargs = lua_gettop(L) - FIXED_ARGS; 1054 int const nargs = lua_gettop(L) - FIXED_ARGS;
1055 Universe* U = universe_get( L); 1055 Universe* U = universe_get( L);
1056 ASSERT_L( nargs >= 0); 1056 ASSERT_L( nargs >= 0);
1057 1057
1058 // public Lanes API accepts a generic range -3/+3 1058 // public Lanes API accepts a generic range -3/+3
1059 // that will be remapped into the platform-specific scheduler priority scheme 1059 // that will be remapped into the platform-specific scheduler priority scheme
1060 // On some platforms, -3 is equivalent to -2 and +3 to +2 1060 // On some platforms, -3 is equivalent to -2 and +3 to +2
1061 if( priority < THREAD_PRIO_MIN || priority > THREAD_PRIO_MAX) 1061 if( priority < THREAD_PRIO_MIN || priority > THREAD_PRIO_MAX)
1062 { 1062 {
1063 return luaL_error( L, "Priority out of range: %d..+%d (%d)", THREAD_PRIO_MIN, THREAD_PRIO_MAX, priority); 1063 return luaL_error( L, "Priority out of range: %d..+%d (%d)", THREAD_PRIO_MIN, THREAD_PRIO_MAX, priority);
1064 } 1064 }
1065 1065
1066 /* --- Create and prepare the sub state --- */ 1066 /* --- Create and prepare the sub state --- */
1067 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: setup\n" INDENT_END)); 1067 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: setup\n" INDENT_END));
1068 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); 1068 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
1069 1069
1070 // populate with selected libraries at the same time 1070 // populate with selected libraries at the same time
1071 L2 = luaG_newstate( U, L, libs_str); // L // L2 1071 L2 = luaG_newstate( U, L, libs_str); // L // L2
1072 1072
1073 STACK_GROW( L2, nargs + 3); // 1073 STACK_GROW( L2, nargs + 3); //
1074 STACK_CHECK( L2, 0); 1074 STACK_CHECK( L2, 0);
1075 1075
1076 STACK_GROW( L, 3); // func libs priority globals package required gc_cb [... args ...] 1076 STACK_GROW( L, 3); // func libs priority globals package required gc_cb [... args ...]
1077 STACK_CHECK( L, 0); 1077 STACK_CHECK( L, 0);
1078 1078
1079 // give a default "Lua" name to the thread to see VM name in Decoda debugger 1079 // give a default "Lua" name to the thread to see VM name in Decoda debugger
1080 lua_pushfstring( L2, "Lane #%p", L2); // "..." 1080 lua_pushfstring( L2, "Lane #%p", L2); // "..."
1081 lua_setglobal( L2, "decoda_name"); // 1081 lua_setglobal( L2, "decoda_name"); //
1082 ASSERT_L( lua_gettop( L2) == 0); 1082 ASSERT_L( lua_gettop( L2) == 0);
1083 1083
1084 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: update 'package'\n" INDENT_END)); 1084 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: update 'package'\n" INDENT_END));
1085 // package 1085 // package
1086 if( package_idx != 0) 1086 if( package_idx != 0)
1087 { 1087 {
1088 // when copying with mode eLM_LaneBody, should raise an error in case of problem, not leave it one the stack 1088 // when copying with mode eLM_LaneBody, should raise an error in case of problem, not leave it one the stack
1089 (void) luaG_inter_copy_package( U, L, L2, package_idx, eLM_LaneBody); 1089 (void) luaG_inter_copy_package( U, L, L2, package_idx, eLM_LaneBody);
1090 } 1090 }
1091 1091
1092 // modules to require in the target lane *before* the function is transfered! 1092 // modules to require in the target lane *before* the function is transfered!
1093 1093
1094 if( required_idx != 0) 1094 if( required_idx != 0)
1095 { 1095 {
1096 int nbRequired = 1; 1096 int nbRequired = 1;
1097 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: require 'required' list\n" INDENT_END)); 1097 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: require 'required' list\n" INDENT_END));
1098 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); 1098 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
1099 // should not happen, was checked in lanes.lua before calling lane_new() 1099 // should not happen, was checked in lanes.lua before calling lane_new()
1100 if( lua_type( L, required_idx) != LUA_TTABLE) 1100 if( lua_type( L, required_idx) != LUA_TTABLE)
1101 { 1101 {
1102 return luaL_error( L, "expected required module list as a table, got %s", luaL_typename( L, required_idx)); 1102 return luaL_error( L, "expected required module list as a table, got %s", luaL_typename( L, required_idx));
1103 } 1103 }
1104 1104
1105 lua_pushnil( L); // func libs priority globals package required gc_cb [... args ...] nil 1105 lua_pushnil( L); // func libs priority globals package required gc_cb [... args ...] nil
1106 while( lua_next( L, required_idx) != 0) // func libs priority globals package required gc_cb [... args ...] n "modname" 1106 while( lua_next( L, required_idx) != 0) // func libs priority globals package required gc_cb [... args ...] n "modname"
1107 { 1107 {
1108 if( lua_type( L, -1) != LUA_TSTRING || lua_type( L, -2) != LUA_TNUMBER || lua_tonumber( L, -2) != nbRequired) 1108 if( lua_type( L, -1) != LUA_TSTRING || lua_type( L, -2) != LUA_TNUMBER || lua_tonumber( L, -2) != nbRequired)
1109 { 1109 {
1110 return luaL_error( L, "required module list should be a list of strings"); 1110 return luaL_error( L, "required module list should be a list of strings");
1111 } 1111 }
1112 else 1112 else
1113 { 1113 {
1114 // require the module in the target state, and populate the lookup table there too 1114 // require the module in the target state, and populate the lookup table there too
1115 size_t len; 1115 size_t len;
1116 char const* name = lua_tolstring( L, -1, &len); 1116 char const* name = lua_tolstring( L, -1, &len);
1117 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: require '%s'\n" INDENT_END, name)); 1117 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: require '%s'\n" INDENT_END, name));
1118 1118
1119 // require the module in the target lane 1119 // require the module in the target lane
1120 lua_getglobal( L2, "require"); // require()? 1120 lua_getglobal( L2, "require"); // require()?
1121 if( lua_isnil( L2, -1)) 1121 if( lua_isnil( L2, -1))
1122 { 1122 {
1123 lua_pop( L2, 1); // 1123 lua_pop( L2, 1); //
1124 luaL_error( L, "cannot pre-require modules without loading 'package' library first"); 1124 luaL_error( L, "cannot pre-require modules without loading 'package' library first");
1125 } 1125 }
1126 else 1126 else
1127 { 1127 {
1128 lua_pushlstring( L2, name, len); // require() name 1128 lua_pushlstring( L2, name, len); // require() name
1129 if( lua_pcall( L2, 1, 1, 0) != LUA_OK) // ret/errcode 1129 if( lua_pcall( L2, 1, 1, 0) != LUA_OK) // ret/errcode
1130 { 1130 {
1131 // propagate error to main state if any 1131 // propagate error to main state if any
1132 luaG_inter_move( U, L2, L, 1, eLM_LaneBody); // func libs priority globals package required gc_cb [... args ...] n "modname" error 1132 luaG_inter_move( U, L2, L, 1, eLM_LaneBody); // func libs priority globals package required gc_cb [... args ...] n "modname" error
1133 return lua_error( L); 1133 return lua_error( L);
1134 } 1134 }
1135 // after requiring the module, register the functions it exported in our name<->function database 1135 // after requiring the module, register the functions it exported in our name<->function database
1136 populate_func_lookup_table( L2, -1, name); 1136 populate_func_lookup_table( L2, -1, name);
1137 lua_pop( L2, 1); // 1137 lua_pop( L2, 1); //
1138 } 1138 }
1139 } 1139 }
1140 lua_pop( L, 1); // func libs priority globals package required gc_cb [... args ...] n 1140 lua_pop( L, 1); // func libs priority globals package required gc_cb [... args ...] n
1141 ++ nbRequired; 1141 ++ nbRequired;
1142 } // func libs priority globals package required gc_cb [... args ...] 1142 } // func libs priority globals package required gc_cb [... args ...]
1143 DEBUGSPEW_CODE( -- U->debugspew_indent_depth); 1143 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
1144 } 1144 }
1145 STACK_MID( L, 0); 1145 STACK_MID( L, 0);
1146 STACK_MID( L2, 0); // 1146 STACK_MID( L2, 0); //
1147 1147
1148 // Appending the specified globals to the global environment 1148 // Appending the specified globals to the global environment
1149 // *after* stdlibs have been loaded and modules required, in case we transfer references to native functions they exposed... 1149 // *after* stdlibs have been loaded and modules required, in case we transfer references to native functions they exposed...
1150 // 1150 //
1151 if( globals_idx != 0) 1151 if( globals_idx != 0)
1152 { 1152 {
1153 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: transfer globals\n" INDENT_END)); 1153 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: transfer globals\n" INDENT_END));
1154 if( !lua_istable( L, globals_idx)) 1154 if( !lua_istable( L, globals_idx))
1155 { 1155 {
1156 return luaL_error( L, "Expected table, got %s", luaL_typename( L, globals_idx)); 1156 return luaL_error( L, "Expected table, got %s", luaL_typename( L, globals_idx));
1157 } 1157 }
1158 1158
1159 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); 1159 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
1160 lua_pushnil( L); // func libs priority globals package required gc_cb [... args ...] nil 1160 lua_pushnil( L); // func libs priority globals package required gc_cb [... args ...] nil
1161 // Lua 5.2 wants us to push the globals table on the stack 1161 // Lua 5.2 wants us to push the globals table on the stack
1162 lua_pushglobaltable( L2); // _G 1162 lua_pushglobaltable( L2); // _G
1163 while( lua_next( L, globals_idx)) // func libs priority globals package required gc_cb [... args ...] k v 1163 while( lua_next( L, globals_idx)) // func libs priority globals package required gc_cb [... args ...] k v
1164 { 1164 {
1165 luaG_inter_copy( U, L, L2, 2, eLM_LaneBody); // _G k v 1165 luaG_inter_copy( U, L, L2, 2, eLM_LaneBody); // _G k v
1166 // assign it in L2's globals table 1166 // assign it in L2's globals table
1167 lua_rawset( L2, -3); // _G 1167 lua_rawset( L2, -3); // _G
1168 lua_pop( L, 1); // func libs priority globals package required gc_cb [... args ...] k 1168 lua_pop( L, 1); // func libs priority globals package required gc_cb [... args ...] k
1169 } // func libs priority globals package required gc_cb [... args ...] 1169 } // func libs priority globals package required gc_cb [... args ...]
1170 lua_pop( L2, 1); // 1170 lua_pop( L2, 1); //
1171 1171
1172 DEBUGSPEW_CODE( -- U->debugspew_indent_depth); 1172 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
1173 } 1173 }
1174 STACK_MID( L, 0); 1174 STACK_MID( L, 0);
1175 STACK_MID( L2, 0); 1175 STACK_MID( L2, 0);
1176 1176
1177 // Lane main function 1177 // Lane main function
1178 if( lua_type( L, 1) == LUA_TFUNCTION) 1178 if( lua_type( L, 1) == LUA_TFUNCTION)
1179 { 1179 {
1180 int res; 1180 int res;
1181 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: transfer lane body\n" INDENT_END)); 1181 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: transfer lane body\n" INDENT_END));
1182 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); 1182 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
1183 lua_pushvalue( L, 1); // func libs priority globals package required gc_cb [... args ...] func 1183 lua_pushvalue( L, 1); // func libs priority globals package required gc_cb [... args ...] func
1184 res = luaG_inter_move( U, L, L2, 1, eLM_LaneBody); // func libs priority globals package required gc_cb [... args ...] // func 1184 res = luaG_inter_move( U, L, L2, 1, eLM_LaneBody); // func libs priority globals package required gc_cb [... args ...] // func
1185 DEBUGSPEW_CODE( -- U->debugspew_indent_depth); 1185 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
1186 if( res != 0) 1186 if( res != 0)
1187 { 1187 {
1188 return luaL_error( L, "tried to copy unsupported types"); 1188 return luaL_error( L, "tried to copy unsupported types");
1189 } 1189 }
1190 } 1190 }
1191 else if( lua_type( L, 1) == LUA_TSTRING) 1191 else if( lua_type( L, 1) == LUA_TSTRING)
1192 { 1192 {
1193 // compile the string 1193 // compile the string
1194 if( luaL_loadstring( L2, lua_tostring( L, 1)) != 0) // func 1194 if( luaL_loadstring( L2, lua_tostring( L, 1)) != 0) // func
1195 { 1195 {
1196 return luaL_error( L, "error when parsing lane function code"); 1196 return luaL_error( L, "error when parsing lane function code");
1197 } 1197 }
1198 } 1198 }
1199 STACK_MID( L, 0); 1199 STACK_MID( L, 0);
1200 STACK_MID( L2, 1); 1200 STACK_MID( L2, 1);
1201 ASSERT_L( lua_isfunction( L2, 1)); 1201 ASSERT_L( lua_isfunction( L2, 1));
1202 1202
1203 // revive arguments 1203 // revive arguments
1204 if( nargs > 0) 1204 if( nargs > 0)
1205 { 1205 {
1206 int res; 1206 int res;
1207 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: transfer lane arguments\n" INDENT_END)); 1207 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: transfer lane arguments\n" INDENT_END));
1208 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); 1208 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
1209 res = luaG_inter_move( U, L, L2, nargs, eLM_LaneBody); // func libs priority globals package required gc_cb // func [... args ...] 1209 res = luaG_inter_move( U, L, L2, nargs, eLM_LaneBody); // func libs priority globals package required gc_cb // func [... args ...]
1210 DEBUGSPEW_CODE( -- U->debugspew_indent_depth); 1210 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
1211 if( res != 0) 1211 if( res != 0)
1212 { 1212 {
1213 return luaL_error( L, "tried to copy unsupported types"); 1213 return luaL_error( L, "tried to copy unsupported types");
1214 } 1214 }
1215 } 1215 }
1216 STACK_END( L, -nargs); 1216 STACK_END( L, -nargs);
1217 ASSERT_L( lua_gettop( L) == FIXED_ARGS); 1217 ASSERT_L( lua_gettop( L) == FIXED_ARGS);
1218 STACK_CHECK( L, 0); 1218 STACK_CHECK( L, 0);
1219 STACK_MID( L2, 1 + nargs); 1219 STACK_MID( L2, 1 + nargs);
1220 1220
1221 // 's' is allocated from heap, not Lua, since its life span may surpass the handle's (if free running thread) 1221 // 's' is allocated from heap, not Lua, since its life span may surpass the handle's (if free running thread)
1222 // 1222 //
1223 // a Lane full userdata needs a single uservalue 1223 // a Lane full userdata needs a single uservalue
1224 ud = lua_newuserdatauv( L, sizeof( Lane*), 1); // func libs priority globals package required gc_cb lane 1224 ud = lua_newuserdatauv( L, sizeof( Lane*), 1); // func libs priority globals package required gc_cb lane
1225 s = *ud = (Lane*) malloc( sizeof( Lane)); 1225 s = *ud = (Lane*) malloc( sizeof( Lane));
1226 if( s == NULL) 1226 if( s == NULL)
1227 { 1227 {
1228 return luaL_error( L, "could not create lane: out of memory"); 1228 return luaL_error( L, "could not create lane: out of memory");
1229 } 1229 }
1230 1230
1231 s->L = L2; 1231 s->L = L2;
1232 s->U = U; 1232 s->U = U;
1233 s->status = PENDING; 1233 s->status = PENDING;
1234 s->waiting_on = NULL; 1234 s->waiting_on = NULL;
1235 s->debug_name = "<unnamed>"; 1235 s->debug_name = "<unnamed>";
1236 s->cancel_request = CANCEL_NONE; 1236 s->cancel_request = CANCEL_NONE;
1237 1237
1238#if THREADWAIT_METHOD == THREADWAIT_CONDVAR 1238#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
1239 MUTEX_INIT( &s->done_lock); 1239 MUTEX_INIT( &s->done_lock);
1240 SIGNAL_INIT( &s->done_signal); 1240 SIGNAL_INIT( &s->done_signal);
1241#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR 1241#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
1242 s->mstatus = NORMAL; 1242 s->mstatus = NORMAL;
1243 s->selfdestruct_next = NULL; 1243 s->selfdestruct_next = NULL;
1244#if HAVE_LANE_TRACKING 1244#if HAVE_LANE_TRACKING
1245 s->tracking_next = NULL; 1245 s->tracking_next = NULL;
1246 if( s->U->tracking_first) 1246 if( s->U->tracking_first)
1247 { 1247 {
1248 tracking_add( s); 1248 tracking_add( s);
1249 } 1249 }
1250#endif // HAVE_LANE_TRACKING 1250#endif // HAVE_LANE_TRACKING
1251 1251
1252 // Set metatable for the userdata 1252 // Set metatable for the userdata
1253 // 1253 //
1254 lua_pushvalue( L, lua_upvalueindex( 1)); // func libs priority globals package required gc_cb lane mt 1254 lua_pushvalue( L, lua_upvalueindex( 1)); // func libs priority globals package required gc_cb lane mt
1255 lua_setmetatable( L, -2); // func libs priority globals package required gc_cb lane 1255 lua_setmetatable( L, -2); // func libs priority globals package required gc_cb lane
1256 STACK_MID( L, 1); 1256 STACK_MID( L, 1);
1257 1257
1258 // Create uservalue for the userdata 1258 // Create uservalue for the userdata
1259 // (this is where lane body return values will be stored when the handle is indexed by a numeric key) 1259 // (this is where lane body return values will be stored when the handle is indexed by a numeric key)
1260 lua_newtable( L); // func libs cancelstep priority globals package required gc_cb lane uv 1260 lua_newtable( L); // func libs cancelstep priority globals package required gc_cb lane uv
1261 1261
1262 // Store the gc_cb callback in the uservalue 1262 // Store the gc_cb callback in the uservalue
1263 if( gc_cb_idx > 0) 1263 if( gc_cb_idx > 0)
1264 { 1264 {
1265 push_unique_key( L, GCCB_KEY); // func libs priority globals package required gc_cb lane uv k 1265 push_unique_key( L, GCCB_KEY); // func libs priority globals package required gc_cb lane uv k
1266 lua_pushvalue( L, gc_cb_idx); // func libs priority globals package required gc_cb lane uv k gc_cb 1266 lua_pushvalue( L, gc_cb_idx); // func libs priority globals package required gc_cb lane uv k gc_cb
1267 lua_rawset( L, -3); // func libs priority globals package required gc_cb lane uv 1267 lua_rawset( L, -3); // func libs priority globals package required gc_cb lane uv
1268 } 1268 }
1269 1269
1270 lua_setiuservalue( L, -2, 1); // func libs priority globals package required gc_cb lane 1270 lua_setiuservalue( L, -2, 1); // func libs priority globals package required gc_cb lane
1271 1271
1272 // Store 's' in the lane's registry, for 'cancel_test()' (we do cancel tests at pending send/receive). 1272 // Store 's' in the lane's registry, for 'cancel_test()' (we do cancel tests at pending send/receive).
1273 REGISTRY_SET( L2, CANCEL_TEST_KEY, lua_pushlightuserdata( L2, s)); // func [... args ...] 1273 REGISTRY_SET( L2, CANCEL_TEST_KEY, lua_pushlightuserdata( L2, s)); // func [... args ...]
1274 1274
1275 STACK_END( L, 1); 1275 STACK_END( L, 1);
1276 STACK_END( L2, 1 + nargs); 1276 STACK_END( L2, 1 + nargs);
1277 1277
1278 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: launching thread\n" INDENT_END)); 1278 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: launching thread\n" INDENT_END));
1279 THREAD_CREATE( &s->thread, lane_main, s, priority); 1279 THREAD_CREATE( &s->thread, lane_main, s, priority);
1280 1280
1281 DEBUGSPEW_CODE( -- U->debugspew_indent_depth); 1281 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
1282 return 1; 1282 return 1;
1283} 1283}
1284 1284
1285 1285
@@ -1297,79 +1297,79 @@ LUAG_FUNC( lane_new)
1297// 1297//
1298LUAG_FUNC( thread_gc) 1298LUAG_FUNC( thread_gc)
1299{ 1299{
1300 bool_t have_gc_cb = FALSE; 1300 bool_t have_gc_cb = FALSE;
1301 Lane* s = lua_toLane( L, 1); // ud 1301 Lane* s = lua_toLane( L, 1); // ud
1302 1302
1303 // if there a gc callback? 1303 // if there a gc callback?
1304 lua_getiuservalue( L, 1, 1); // ud uservalue 1304 lua_getiuservalue( L, 1, 1); // ud uservalue
1305 push_unique_key( L, GCCB_KEY); // ud uservalue __gc 1305 push_unique_key( L, GCCB_KEY); // ud uservalue __gc
1306 lua_rawget( L, -2); // ud uservalue gc_cb|nil 1306 lua_rawget( L, -2); // ud uservalue gc_cb|nil
1307 if( !lua_isnil( L, -1)) 1307 if( !lua_isnil( L, -1))
1308 { 1308 {
1309 lua_remove( L, -2); // ud gc_cb|nil 1309 lua_remove( L, -2); // ud gc_cb|nil
1310 lua_pushstring( L, s->debug_name); // ud gc_cb name 1310 lua_pushstring( L, s->debug_name); // ud gc_cb name
1311 have_gc_cb = TRUE; 1311 have_gc_cb = TRUE;
1312 } 1312 }
1313 else 1313 else
1314 { 1314 {
1315 lua_pop( L, 2); // ud 1315 lua_pop( L, 2); // ud
1316 } 1316 }
1317 1317
1318 // We can read 's->status' without locks, but not wait for it 1318 // We can read 's->status' without locks, but not wait for it
1319 // test KILLED state first, as it doesn't need to enter the selfdestruct chain 1319 // test KILLED state first, as it doesn't need to enter the selfdestruct chain
1320 if( s->mstatus == KILLED) 1320 if( s->mstatus == KILLED)
1321 { 1321 {
1322 // Make sure a kill has proceeded, before cleaning up the data structure. 1322 // Make sure a kill has proceeded, before cleaning up the data structure.
1323 // 1323 //
1324 // NO lua_close() in this case because we don't know where execution of the state was interrupted 1324 // NO lua_close() in this case because we don't know where execution of the state was interrupted
1325 DEBUGSPEW_CODE( fprintf( stderr, "** Joining with a killed thread (needs testing) **")); 1325 DEBUGSPEW_CODE( fprintf( stderr, "** Joining with a killed thread (needs testing) **"));
1326 // make sure the thread is no longer running, just like thread_join() 1326 // make sure the thread is no longer running, just like thread_join()
1327 if(! THREAD_ISNULL( s->thread)) 1327 if(! THREAD_ISNULL( s->thread))
1328 { 1328 {
1329 THREAD_WAIT( &s->thread, -1, &s->done_signal, &s->done_lock, &s->status); 1329 THREAD_WAIT( &s->thread, -1, &s->done_signal, &s->done_lock, &s->status);
1330 } 1330 }
1331 if( s->status >= DONE && s->L) 1331 if( s->status >= DONE && s->L)
1332 { 1332 {
1333 // we know the thread was killed while the Lua VM was not doing anything: we should be able to close it without crashing 1333 // we know the thread was killed while the Lua VM was not doing anything: we should be able to close it without crashing
1334 // now, thread_cancel() will not forcefully kill a lane with s->status >= DONE, so I am not sure it can ever happen 1334 // now, thread_cancel() will not forcefully kill a lane with s->status >= DONE, so I am not sure it can ever happen
1335 lua_close( s->L); 1335 lua_close( s->L);
1336 s->L = 0; 1336 s->L = 0;
1337 // just in case, but s will be freed soon so... 1337 // just in case, but s will be freed soon so...
1338 s->debug_name = "<gc>"; 1338 s->debug_name = "<gc>";
1339 } 1339 }
1340 DEBUGSPEW_CODE( fprintf( stderr, "** Joined ok **")); 1340 DEBUGSPEW_CODE( fprintf( stderr, "** Joined ok **"));
1341 } 1341 }
1342 else if( s->status < DONE) 1342 else if( s->status < DONE)
1343 { 1343 {
1344 // still running: will have to be cleaned up later 1344 // still running: will have to be cleaned up later
1345 selfdestruct_add( s); 1345 selfdestruct_add( s);
1346 assert( s->selfdestruct_next); 1346 assert( s->selfdestruct_next);
1347 if( have_gc_cb) 1347 if( have_gc_cb)
1348 { 1348 {
1349 lua_pushliteral( L, "selfdestruct"); // ud gc_cb name status 1349 lua_pushliteral( L, "selfdestruct"); // ud gc_cb name status
1350 lua_call( L, 2, 0); // ud 1350 lua_call( L, 2, 0); // ud
1351 } 1351 }
1352 return 0; 1352 return 0;
1353 } 1353 }
1354 else if( s->L) 1354 else if( s->L)
1355 { 1355 {
1356 // no longer accessing the Lua VM: we can close right now 1356 // no longer accessing the Lua VM: we can close right now
1357 lua_close( s->L); 1357 lua_close( s->L);
1358 s->L = 0; 1358 s->L = 0;
1359 // just in case, but s will be freed soon so... 1359 // just in case, but s will be freed soon so...
1360 s->debug_name = "<gc>"; 1360 s->debug_name = "<gc>";
1361 } 1361 }
1362 1362
1363 // Clean up after a (finished) thread 1363 // Clean up after a (finished) thread
1364 lane_cleanup( s); 1364 lane_cleanup( s);
1365 1365
1366 // do this after lane cleanup in case the callback triggers an error 1366 // do this after lane cleanup in case the callback triggers an error
1367 if( have_gc_cb) 1367 if( have_gc_cb)
1368 { 1368 {
1369 lua_pushliteral( L, "closed"); // ud gc_cb name status 1369 lua_pushliteral( L, "closed"); // ud gc_cb name status
1370 lua_call( L, 2, 0); // ud 1370 lua_call( L, 2, 0); // ud
1371 } 1371 }
1372 return 0; 1372 return 0;
1373} 1373}
1374 1374
1375//--- 1375//---
@@ -1384,25 +1384,25 @@ LUAG_FUNC( thread_gc)
1384// 1384//
1385static char const * thread_status_string( Lane* s) 1385static char const * thread_status_string( Lane* s)
1386{ 1386{
1387 enum e_status st = s->status; // read just once (volatile) 1387 enum e_status st = s->status; // read just once (volatile)
1388 char const* str = 1388 char const* str =
1389 (s->mstatus == KILLED) ? "killed" : // new to v3.3.0! 1389 (s->mstatus == KILLED) ? "killed" : // new to v3.3.0!
1390 (st == PENDING) ? "pending" : 1390 (st == PENDING) ? "pending" :
1391 (st == RUNNING) ? "running" : // like in 'co.status()' 1391 (st == RUNNING) ? "running" : // like in 'co.status()'
1392 (st == WAITING) ? "waiting" : 1392 (st == WAITING) ? "waiting" :
1393 (st == DONE) ? "done" : 1393 (st == DONE) ? "done" :
1394 (st == ERROR_ST) ? "error" : 1394 (st == ERROR_ST) ? "error" :
1395 (st == CANCELLED) ? "cancelled" : NULL; 1395 (st == CANCELLED) ? "cancelled" : NULL;
1396 return str; 1396 return str;
1397} 1397}
1398 1398
1399int push_thread_status( lua_State* L, Lane* s) 1399int push_thread_status( lua_State* L, Lane* s)
1400{ 1400{
1401 char const* const str = thread_status_string( s); 1401 char const* const str = thread_status_string( s);
1402 ASSERT_L( str); 1402 ASSERT_L( str);
1403 1403
1404 lua_pushstring( L, str); 1404 lua_pushstring( L, str);
1405 return 1; 1405 return 1;
1406} 1406}
1407 1407
1408 1408
@@ -1416,77 +1416,77 @@ int push_thread_status( lua_State* L, Lane* s)
1416// 1416//
1417LUAG_FUNC( thread_join) 1417LUAG_FUNC( thread_join)
1418{ 1418{
1419 Lane* const s = lua_toLane( L, 1); 1419 Lane* const s = lua_toLane( L, 1);
1420 double wait_secs = luaL_optnumber( L, 2, -1.0); 1420 double wait_secs = luaL_optnumber( L, 2, -1.0);
1421 lua_State* L2 = s->L; 1421 lua_State* L2 = s->L;
1422 int ret; 1422 int ret;
1423 bool_t done = THREAD_ISNULL( s->thread) || THREAD_WAIT( &s->thread, wait_secs, &s->done_signal, &s->done_lock, &s->status); 1423 bool_t done = THREAD_ISNULL( s->thread) || THREAD_WAIT( &s->thread, wait_secs, &s->done_signal, &s->done_lock, &s->status);
1424 if( !done || !L2) 1424 if( !done || !L2)
1425 { 1425 {
1426 STACK_GROW( L, 2); 1426 STACK_GROW( L, 2);
1427 lua_pushnil( L); 1427 lua_pushnil( L);
1428 lua_pushliteral( L, "timeout"); 1428 lua_pushliteral( L, "timeout");
1429 return 2; 1429 return 2;
1430 } 1430 }
1431 1431
1432 STACK_CHECK( L, 0); 1432 STACK_CHECK( L, 0);
1433 // Thread is DONE/ERROR_ST/CANCELLED; all ours now 1433 // Thread is DONE/ERROR_ST/CANCELLED; all ours now
1434 1434
1435 if( s->mstatus == KILLED) // OS thread was killed if thread_cancel was forced 1435 if( s->mstatus == KILLED) // OS thread was killed if thread_cancel was forced
1436 { 1436 {
1437 // in that case, even if the thread was killed while DONE/ERROR_ST/CANCELLED, ignore regular return values 1437 // in that case, even if the thread was killed while DONE/ERROR_ST/CANCELLED, ignore regular return values
1438 STACK_GROW( L, 2); 1438 STACK_GROW( L, 2);
1439 lua_pushnil( L); 1439 lua_pushnil( L);
1440 lua_pushliteral( L, "killed"); 1440 lua_pushliteral( L, "killed");
1441 ret = 2; 1441 ret = 2;
1442 } 1442 }
1443 else 1443 else
1444 { 1444 {
1445 Universe* U = universe_get( L); 1445 Universe* U = universe_get( L);
1446 // debug_name is a pointer to string possibly interned in the lane's state, that no longer exists when the state is closed 1446 // debug_name is a pointer to string possibly interned in the lane's state, that no longer exists when the state is closed
1447 // so store it in the userdata uservalue at a key that can't possibly collide 1447 // so store it in the userdata uservalue at a key that can't possibly collide
1448 securize_debug_threadname( L, s); 1448 securize_debug_threadname( L, s);
1449 switch( s->status) 1449 switch( s->status)
1450 { 1450 {
1451 case DONE: 1451 case DONE:
1452 { 1452 {
1453 uint_t n = lua_gettop( L2); // whole L2 stack 1453 uint_t n = lua_gettop( L2); // whole L2 stack
1454 if( (n > 0) && (luaG_inter_move( U, L2, L, n, eLM_LaneBody) != 0)) 1454 if( (n > 0) && (luaG_inter_move( U, L2, L, n, eLM_LaneBody) != 0))
1455 { 1455 {
1456 return luaL_error( L, "tried to copy unsupported types"); 1456 return luaL_error( L, "tried to copy unsupported types");
1457 } 1457 }
1458 ret = n; 1458 ret = n;
1459 } 1459 }
1460 break; 1460 break;
1461 1461
1462 case ERROR_ST: 1462 case ERROR_ST:
1463 { 1463 {
1464 int const n = lua_gettop( L2); 1464 int const n = lua_gettop( L2);
1465 STACK_GROW( L, 3); 1465 STACK_GROW( L, 3);
1466 lua_pushnil( L); 1466 lua_pushnil( L);
1467 // 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 ... 1467 // 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 ...
1468 if( luaG_inter_move( U, L2, L, n, eLM_LaneBody) != 0) // nil "err" [trace] 1468 if( luaG_inter_move( U, L2, L, n, eLM_LaneBody) != 0) // nil "err" [trace]
1469 { 1469 {
1470 return luaL_error( L, "tried to copy unsupported types: %s", lua_tostring( L, -n)); 1470 return luaL_error( L, "tried to copy unsupported types: %s", lua_tostring( L, -n));
1471 } 1471 }
1472 ret = 1 + n; 1472 ret = 1 + n;
1473 } 1473 }
1474 break; 1474 break;
1475 1475
1476 case CANCELLED: 1476 case CANCELLED:
1477 ret = 0; 1477 ret = 0;
1478 break; 1478 break;
1479 1479
1480 default: 1480 default:
1481 DEBUGSPEW_CODE( fprintf( stderr, "Status: %d\n", s->status)); 1481 DEBUGSPEW_CODE( fprintf( stderr, "Status: %d\n", s->status));
1482 ASSERT_L( FALSE); 1482 ASSERT_L( FALSE);
1483 ret = 0; 1483 ret = 0;
1484 } 1484 }
1485 lua_close( L2); 1485 lua_close( L2);
1486 } 1486 }
1487 s->L = 0; 1487 s->L = 0;
1488 STACK_END( L, ret); 1488 STACK_END( L, ret);
1489 return ret; 1489 return ret;
1490} 1490}
1491 1491
1492 1492
@@ -1500,150 +1500,150 @@ LUAG_FUNC( thread_join)
1500// Else raise an error 1500// Else raise an error
1501LUAG_FUNC( thread_index) 1501LUAG_FUNC( thread_index)
1502{ 1502{
1503 int const UD = 1; 1503 int const UD = 1;
1504 int const KEY = 2; 1504 int const KEY = 2;
1505 int const USR = 3; 1505 int const USR = 3;
1506 Lane* const s = lua_toLane( L, UD); 1506 Lane* const s = lua_toLane( L, UD);
1507 ASSERT_L( lua_gettop( L) == 2); 1507 ASSERT_L( lua_gettop( L) == 2);
1508 1508
1509 STACK_GROW( L, 8); // up to 8 positions are needed in case of error propagation 1509 STACK_GROW( L, 8); // up to 8 positions are needed in case of error propagation
1510 1510
1511 // If key is numeric, wait until the thread returns and populate the environment with the return values 1511 // If key is numeric, wait until the thread returns and populate the environment with the return values
1512 if( lua_type( L, KEY) == LUA_TNUMBER) 1512 if( lua_type( L, KEY) == LUA_TNUMBER)
1513 { 1513 {
1514 // first, check that we don't already have an environment that holds the requested value 1514 // first, check that we don't already have an environment that holds the requested value
1515 { 1515 {
1516 // If key is found in the uservalue, return it 1516 // If key is found in the uservalue, return it
1517 lua_getiuservalue( L, UD, 1); 1517 lua_getiuservalue( L, UD, 1);
1518 lua_pushvalue( L, KEY); 1518 lua_pushvalue( L, KEY);
1519 lua_rawget( L, USR); 1519 lua_rawget( L, USR);
1520 if( !lua_isnil( L, -1)) 1520 if( !lua_isnil( L, -1))
1521 { 1521 {
1522 return 1; 1522 return 1;
1523 } 1523 }
1524 lua_pop( L, 1); 1524 lua_pop( L, 1);
1525 } 1525 }
1526 { 1526 {
1527 // check if we already fetched the values from the thread or not 1527 // check if we already fetched the values from the thread or not
1528 bool_t fetched; 1528 bool_t fetched;
1529 lua_Integer key = lua_tointeger( L, KEY); 1529 lua_Integer key = lua_tointeger( L, KEY);
1530 lua_pushinteger( L, 0); 1530 lua_pushinteger( L, 0);
1531 lua_rawget( L, USR); 1531 lua_rawget( L, USR);
1532 fetched = !lua_isnil( L, -1); 1532 fetched = !lua_isnil( L, -1);
1533 lua_pop( L, 1); // back to our 2 args + uservalue on the stack 1533 lua_pop( L, 1); // back to our 2 args + uservalue on the stack
1534 if( !fetched) 1534 if( !fetched)
1535 { 1535 {
1536 lua_pushinteger( L, 0); 1536 lua_pushinteger( L, 0);
1537 lua_pushboolean( L, 1); 1537 lua_pushboolean( L, 1);
1538 lua_rawset( L, USR); 1538 lua_rawset( L, USR);
1539 // wait until thread has completed 1539 // wait until thread has completed
1540 lua_pushcfunction( L, LG_thread_join); 1540 lua_pushcfunction( L, LG_thread_join);
1541 lua_pushvalue( L, UD); 1541 lua_pushvalue( L, UD);
1542 lua_call( L, 1, LUA_MULTRET); // all return values are on the stack, at slots 4+ 1542 lua_call( L, 1, LUA_MULTRET); // all return values are on the stack, at slots 4+
1543 switch( s->status) 1543 switch( s->status)
1544 { 1544 {
1545 default: 1545 default:
1546 if( s->mstatus != KILLED) 1546 if( s->mstatus != KILLED)
1547 { 1547 {
1548 // this is an internal error, we probably never get here 1548 // this is an internal error, we probably never get here
1549 lua_settop( L, 0); 1549 lua_settop( L, 0);
1550 lua_pushliteral( L, "Unexpected status: "); 1550 lua_pushliteral( L, "Unexpected status: ");
1551 lua_pushstring( L, thread_status_string( s)); 1551 lua_pushstring( L, thread_status_string( s));
1552 lua_concat( L, 2); 1552 lua_concat( L, 2);
1553 lua_error( L); 1553 lua_error( L);
1554 break; 1554 break;
1555 } 1555 }
1556 // fall through if we are killed, as we got nil, "killed" on the stack 1556 // fall through if we are killed, as we got nil, "killed" on the stack
1557 1557
1558 case DONE: // got regular return values 1558 case DONE: // got regular return values
1559 { 1559 {
1560 int i, nvalues = lua_gettop( L) - 3; 1560 int i, nvalues = lua_gettop( L) - 3;
1561 for( i = nvalues; i > 0; -- i) 1561 for( i = nvalues; i > 0; -- i)
1562 { 1562 {
1563 // pop the last element of the stack, to store it in the uservalue at its proper index 1563 // pop the last element of the stack, to store it in the uservalue at its proper index
1564 lua_rawseti( L, USR, i); 1564 lua_rawseti( L, USR, i);
1565 } 1565 }
1566 } 1566 }
1567 break; 1567 break;
1568 1568
1569 case ERROR_ST: // got 3 values: nil, errstring, callstack table 1569 case ERROR_ST: // got 3 values: nil, errstring, callstack table
1570 // me[-2] could carry the stack table, but even 1570 // me[-2] could carry the stack table, but even
1571 // me[-1] is rather unnecessary (and undocumented); 1571 // me[-1] is rather unnecessary (and undocumented);
1572 // use ':join()' instead. --AKa 22-Jan-2009 1572 // use ':join()' instead. --AKa 22-Jan-2009
1573 ASSERT_L( lua_isnil( L, 4) && !lua_isnil( L, 5) && lua_istable( L, 6)); 1573 ASSERT_L( lua_isnil( L, 4) && !lua_isnil( L, 5) && lua_istable( L, 6));
1574 // store errstring at key -1 1574 // store errstring at key -1
1575 lua_pushnumber( L, -1); 1575 lua_pushnumber( L, -1);
1576 lua_pushvalue( L, 5); 1576 lua_pushvalue( L, 5);
1577 lua_rawset( L, USR); 1577 lua_rawset( L, USR);
1578 break; 1578 break;
1579 1579
1580 case CANCELLED: 1580 case CANCELLED:
1581 // do nothing 1581 // do nothing
1582 break; 1582 break;
1583 } 1583 }
1584 } 1584 }
1585 lua_settop( L, 3); // UD KEY ENV 1585 lua_settop( L, 3); // UD KEY ENV
1586 if( key != -1) 1586 if( key != -1)
1587 { 1587 {
1588 lua_pushnumber( L, -1); // UD KEY ENV -1 1588 lua_pushnumber( L, -1); // UD KEY ENV -1
1589 lua_rawget( L, USR); // UD KEY ENV "error" 1589 lua_rawget( L, USR); // UD KEY ENV "error"
1590 if( !lua_isnil( L, -1)) // an error was stored 1590 if( !lua_isnil( L, -1)) // an error was stored
1591 { 1591 {
1592 // Note: Lua 5.1 interpreter is not prepared to show 1592 // Note: Lua 5.1 interpreter is not prepared to show
1593 // non-string errors, so we use 'tostring()' here 1593 // non-string errors, so we use 'tostring()' here
1594 // to get meaningful output. --AKa 22-Jan-2009 1594 // to get meaningful output. --AKa 22-Jan-2009
1595 // 1595 //
1596 // Also, the stack dump we get is no good; it only 1596 // Also, the stack dump we get is no good; it only
1597 // lists our internal Lanes functions. There seems 1597 // lists our internal Lanes functions. There seems
1598 // to be no way to switch it off, though. 1598 // to be no way to switch it off, though.
1599 // 1599 //
1600 // Level 3 should show the line where 'h[x]' was read 1600 // Level 3 should show the line where 'h[x]' was read
1601 // but this only seems to work for string messages 1601 // but this only seems to work for string messages
1602 // (Lua 5.1.4). No idea, why. --AKa 22-Jan-2009 1602 // (Lua 5.1.4). No idea, why. --AKa 22-Jan-2009
1603 lua_getmetatable( L, UD); // UD KEY ENV "error" mt 1603 lua_getmetatable( L, UD); // UD KEY ENV "error" mt
1604 lua_getfield( L, -1, "cached_error"); // UD KEY ENV "error" mt error() 1604 lua_getfield( L, -1, "cached_error"); // UD KEY ENV "error" mt error()
1605 lua_getfield( L, -2, "cached_tostring"); // UD KEY ENV "error" mt error() tostring() 1605 lua_getfield( L, -2, "cached_tostring"); // UD KEY ENV "error" mt error() tostring()
1606 lua_pushvalue( L, 4); // UD KEY ENV "error" mt error() tostring() "error" 1606 lua_pushvalue( L, 4); // UD KEY ENV "error" mt error() tostring() "error"
1607 lua_call( L, 1, 1); // tostring( errstring) -- just in case // UD KEY ENV "error" mt error() "error" 1607 lua_call( L, 1, 1); // tostring( errstring) -- just in case // UD KEY ENV "error" mt error() "error"
1608 lua_pushinteger( L, 3); // UD KEY ENV "error" mt error() "error" 3 1608 lua_pushinteger( L, 3); // UD KEY ENV "error" mt error() "error" 3
1609 lua_call( L, 2, 0); // error( tostring( errstring), 3) // UD KEY ENV "error" mt 1609 lua_call( L, 2, 0); // error( tostring( errstring), 3) // UD KEY ENV "error" mt
1610 } 1610 }
1611 else 1611 else
1612 { 1612 {
1613 lua_pop( L, 1); // back to our 3 arguments on the stack 1613 lua_pop( L, 1); // back to our 3 arguments on the stack
1614 } 1614 }
1615 } 1615 }
1616 lua_rawgeti( L, USR, (int)key); 1616 lua_rawgeti( L, USR, (int)key);
1617 } 1617 }
1618 return 1; 1618 return 1;
1619 } 1619 }
1620 if( lua_type( L, KEY) == LUA_TSTRING) 1620 if( lua_type( L, KEY) == LUA_TSTRING)
1621 { 1621 {
1622 char const * const keystr = lua_tostring( L, KEY); 1622 char const * const keystr = lua_tostring( L, KEY);
1623 lua_settop( L, 2); // keep only our original arguments on the stack 1623 lua_settop( L, 2); // keep only our original arguments on the stack
1624 if( strcmp( keystr, "status") == 0) 1624 if( strcmp( keystr, "status") == 0)
1625 { 1625 {
1626 return push_thread_status( L, s); // push the string representing the status 1626 return push_thread_status( L, s); // push the string representing the status
1627 } 1627 }
1628 // return UD.metatable[key] 1628 // return UD.metatable[key]
1629 lua_getmetatable( L, UD); // UD KEY mt 1629 lua_getmetatable( L, UD); // UD KEY mt
1630 lua_replace( L, -3); // mt KEY 1630 lua_replace( L, -3); // mt KEY
1631 lua_rawget( L, -2); // mt value 1631 lua_rawget( L, -2); // mt value
1632 // only "cancel" and "join" are registered as functions, any other string will raise an error 1632 // only "cancel" and "join" are registered as functions, any other string will raise an error
1633 if( lua_iscfunction( L, -1)) 1633 if( lua_iscfunction( L, -1))
1634 { 1634 {
1635 return 1; 1635 return 1;
1636 } 1636 }
1637 return luaL_error( L, "can't index a lane with '%s'", keystr); 1637 return luaL_error( L, "can't index a lane with '%s'", keystr);
1638 } 1638 }
1639 // unknown key 1639 // unknown key
1640 lua_getmetatable( L, UD); 1640 lua_getmetatable( L, UD);
1641 lua_getfield( L, -1, "cached_error"); 1641 lua_getfield( L, -1, "cached_error");
1642 lua_pushliteral( L, "Unknown key: "); 1642 lua_pushliteral( L, "Unknown key: ");
1643 lua_pushvalue( L, KEY); 1643 lua_pushvalue( L, KEY);
1644 lua_concat( L, 2); 1644 lua_concat( L, 2);
1645 lua_call( L, 1, 0); // error( "Unknown key: " .. key) -> doesn't return 1645 lua_call( L, 1, 0); // error( "Unknown key: " .. key) -> doesn't return
1646 return 0; 1646 return 0;
1647} 1647}
1648 1648
1649#if HAVE_LANE_TRACKING 1649#if HAVE_LANE_TRACKING
@@ -1771,36 +1771,36 @@ static const struct luaL_Reg lanes_functions [] = {
1771static void init_once_LOCKED( void) 1771static void init_once_LOCKED( void)
1772{ 1772{
1773#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 1773#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
1774 now_secs(); // initialize 'now_secs()' internal offset 1774 now_secs(); // initialize 'now_secs()' internal offset
1775#endif 1775#endif
1776 1776
1777#if (defined PLATFORM_OSX) && (defined _UTILBINDTHREADTOCPU) 1777#if (defined PLATFORM_OSX) && (defined _UTILBINDTHREADTOCPU)
1778 chudInitialize(); 1778 chudInitialize();
1779#endif 1779#endif
1780 1780
1781 //--- 1781 //---
1782 // Linux needs SCHED_RR to change thread priorities, and that is only 1782 // Linux needs SCHED_RR to change thread priorities, and that is only
1783 // allowed for sudo'ers. SCHED_OTHER (default) has no priorities. 1783 // allowed for sudo'ers. SCHED_OTHER (default) has no priorities.
1784 // SCHED_OTHER threads are always lower priority than SCHED_RR. 1784 // SCHED_OTHER threads are always lower priority than SCHED_RR.
1785 // 1785 //
1786 // ^-- those apply to 2.6 kernel. IF **wishful thinking** these 1786 // ^-- those apply to 2.6 kernel. IF **wishful thinking** these
1787 // constraints will change in the future, non-sudo priorities can 1787 // constraints will change in the future, non-sudo priorities can
1788 // be enabled also for Linux. 1788 // be enabled also for Linux.
1789 // 1789 //
1790#ifdef PLATFORM_LINUX 1790#ifdef PLATFORM_LINUX
1791 sudo = (geteuid() == 0); // we are root? 1791 sudo = (geteuid() == 0); // we are root?
1792 1792
1793 // If lower priorities (-2..-1) are wanted, we need to lift the main 1793 // If lower priorities (-2..-1) are wanted, we need to lift the main
1794 // thread to SCHED_RR and 50 (medium) level. Otherwise, we're always below 1794 // thread to SCHED_RR and 50 (medium) level. Otherwise, we're always below
1795 // the launched threads (even -2). 1795 // the launched threads (even -2).
1796 // 1796 //
1797#ifdef LINUX_SCHED_RR 1797#ifdef LINUX_SCHED_RR
1798 if( sudo) 1798 if( sudo)
1799 { 1799 {
1800 struct sched_param sp; 1800 struct sched_param sp;
1801 sp.sched_priority = _PRIO_0; 1801 sp.sched_priority = _PRIO_0;
1802 PT_CALL( pthread_setschedparam( pthread_self(), SCHED_RR, &sp)); 1802 PT_CALL( pthread_setschedparam( pthread_self(), SCHED_RR, &sp));
1803 } 1803 }
1804#endif // LINUX_SCHED_RR 1804#endif // LINUX_SCHED_RR
1805#endif // PLATFORM_LINUX 1805#endif // PLATFORM_LINUX
1806} 1806}
@@ -1812,210 +1812,210 @@ static volatile long s_initCount = 0;
1812// param 1: settings table 1812// param 1: settings table
1813LUAG_FUNC( configure) 1813LUAG_FUNC( configure)
1814{ 1814{
1815 Universe* U = universe_get( L); 1815 Universe* U = universe_get( L);
1816 bool_t const from_master_state = (U == NULL); 1816 bool_t const from_master_state = (U == NULL);
1817 char const* name = luaL_checkstring( L, lua_upvalueindex( 1)); 1817 char const* name = luaL_checkstring( L, lua_upvalueindex( 1));
1818 _ASSERT_L( L, lua_type( L, 1) == LUA_TTABLE); 1818 _ASSERT_L( L, lua_type( L, 1) == LUA_TTABLE);
1819 1819
1820 /* 1820 /*
1821 ** Making one-time initializations. 1821 ** Making one-time initializations.
1822 ** 1822 **
1823 ** When the host application is single-threaded (and all threading happens via Lanes) 1823 ** When the host application is single-threaded (and all threading happens via Lanes)
1824 ** there is no problem. But if the host is multithreaded, we need to lock around the 1824 ** there is no problem. But if the host is multithreaded, we need to lock around the
1825 ** initializations. 1825 ** initializations.
1826 */ 1826 */
1827#if THREADAPI == THREADAPI_WINDOWS 1827#if THREADAPI == THREADAPI_WINDOWS
1828 { 1828 {
1829 static volatile int /*bool*/ go_ahead; // = 0 1829 static volatile int /*bool*/ go_ahead; // = 0
1830 if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0) 1830 if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0)
1831 { 1831 {
1832 init_once_LOCKED(); 1832 init_once_LOCKED();
1833 go_ahead = 1; // let others pass 1833 go_ahead = 1; // let others pass
1834 } 1834 }
1835 else 1835 else
1836 { 1836 {
1837 while( !go_ahead) { Sleep(1); } // changes threads 1837 while( !go_ahead) { Sleep(1); } // changes threads
1838 } 1838 }
1839 } 1839 }
1840#else // THREADAPI == THREADAPI_PTHREAD 1840#else // THREADAPI == THREADAPI_PTHREAD
1841 if( s_initCount == 0) 1841 if( s_initCount == 0)
1842 { 1842 {
1843 static pthread_mutex_t my_lock = PTHREAD_MUTEX_INITIALIZER; 1843 static pthread_mutex_t my_lock = PTHREAD_MUTEX_INITIALIZER;
1844 pthread_mutex_lock( &my_lock); 1844 pthread_mutex_lock( &my_lock);
1845 { 1845 {
1846 // Recheck now that we're within the lock 1846 // Recheck now that we're within the lock
1847 // 1847 //
1848 if( s_initCount == 0) 1848 if( s_initCount == 0)
1849 { 1849 {
1850 init_once_LOCKED(); 1850 init_once_LOCKED();
1851 s_initCount = 1; 1851 s_initCount = 1;
1852 } 1852 }
1853 } 1853 }
1854 pthread_mutex_unlock( &my_lock); 1854 pthread_mutex_unlock( &my_lock);
1855 } 1855 }
1856#endif // THREADAPI == THREADAPI_PTHREAD 1856#endif // THREADAPI == THREADAPI_PTHREAD
1857 1857
1858 STACK_GROW( L, 4); 1858 STACK_GROW( L, 4);
1859 STACK_CHECK_ABS( L, 1); // settings 1859 STACK_CHECK_ABS( L, 1); // settings
1860 1860
1861 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() BEGIN\n" INDENT_END, L)); 1861 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() BEGIN\n" INDENT_END, L));
1862 DEBUGSPEW_CODE( if( U) ++ U->debugspew_indent_depth); 1862 DEBUGSPEW_CODE( if( U) ++ U->debugspew_indent_depth);
1863 1863
1864 if( U == NULL) 1864 if( U == NULL)
1865 { 1865 {
1866 U = universe_create( L); // settings universe 1866 U = universe_create( L); // settings universe
1867 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); 1867 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
1868 lua_newtable( L); // settings universe mt 1868 lua_newtable( L); // settings universe mt
1869 lua_getfield( L, 1, "shutdown_timeout"); // settings universe mt shutdown_timeout 1869 lua_getfield( L, 1, "shutdown_timeout"); // settings universe mt shutdown_timeout
1870 lua_pushcclosure( L, selfdestruct_gc, 1); // settings universe mt selfdestruct_gc 1870 lua_pushcclosure( L, selfdestruct_gc, 1); // settings universe mt selfdestruct_gc
1871 lua_setfield( L, -2, "__gc"); // settings universe mt 1871 lua_setfield( L, -2, "__gc"); // settings universe mt
1872 lua_setmetatable( L, -2); // settings universe 1872 lua_setmetatable( L, -2); // settings universe
1873 lua_pop( L, 1); // settings 1873 lua_pop( L, 1); // settings
1874 lua_getfield( L, 1, "verbose_errors"); // settings verbose_errors 1874 lua_getfield( L, 1, "verbose_errors"); // settings verbose_errors
1875 U->verboseErrors = lua_toboolean( L, -1); 1875 U->verboseErrors = lua_toboolean( L, -1);
1876 lua_pop( L, 1); // settings 1876 lua_pop( L, 1); // settings
1877 lua_getfield( L, 1, "demote_full_userdata"); // settings demote_full_userdata 1877 lua_getfield( L, 1, "demote_full_userdata"); // settings demote_full_userdata
1878 U->demoteFullUserdata = lua_toboolean( L, -1); 1878 U->demoteFullUserdata = lua_toboolean( L, -1);
1879 lua_pop( L, 1); // settings 1879 lua_pop( L, 1); // settings
1880#if HAVE_LANE_TRACKING 1880#if HAVE_LANE_TRACKING
1881 MUTEX_INIT( &U->tracking_cs); 1881 MUTEX_INIT( &U->tracking_cs);
1882 lua_getfield( L, 1, "track_lanes"); // settings track_lanes 1882 lua_getfield( L, 1, "track_lanes"); // settings track_lanes
1883 U->tracking_first = lua_toboolean( L, -1) ? TRACKING_END : NULL; 1883 U->tracking_first = lua_toboolean( L, -1) ? TRACKING_END : NULL;
1884 lua_pop( L, 1); // settings 1884 lua_pop( L, 1); // settings
1885#endif // HAVE_LANE_TRACKING 1885#endif // HAVE_LANE_TRACKING
1886 // Linked chains handling 1886 // Linked chains handling
1887 MUTEX_INIT( &U->selfdestruct_cs); 1887 MUTEX_INIT( &U->selfdestruct_cs);
1888 MUTEX_RECURSIVE_INIT( &U->require_cs); 1888 MUTEX_RECURSIVE_INIT( &U->require_cs);
1889 // Locks for 'tools.c' inc/dec counters 1889 // Locks for 'tools.c' inc/dec counters
1890 MUTEX_INIT( &U->deep_lock); 1890 MUTEX_INIT( &U->deep_lock);
1891 MUTEX_INIT( &U->mtid_lock); 1891 MUTEX_INIT( &U->mtid_lock);
1892 U->selfdestruct_first = SELFDESTRUCT_END; 1892 U->selfdestruct_first = SELFDESTRUCT_END;
1893 initialize_allocator_function( U, L); 1893 initialize_allocator_function( U, L);
1894 initialize_on_state_create( U, L); 1894 initialize_on_state_create( U, L);
1895 init_keepers( U, L); 1895 init_keepers( U, L);
1896 STACK_MID( L, 1); 1896 STACK_MID( L, 1);
1897 1897
1898 // Initialize 'timer_deep'; a common Linda object shared by all states 1898 // Initialize 'timer_deep'; a common Linda object shared by all states
1899 lua_pushcfunction( L, LG_linda); // settings lanes.linda 1899 lua_pushcfunction( L, LG_linda); // settings lanes.linda
1900 lua_pushliteral( L, "lanes-timer"); // settings lanes.linda "lanes-timer" 1900 lua_pushliteral( L, "lanes-timer"); // settings lanes.linda "lanes-timer"
1901 lua_call( L, 1, 1); // settings linda 1901 lua_call( L, 1, 1); // settings linda
1902 STACK_MID( L, 2); 1902 STACK_MID( L, 2);
1903 1903
1904 // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer 1904 // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer
1905 U->timer_deep = *(DeepPrelude**) lua_touserdata( L, -1); 1905 U->timer_deep = *(DeepPrelude**) lua_touserdata( L, -1);
1906 // increment refcount so that this linda remains alive as long as the universe exists. 1906 // increment refcount so that this linda remains alive as long as the universe exists.
1907 ++ U->timer_deep->refcount; 1907 ++ U->timer_deep->refcount;
1908 lua_pop( L, 1); // settings 1908 lua_pop( L, 1); // settings
1909 } 1909 }
1910 STACK_MID( L, 1); 1910 STACK_MID( L, 1);
1911 1911
1912 // Serialize calls to 'require' from now on, also in the primary state 1912 // Serialize calls to 'require' from now on, also in the primary state
1913 serialize_require( DEBUGSPEW_PARAM_COMMA( U) L); 1913 serialize_require( DEBUGSPEW_PARAM_COMMA( U) L);
1914 1914
1915 // Retrieve main module interface table 1915 // Retrieve main module interface table
1916 lua_pushvalue( L, lua_upvalueindex( 2)); // settings M 1916 lua_pushvalue( L, lua_upvalueindex( 2)); // settings M
1917 // remove configure() (this function) from the module interface 1917 // remove configure() (this function) from the module interface
1918 lua_pushnil( L); // settings M nil 1918 lua_pushnil( L); // settings M nil
1919 lua_setfield( L, -2, "configure"); // settings M 1919 lua_setfield( L, -2, "configure"); // settings M
1920 // add functions to the module's table 1920 // add functions to the module's table
1921 luaG_registerlibfuncs( L, lanes_functions); 1921 luaG_registerlibfuncs( L, lanes_functions);
1922#if HAVE_LANE_TRACKING 1922#if HAVE_LANE_TRACKING
1923 // register core.threads() only if settings say it should be available 1923 // register core.threads() only if settings say it should be available
1924 if( U->tracking_first != NULL) 1924 if( U->tracking_first != NULL)
1925 { 1925 {
1926 lua_pushcfunction( L, LG_threads); // settings M LG_threads() 1926 lua_pushcfunction( L, LG_threads); // settings M LG_threads()
1927 lua_setfield( L, -2, "threads"); // settings M 1927 lua_setfield( L, -2, "threads"); // settings M
1928 } 1928 }
1929#endif // HAVE_LANE_TRACKING 1929#endif // HAVE_LANE_TRACKING
1930 STACK_MID( L, 2); 1930 STACK_MID( L, 2);
1931 1931
1932 { 1932 {
1933 char const* errmsg; 1933 char const* errmsg;
1934 errmsg = push_deep_proxy( U, L, (DeepPrelude*) U->timer_deep, 0, eLM_LaneBody); // settings M timer_deep 1934 errmsg = push_deep_proxy( U, L, (DeepPrelude*) U->timer_deep, 0, eLM_LaneBody); // settings M timer_deep
1935 if( errmsg != NULL) 1935 if( errmsg != NULL)
1936 { 1936 {
1937 return luaL_error( L, errmsg); 1937 return luaL_error( L, errmsg);
1938 } 1938 }
1939 lua_setfield( L, -2, "timer_gateway"); // settings M 1939 lua_setfield( L, -2, "timer_gateway"); // settings M
1940 } 1940 }
1941 STACK_MID( L, 2); 1941 STACK_MID( L, 2);
1942 1942
1943 // prepare the metatable for threads 1943 // prepare the metatable for threads
1944 // contains keys: { __gc, __index, cached_error, cached_tostring, cancel, join, get_debug_threadname } 1944 // contains keys: { __gc, __index, cached_error, cached_tostring, cancel, join, get_debug_threadname }
1945 // 1945 //
1946 if( luaL_newmetatable( L, "Lane")) // settings M mt 1946 if( luaL_newmetatable( L, "Lane")) // settings M mt
1947 { 1947 {
1948 lua_pushcfunction( L, LG_thread_gc); // settings M mt LG_thread_gc 1948 lua_pushcfunction( L, LG_thread_gc); // settings M mt LG_thread_gc
1949 lua_setfield( L, -2, "__gc"); // settings M mt 1949 lua_setfield( L, -2, "__gc"); // settings M mt
1950 lua_pushcfunction( L, LG_thread_index); // settings M mt LG_thread_index 1950 lua_pushcfunction( L, LG_thread_index); // settings M mt LG_thread_index
1951 lua_setfield( L, -2, "__index"); // settings M mt 1951 lua_setfield( L, -2, "__index"); // settings M mt
1952 lua_getglobal( L, "error"); // settings M mt error 1952 lua_getglobal( L, "error"); // settings M mt error
1953 ASSERT_L( lua_isfunction( L, -1)); 1953 ASSERT_L( lua_isfunction( L, -1));
1954 lua_setfield( L, -2, "cached_error"); // settings M mt 1954 lua_setfield( L, -2, "cached_error"); // settings M mt
1955 lua_getglobal( L, "tostring"); // settings M mt tostring 1955 lua_getglobal( L, "tostring"); // settings M mt tostring
1956 ASSERT_L( lua_isfunction( L, -1)); 1956 ASSERT_L( lua_isfunction( L, -1));
1957 lua_setfield( L, -2, "cached_tostring"); // settings M mt 1957 lua_setfield( L, -2, "cached_tostring"); // settings M mt
1958 lua_pushcfunction( L, LG_thread_join); // settings M mt LG_thread_join 1958 lua_pushcfunction( L, LG_thread_join); // settings M mt LG_thread_join
1959 lua_setfield( L, -2, "join"); // settings M mt 1959 lua_setfield( L, -2, "join"); // settings M mt
1960 lua_pushcfunction( L, LG_get_debug_threadname); // settings M mt LG_get_debug_threadname 1960 lua_pushcfunction( L, LG_get_debug_threadname); // settings M mt LG_get_debug_threadname
1961 lua_setfield( L, -2, "get_debug_threadname"); // settings M mt 1961 lua_setfield( L, -2, "get_debug_threadname"); // settings M mt
1962 lua_pushcfunction( L, LG_thread_cancel); // settings M mt LG_thread_cancel 1962 lua_pushcfunction( L, LG_thread_cancel); // settings M mt LG_thread_cancel
1963 lua_setfield( L, -2, "cancel"); // settings M mt 1963 lua_setfield( L, -2, "cancel"); // settings M mt
1964 lua_pushliteral( L, "Lane"); // settings M mt "Lane" 1964 lua_pushliteral( L, "Lane"); // settings M mt "Lane"
1965 lua_setfield( L, -2, "__metatable"); // settings M mt 1965 lua_setfield( L, -2, "__metatable"); // settings M mt
1966 } 1966 }
1967 1967
1968 lua_pushcclosure( L, LG_lane_new, 1); // settings M lane_new 1968 lua_pushcclosure( L, LG_lane_new, 1); // settings M lane_new
1969 lua_setfield( L, -2, "lane_new"); // settings M 1969 lua_setfield( L, -2, "lane_new"); // settings M
1970 1970
1971 // we can't register 'lanes.require' normally because we want to create an upvalued closure 1971 // we can't register 'lanes.require' normally because we want to create an upvalued closure
1972 lua_getglobal( L, "require"); // settings M require 1972 lua_getglobal( L, "require"); // settings M require
1973 lua_pushcclosure( L, LG_require, 1); // settings M lanes.require 1973 lua_pushcclosure( L, LG_require, 1); // settings M lanes.require
1974 lua_setfield( L, -2, "require"); // settings M 1974 lua_setfield( L, -2, "require"); // settings M
1975 1975
1976 lua_pushfstring( 1976 lua_pushfstring(
1977 L, "%d.%d.%d" 1977 L, "%d.%d.%d"
1978 , LANES_VERSION_MAJOR, LANES_VERSION_MINOR, LANES_VERSION_PATCH 1978 , LANES_VERSION_MAJOR, LANES_VERSION_MINOR, LANES_VERSION_PATCH
1979 ); // settings M VERSION 1979 ); // settings M VERSION
1980 lua_setfield( L, -2, "version"); // settings M 1980 lua_setfield( L, -2, "version"); // settings M
1981 1981
1982 lua_pushinteger(L, THREAD_PRIO_MAX); // settings M THREAD_PRIO_MAX 1982 lua_pushinteger(L, THREAD_PRIO_MAX); // settings M THREAD_PRIO_MAX
1983 lua_setfield( L, -2, "max_prio"); // settings M 1983 lua_setfield( L, -2, "max_prio"); // settings M
1984 1984
1985 push_unique_key( L, CANCEL_ERROR); // settings M CANCEL_ERROR 1985 push_unique_key( L, CANCEL_ERROR); // settings M CANCEL_ERROR
1986 lua_setfield( L, -2, "cancel_error"); // settings M 1986 lua_setfield( L, -2, "cancel_error"); // settings M
1987 1987
1988 STACK_MID( L, 2); // reference stack contains only the function argument 'settings' 1988 STACK_MID( L, 2); // reference stack contains only the function argument 'settings'
1989 // we'll need this every time we transfer some C function from/to this state 1989 // we'll need this every time we transfer some C function from/to this state
1990 REGISTRY_SET( L, LOOKUP_REGKEY, lua_newtable( L)); 1990 REGISTRY_SET( L, LOOKUP_REGKEY, lua_newtable( L));
1991 STACK_MID( L, 2); 1991 STACK_MID( L, 2);
1992 1992
1993 // register all native functions found in that module in the transferable functions database 1993 // register all native functions found in that module in the transferable functions database
1994 // we process it before _G because we don't want to find the module when scanning _G (this would generate longer names) 1994 // we process it before _G because we don't want to find the module when scanning _G (this would generate longer names)
1995 // for example in package.loaded["lanes.core"].* 1995 // for example in package.loaded["lanes.core"].*
1996 populate_func_lookup_table( L, -1, name); 1996 populate_func_lookup_table( L, -1, name);
1997 STACK_MID( L, 2); 1997 STACK_MID( L, 2);
1998 1998
1999 // record all existing C/JIT-fast functions 1999 // record all existing C/JIT-fast functions
2000 // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack 2000 // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack
2001 if( from_master_state) 2001 if( from_master_state)
2002 { 2002 {
2003 // don't do this when called during the initialization of a new lane, 2003 // don't do this when called during the initialization of a new lane,
2004 // because we will do it after on_state_create() is called, 2004 // because we will do it after on_state_create() is called,
2005 // and we don't want to skip _G because of caching in case globals are created then 2005 // and we don't want to skip _G because of caching in case globals are created then
2006 lua_pushglobaltable( L); // settings M _G 2006 lua_pushglobaltable( L); // settings M _G
2007 populate_func_lookup_table( L, -1, NULL); 2007 populate_func_lookup_table( L, -1, NULL);
2008 lua_pop( L, 1); // settings M 2008 lua_pop( L, 1); // settings M
2009 } 2009 }
2010 lua_pop( L, 1); // settings 2010 lua_pop( L, 1); // settings
2011 2011
2012 // set _R[CONFIG_REGKEY] = settings 2012 // set _R[CONFIG_REGKEY] = settings
2013 REGISTRY_SET( L, CONFIG_REGKEY, lua_pushvalue( L, -2)); // -2 because CONFIG_REGKEY is pushed before the value itself 2013 REGISTRY_SET( L, CONFIG_REGKEY, lua_pushvalue( L, -2)); // -2 because CONFIG_REGKEY is pushed before the value itself
2014 STACK_END( L, 1); 2014 STACK_END( L, 1);
2015 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() END\n" INDENT_END, L)); 2015 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() END\n" INDENT_END, L));
2016 DEBUGSPEW_CODE( -- U->debugspew_indent_depth); 2016 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
2017 // Return the settings table 2017 // Return the settings table
2018 return 1; 2018 return 1;
2019} 2019}
2020 2020
2021#if defined PLATFORM_WIN32 && !defined NDEBUG 2021#if defined PLATFORM_WIN32 && !defined NDEBUG
@@ -2024,11 +2024,11 @@ LUAG_FUNC( configure)
2024 2024
2025void signal_handler( int signal) 2025void signal_handler( int signal)
2026{ 2026{
2027 if( signal == SIGABRT) 2027 if( signal == SIGABRT)
2028 { 2028 {
2029 _cprintf( "caught abnormal termination!"); 2029 _cprintf( "caught abnormal termination!");
2030 abort(); 2030 abort();
2031 } 2031 }
2032} 2032}
2033 2033
2034// helper to have correct callstacks when crashing a Win32 running on 64 bits Windows 2034// helper to have correct callstacks when crashing a Win32 running on 64 bits Windows
@@ -2037,88 +2037,88 @@ static volatile long s_ecoc_initCount = 0;
2037static volatile int s_ecoc_go_ahead = 0; 2037static volatile int s_ecoc_go_ahead = 0;
2038static void EnableCrashingOnCrashes( void) 2038static void EnableCrashingOnCrashes( void)
2039{ 2039{
2040 if( InterlockedCompareExchange( &s_ecoc_initCount, 1, 0) == 0) 2040 if( InterlockedCompareExchange( &s_ecoc_initCount, 1, 0) == 0)
2041 { 2041 {
2042 typedef BOOL (WINAPI* tGetPolicy)( LPDWORD lpFlags); 2042 typedef BOOL (WINAPI* tGetPolicy)( LPDWORD lpFlags);
2043 typedef BOOL (WINAPI* tSetPolicy)( DWORD dwFlags); 2043 typedef BOOL (WINAPI* tSetPolicy)( DWORD dwFlags);
2044 const DWORD EXCEPTION_SWALLOWING = 0x1; 2044 const DWORD EXCEPTION_SWALLOWING = 0x1;
2045 2045
2046 HMODULE kernel32 = LoadLibraryA("kernel32.dll"); 2046 HMODULE kernel32 = LoadLibraryA("kernel32.dll");
2047 tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32, "GetProcessUserModeExceptionPolicy"); 2047 tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32, "GetProcessUserModeExceptionPolicy");
2048 tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32, "SetProcessUserModeExceptionPolicy"); 2048 tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32, "SetProcessUserModeExceptionPolicy");
2049 if( pGetPolicy && pSetPolicy) 2049 if( pGetPolicy && pSetPolicy)
2050 { 2050 {
2051 DWORD dwFlags; 2051 DWORD dwFlags;
2052 if( pGetPolicy( &dwFlags)) 2052 if( pGetPolicy( &dwFlags))
2053 { 2053 {
2054 // Turn off the filter 2054 // Turn off the filter
2055 pSetPolicy( dwFlags & ~EXCEPTION_SWALLOWING); 2055 pSetPolicy( dwFlags & ~EXCEPTION_SWALLOWING);
2056 } 2056 }
2057 } 2057 }
2058 //typedef void (* SignalHandlerPointer)( int); 2058 //typedef void (* SignalHandlerPointer)( int);
2059 /*SignalHandlerPointer previousHandler =*/ signal( SIGABRT, signal_handler); 2059 /*SignalHandlerPointer previousHandler =*/ signal( SIGABRT, signal_handler);
2060 2060
2061 s_ecoc_go_ahead = 1; // let others pass 2061 s_ecoc_go_ahead = 1; // let others pass
2062 } 2062 }
2063 else 2063 else
2064 { 2064 {
2065 while( !s_ecoc_go_ahead) { Sleep(1); } // changes threads 2065 while( !s_ecoc_go_ahead) { Sleep(1); } // changes threads
2066 } 2066 }
2067} 2067}
2068#endif // PLATFORM_WIN32 2068#endif // PLATFORM_WIN32
2069 2069
2070int LANES_API luaopen_lanes_core( lua_State* L) 2070int LANES_API luaopen_lanes_core( lua_State* L)
2071{ 2071{
2072#if defined PLATFORM_WIN32 && !defined NDEBUG 2072#if defined PLATFORM_WIN32 && !defined NDEBUG
2073 EnableCrashingOnCrashes(); 2073 EnableCrashingOnCrashes();
2074#endif // defined PLATFORM_WIN32 && !defined NDEBUG 2074#endif // defined PLATFORM_WIN32 && !defined NDEBUG
2075 2075
2076 STACK_GROW( L, 4); 2076 STACK_GROW( L, 4);
2077 STACK_CHECK( L, 0); 2077 STACK_CHECK( L, 0);
2078 2078
2079 // Create main module interface table 2079 // Create main module interface table
2080 // we only have 1 closure, which must be called to configure Lanes 2080 // we only have 1 closure, which must be called to configure Lanes
2081 lua_newtable( L); // M 2081 lua_newtable( L); // M
2082 lua_pushvalue( L, 1); // M "lanes.core" 2082 lua_pushvalue( L, 1); // M "lanes.core"
2083 lua_pushvalue( L, -2); // M "lanes.core" M 2083 lua_pushvalue( L, -2); // M "lanes.core" M
2084 lua_pushcclosure( L, LG_configure, 2); // M LG_configure() 2084 lua_pushcclosure( L, LG_configure, 2); // M LG_configure()
2085 REGISTRY_GET( L, CONFIG_REGKEY); // M LG_configure() settings 2085 REGISTRY_GET( L, CONFIG_REGKEY); // M LG_configure() settings
2086 if( !lua_isnil( L, -1)) // this is not the first require "lanes.core": call configure() immediately 2086 if( !lua_isnil( L, -1)) // this is not the first require "lanes.core": call configure() immediately
2087 { 2087 {
2088 lua_pushvalue( L, -1); // M LG_configure() settings settings 2088 lua_pushvalue( L, -1); // M LG_configure() settings settings
2089 lua_setfield( L, -4, "settings"); // M LG_configure() settings 2089 lua_setfield( L, -4, "settings"); // M LG_configure() settings
2090 lua_call( L, 1, 0); // M 2090 lua_call( L, 1, 0); // M
2091 } 2091 }
2092 else 2092 else
2093 { 2093 {
2094 // will do nothing on first invocation, as we haven't stored settings in the registry yet 2094 // will do nothing on first invocation, as we haven't stored settings in the registry yet
2095 lua_setfield( L, -3, "settings"); // M LG_configure() 2095 lua_setfield( L, -3, "settings"); // M LG_configure()
2096 lua_setfield( L, -2, "configure"); // M 2096 lua_setfield( L, -2, "configure"); // M
2097 } 2097 }
2098 2098
2099 STACK_END( L, 1); 2099 STACK_END( L, 1);
2100 return 1; 2100 return 1;
2101} 2101}
2102 2102
2103static int default_luaopen_lanes( lua_State* L) 2103static int default_luaopen_lanes( lua_State* L)
2104{ 2104{
2105 int rc = luaL_loadfile( L, "lanes.lua") || lua_pcall( L, 0, 1, 0); 2105 int rc = luaL_loadfile( L, "lanes.lua") || lua_pcall( L, 0, 1, 0);
2106 if( rc != LUA_OK) 2106 if( rc != LUA_OK)
2107 { 2107 {
2108 return luaL_error( L, "failed to initialize embedded Lanes"); 2108 return luaL_error( L, "failed to initialize embedded Lanes");
2109 } 2109 }
2110 return 1; 2110 return 1;
2111} 2111}
2112 2112
2113// call this instead of luaopen_lanes_core() when embedding Lua and Lanes in a custom application 2113// call this instead of luaopen_lanes_core() when embedding Lua and Lanes in a custom application
2114void LANES_API luaopen_lanes_embedded( lua_State* L, lua_CFunction _luaopen_lanes) 2114void LANES_API luaopen_lanes_embedded( lua_State* L, lua_CFunction _luaopen_lanes)
2115{ 2115{
2116 STACK_CHECK( L, 0); 2116 STACK_CHECK( L, 0);
2117 // pre-require lanes.core so that when lanes.lua calls require "lanes.core" it finds it is already loaded 2117 // pre-require lanes.core so that when lanes.lua calls require "lanes.core" it finds it is already loaded
2118 luaL_requiref( L, "lanes.core", luaopen_lanes_core, 0); // ... lanes.core 2118 luaL_requiref( L, "lanes.core", luaopen_lanes_core, 0); // ... lanes.core
2119 lua_pop( L, 1); // ... 2119 lua_pop( L, 1); // ...
2120 STACK_MID( L, 0); 2120 STACK_MID( L, 0);
2121 // call user-provided function that runs the chunk "lanes.lua" from wherever they stored it 2121 // call user-provided function that runs the chunk "lanes.lua" from wherever they stored it
2122 luaL_requiref( L, "lanes", _luaopen_lanes ? _luaopen_lanes : default_luaopen_lanes, 0); // ... lanes 2122 luaL_requiref( L, "lanes", _luaopen_lanes ? _luaopen_lanes : default_luaopen_lanes, 0); // ... lanes
2123 STACK_END( L, 1); 2123 STACK_END( L, 1);
2124} 2124}