aboutsummaryrefslogtreecommitdiff
path: root/src/lanes.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lanes.c')
-rw-r--r--src/lanes.c696
1 files changed, 502 insertions, 194 deletions
diff --git a/src/lanes.c b/src/lanes.c
index 0c943aa..513a006 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -51,7 +51,7 @@
51 * ... 51 * ...
52 */ 52 */
53 53
54const char *VERSION= "2.1.0"; 54char const* VERSION = "3.1.0";
55 55
56/* 56/*
57=============================================================================== 57===============================================================================
@@ -139,7 +139,7 @@ struct s_lane {
139 // M: sets to FALSE, flags TRUE for cancel request 139 // M: sets to FALSE, flags TRUE for cancel request
140 // S: reads to see if cancel is requested 140 // S: reads to see if cancel is requested
141 141
142#if !( (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) ) 142#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
143 SIGNAL_T done_signal_; 143 SIGNAL_T done_signal_;
144 // 144 //
145 // M: Waited upon at lane ending (if Posix with no PTHREAD_TIMEDJOIN) 145 // M: Waited upon at lane ending (if Posix with no PTHREAD_TIMEDJOIN)
@@ -149,7 +149,7 @@ struct s_lane {
149 // 149 //
150 // Lock required by 'done_signal' condition variable, protecting 150 // Lock required by 'done_signal' condition variable, protecting
151 // lane status changes to DONE/ERROR_ST/CANCELLED. 151 // lane status changes to DONE/ERROR_ST/CANCELLED.
152#endif 152#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
153 153
154 volatile enum { 154 volatile enum {
155 NORMAL, // normal master side state 155 NORMAL, // normal master side state
@@ -249,6 +249,20 @@ static void linda_id( lua_State*, char const * const which);
249#define lua_toLinda(L,n) ((struct s_Linda *)luaG_todeep( L, linda_id, n )) 249#define lua_toLinda(L,n) ((struct s_Linda *)luaG_todeep( L, linda_id, n ))
250 250
251 251
252static void check_key_types( lua_State *L, int _start, int _end)
253{
254 int i;
255 for( i = _start; i <= _end; ++ i)
256 {
257 int t = lua_type( L, i);
258 if( t == LUA_TBOOLEAN || t == LUA_TNUMBER || t == LUA_TSTRING || t == LUA_TLIGHTUSERDATA)
259 {
260 continue;
261 }
262 luaL_error( L, "argument #%d: invalid key type (not a boolean, string, number or light userdata)", i);
263 }
264}
265
252/* 266/*
253* bool= linda_send( linda_ud, [timeout_secs=-1,] key_num|str|bool|lightuserdata, ... ) 267* bool= linda_send( linda_ud, [timeout_secs=-1,] key_num|str|bool|lightuserdata, ... )
254* 268*
@@ -271,15 +285,24 @@ LUAG_FUNC( linda_send)
271 if( lua_isnumber(L, 2)) 285 if( lua_isnumber(L, 2))
272 { 286 {
273 timeout= SIGNAL_TIMEOUT_PREPARE( lua_tonumber(L,2) ); 287 timeout= SIGNAL_TIMEOUT_PREPARE( lua_tonumber(L,2) );
274 key_i++; 288 ++ key_i;
275 } 289 }
276 else if( lua_isnil( L, 2)) 290 else if( lua_isnil( L, 2)) // alternate explicit "no timeout" by passing nil before the key
277 { 291 {
278 key_i++; 292 ++ key_i;
279 } 293 }
280 294
281 if( lua_isnil( L, key_i)) 295 // make sure the keys are of a valid type
282 luaL_error( L, "nil key" ); 296 check_key_types( L, key_i, key_i);
297
298 // make sure there is something to send
299 if( (uint_t)lua_gettop( L) == key_i)
300 {
301 luaL_error( L, "no data to send");
302 }
303
304 // convert nils to some special non-nil sentinel in sent values
305 keeper_toggle_nil_sentinels( L, key_i + 1, 1);
283 306
284 STACK_GROW(L, 1); 307 STACK_GROW(L, 1);
285 { 308 {
@@ -315,11 +338,11 @@ LUAG_FUNC( linda_send)
315 338
316 cancel = cancel_test( L); // testing here causes no delays 339 cancel = cancel_test( L); // testing here causes no delays
317 if (cancel) 340 if (cancel)
341 {
318 break; 342 break;
343 }
319 344
320 // Bugfix by Benoit Germain Dec-2009: change status of lane to "waiting" 345 // change status of lane to "waiting"
321 //
322#if 1
323 { 346 {
324 struct s_lane *s; 347 struct s_lane *s;
325 enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings 348 enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings
@@ -338,6 +361,7 @@ LUAG_FUNC( linda_send)
338 ASSERT_L( s->waiting_on == NULL); 361 ASSERT_L( s->waiting_on == NULL);
339 s->waiting_on = &linda->read_happened; 362 s->waiting_on = &linda->read_happened;
340 } 363 }
364 // could not send because no room: wait until some data was read before trying again, or until timeout is reached
341 if( !SIGNAL_WAIT( &linda->read_happened, &K->lock_, timeout)) 365 if( !SIGNAL_WAIT( &linda->read_happened, &K->lock_, timeout))
342 { 366 {
343 if( s) 367 if( s)
@@ -353,12 +377,6 @@ LUAG_FUNC( linda_send)
353 s->status = prev_status; 377 s->status = prev_status;
354 } 378 }
355 } 379 }
356#else
357 // K lock will be released for the duration of wait and re-acquired
358 //
359 if( !SIGNAL_WAIT( &linda->read_happened, &K->lock_, timeout))
360 break; // timeout
361#endif
362 } 380 }
363 STACK_END( KL, 0) 381 STACK_END( KL, 0)
364 keeper_release( K); 382 keeper_release( K);
@@ -379,18 +397,23 @@ LUAG_FUNC( linda_send)
379 397
380 398
381/* 399/*
382* [val, key]= linda_receive( linda_ud, [timeout_secs_num=-1], key_num|str|bool|lightuserdata [, ...] ) 400 * 2 modes of operation
383* 401 * [val, key]= linda_receive( linda_ud, [timeout_secs_num=-1], key_num|str|bool|lightuserdata [, ...] )
384* Receive a value from Linda, consuming it. 402 * Consumes a single value from the Linda, in any key.
385* 403 * Returns: received value (which is consumed from the slot), and the key which had it
386* Returns: value received (which is consumed from the slot) 404
387* key which had it 405 * [val1, ... valCOUNT]= linda_receive( linda_ud, [timeout_secs_num=-1], linda.batched, key_num|str|bool|lightuserdata, COUNT)
388*/ 406 * Consumes COUNT values from the linda, from a single key.
407 * returns the COUNT consumed values, or nil if there weren't enough values to consume
408 *
409 */
410#define BATCH_SENTINEL "270e6c9d-280f-4983-8fee-a7ecdda01475"
389LUAG_FUNC( linda_receive) 411LUAG_FUNC( linda_receive)
390{ 412{
391 struct s_Linda *linda = lua_toLinda( L, 1); 413 struct s_Linda *linda = lua_toLinda( L, 1);
392 int pushed; 414 int pushed, expected_pushed;
393 bool_t cancel = FALSE; 415 bool_t cancel = FALSE;
416 char *keeper_receive;
394 417
395 time_d timeout = -1.0; 418 time_d timeout = -1.0;
396 uint_t key_i = 2; 419 uint_t key_i = 2;
@@ -400,26 +423,44 @@ LUAG_FUNC( linda_receive)
400 if( lua_isnumber( L, 2)) 423 if( lua_isnumber( L, 2))
401 { 424 {
402 timeout = SIGNAL_TIMEOUT_PREPARE( lua_tonumber( L, 2)); 425 timeout = SIGNAL_TIMEOUT_PREPARE( lua_tonumber( L, 2));
403 key_i++; 426 ++ key_i;
427 }
428 else if( lua_isnil( L, 2)) // alternate explicit "no timeout" by passing nil before the key
429 {
430 ++ key_i;
431 }
432
433 // make sure the keys are of a valid type
434 check_key_types( L, key_i, lua_gettop( L));
435
436 // are we in batched mode?
437 lua_pushliteral( L, BATCH_SENTINEL);
438 if( lua_equal( L, key_i, -1))
439 {
440 keeper_receive = "receive_batched";
441 expected_pushed = (int)luaL_checkinteger( L, key_i + 2);
404 } 442 }
405 else if( lua_isnil( L, 2)) 443 else
406 { 444 {
407 key_i++; 445 keeper_receive = "receive";
446 expected_pushed = 2;
408 } 447 }
448 lua_pop( L, 1);
409 449
410 { 450 {
411 struct s_Keeper *K = keeper_acquire( linda); 451 struct s_Keeper *K = keeper_acquire( linda);
412 for( ;;) 452 for( ;;)
413 { 453 {
414 pushed = keeper_call( K->L, "receive", L, linda, key_i); 454 pushed = keeper_call( K->L, keeper_receive, L, linda, key_i);
415 if( pushed < 0) 455 if( pushed < 0)
416 { 456 {
417 break; 457 break;
418 } 458 }
419 if( pushed > 0) 459 if( pushed > 0)
420 { 460 {
421 ASSERT_L( pushed == 2); 461 ASSERT_L( pushed == expected_pushed);
422 462 // replace sentinels with real nils
463 keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, 0);
423 // To be done from within the 'K' locking area 464 // To be done from within the 'K' locking area
424 // 465 //
425 SIGNAL_ALL( &linda->read_happened); 466 SIGNAL_ALL( &linda->read_happened);
@@ -438,9 +479,7 @@ LUAG_FUNC( linda_receive)
438 break; 479 break;
439 } 480 }
440 481
441 // Bugfix by Benoit Germain Dec-2009: change status of lane to "waiting" 482 // change status of lane to "waiting"
442 //
443#if 1
444 { 483 {
445 struct s_lane *s; 484 struct s_lane *s;
446 enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings 485 enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings
@@ -459,6 +498,7 @@ LUAG_FUNC( linda_receive)
459 ASSERT_L( s->waiting_on == NULL); 498 ASSERT_L( s->waiting_on == NULL);
460 s->waiting_on = &linda->write_happened; 499 s->waiting_on = &linda->write_happened;
461 } 500 }
501 // not enough data to read: wakeup when data was sent, or when timeout is reached
462 if( !SIGNAL_WAIT( &linda->write_happened, &K->lock_, timeout)) 502 if( !SIGNAL_WAIT( &linda->write_happened, &K->lock_, timeout))
463 { 503 {
464 if( s) 504 if( s)
@@ -474,12 +514,6 @@ LUAG_FUNC( linda_receive)
474 s->status = prev_status; 514 s->status = prev_status;
475 } 515 }
476 } 516 }
477#else
478 // Release the K lock for the duration of wait, and re-acquire
479 //
480 if( !SIGNAL_WAIT( &linda->write_happened, &K->lock_, timeout))
481 break;
482#endif
483 } 517 }
484 keeper_release( K); 518 keeper_release( K);
485 } 519 }
@@ -501,6 +535,7 @@ LUAG_FUNC( linda_receive)
501* = linda_set( linda_ud, key_num|str|bool|lightuserdata [,value] ) 535* = linda_set( linda_ud, key_num|str|bool|lightuserdata [,value] )
502* 536*
503* Set a value to Linda. 537* Set a value to Linda.
538* TODO: what do we do if we set to non-nil and limit is 0?
504* 539*
505* Existing slot value is replaced, and possible queue entries removed. 540* Existing slot value is replaced, and possible queue entries removed.
506*/ 541*/
@@ -510,9 +545,14 @@ LUAG_FUNC( linda_set)
510 bool_t has_value = !lua_isnil( L, 3); 545 bool_t has_value = !lua_isnil( L, 3);
511 luaL_argcheck( L, linda, 1, "expected a linda object!"); 546 luaL_argcheck( L, linda, 1, "expected a linda object!");
512 547
548 // make sure the key is of a valid type
549 check_key_types( L, 2, 2);
550
513 { 551 {
552 int pushed;
514 struct s_Keeper *K = keeper_acquire( linda); 553 struct s_Keeper *K = keeper_acquire( linda);
515 int pushed = keeper_call( K->L, "set", L, linda, 2); 554 // no nil->sentinel toggling, we really clear the linda contents for the given key with a set()
555 pushed = keeper_call( K->L, "set", L, linda, 2);
516 if( pushed >= 0) // no error? 556 if( pushed >= 0) // no error?
517 { 557 {
518 ASSERT_L( pushed == 0); 558 ASSERT_L( pushed == 0);
@@ -537,20 +577,55 @@ LUAG_FUNC( linda_set)
537 577
538 578
539/* 579/*
580 * [val] = linda_count( linda_ud, [key [, ...]])
581 *
582 * Get a count of the pending elements in the specified keys
583 */
584LUAG_FUNC( linda_count)
585{
586 struct s_Linda *linda= lua_toLinda( L, 1);
587 int pushed;
588
589 luaL_argcheck( L, linda, 1, "expected a linda object!");
590 // make sure the keys are of a valid type
591 check_key_types( L, 2, lua_gettop( L));
592
593 {
594 struct s_Keeper *K = keeper_acquire( linda);
595 pushed = keeper_call( K->L, "count", L, linda, 2);
596 keeper_release( K);
597 if( pushed < 0)
598 {
599 luaL_error( L, "tried to count an invalid key");
600 }
601 }
602 return pushed;
603}
604
605
606/*
540* [val]= linda_get( linda_ud, key_num|str|bool|lightuserdata ) 607* [val]= linda_get( linda_ud, key_num|str|bool|lightuserdata )
541* 608*
542* Get a value from Linda. 609* Get a value from Linda.
610* TODO: add support to get multiple values?
543*/ 611*/
544LUAG_FUNC( linda_get) 612LUAG_FUNC( linda_get)
545{ 613{
546 struct s_Linda *linda= lua_toLinda( L, 1); 614 struct s_Linda *linda= lua_toLinda( L, 1);
547 int pushed; 615 int pushed;
616
548 luaL_argcheck( L, linda, 1, "expected a linda object!"); 617 luaL_argcheck( L, linda, 1, "expected a linda object!");
618 // make sure the key is of a valid type
619 check_key_types( L, 2, 2);
549 620
550 { 621 {
551 struct s_Keeper *K = keeper_acquire( linda); 622 struct s_Keeper *K = keeper_acquire( linda);
552 pushed = keeper_call( K->L, "get", L, linda, 2); 623 pushed = keeper_call( K->L, "get", L, linda, 2);
553 ASSERT_L( pushed==0 || pushed==1 ); 624 ASSERT_L( pushed==0 || pushed==1 );
625 if( pushed > 0)
626 {
627 keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, 0);
628 }
554 keeper_release(K); 629 keeper_release(K);
555 // must trigger error after keeper state has been released 630 // must trigger error after keeper state has been released
556 if( pushed < 0) 631 if( pushed < 0)
@@ -571,7 +646,10 @@ LUAG_FUNC( linda_get)
571LUAG_FUNC( linda_limit) 646LUAG_FUNC( linda_limit)
572{ 647{
573 struct s_Linda *linda= lua_toLinda( L, 1 ); 648 struct s_Linda *linda= lua_toLinda( L, 1 );
649
574 luaL_argcheck( L, linda, 1, "expected a linda object!"); 650 luaL_argcheck( L, linda, 1, "expected a linda object!");
651 // make sure the key is of a valid type
652 check_key_types( L, 2, 2);
575 653
576 { 654 {
577 struct s_Keeper *K = keeper_acquire( linda); 655 struct s_Keeper *K = keeper_acquire( linda);
@@ -608,6 +686,57 @@ LUAG_FUNC( linda_deep ) {
608 686
609 687
610/* 688/*
689* string = linda:__tostring( linda_ud)
690*
691* Return the stringification of a linda
692*
693* Useful for concatenation or debugging purposes
694*/
695LUAG_FUNC( linda_tostring)
696{
697 char text[32];
698 struct s_Linda *linda = lua_toLinda( L, 1);
699 luaL_argcheck( L, linda, 1, "expected a linda object!");
700 sprintf( text, "linda: %p", linda);
701 lua_pushstring( L, text);
702 return 1;
703}
704
705
706/*
707* string = linda:__concat( a, b)
708*
709* Return the concatenation of a pair of items, one of them being a linda
710*
711* Useful for concatenation or debugging purposes
712*/
713LUAG_FUNC( linda_concat)
714{
715 struct s_Linda *linda1 = lua_toLinda( L, 1);
716 struct s_Linda *linda2 = lua_toLinda( L, 2);
717 // lua semantics should enforce that one of the parameters we got is a linda
718 luaL_argcheck( L, linda1 || linda2, 1, "expected a linda object!");
719 // replace the lindas by their string equivalents in the stack
720 if ( linda1)
721 {
722 char text[32];
723 sprintf( text, "linda: %p", linda1);
724 lua_pushstring( L, text);
725 lua_replace( L, 1);
726 }
727 if ( linda2)
728 {
729 char text[32];
730 sprintf( text, "linda: %p", linda2);
731 lua_pushstring( L, text);
732 lua_replace( L, 2);
733 }
734 // concat the result
735 lua_concat( L, 2);
736 return 1;
737}
738
739/*
611* Identity function of a shared userdata object. 740* Identity function of a shared userdata object.
612* 741*
613* lightuserdata= linda_id( "new" [, ...] ) 742* lightuserdata= linda_id( "new" [, ...] )
@@ -658,10 +787,11 @@ static void linda_id( lua_State *L, char const * const which)
658 /* Clean associated structures in the keeper state. 787 /* Clean associated structures in the keeper state.
659 */ 788 */
660 K= keeper_acquire(s); 789 K= keeper_acquire(s);
790 if( K) // can be NULL if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup)
661 { 791 {
662 keeper_call( K->L, "clear", L, s, 0 ); 792 keeper_call( K->L, "clear", L, s, 0 );
793 keeper_release(K);
663 } 794 }
664 keeper_release(K);
665 795
666 /* There aren't any lanes waiting on these lindas, since all proxies 796 /* There aren't any lanes waiting on these lindas, since all proxies
667 * have been gc'ed. Right? 797 * have been gc'ed. Right?
@@ -678,29 +808,43 @@ static void linda_id( lua_State *L, char const * const which)
678 // metatable is its own index 808 // metatable is its own index
679 lua_pushvalue( L, -1); 809 lua_pushvalue( L, -1);
680 lua_setfield( L, -2, "__index"); 810 lua_setfield( L, -2, "__index");
811
681 // protect metatable from external access 812 // protect metatable from external access
682 lua_pushboolean( L, 0); 813 lua_pushboolean( L, 0);
683 lua_setfield( L, -2, "__metatable"); 814 lua_setfield( L, -2, "__metatable");
815
816 lua_pushcfunction( L, LG_linda_tostring);
817 lua_setfield( L, -2, "__tostring");
818
819 lua_pushcfunction( L, LG_linda_concat);
820 lua_setfield( L, -2, "__concat");
821
684 // 822 //
685 // [-1]: linda metatable 823 // [-1]: linda metatable
686 lua_pushcfunction( L, LG_linda_send ); 824 lua_pushcfunction( L, LG_linda_send );
687 lua_setfield( L, -2, "send" ); 825 lua_setfield( L, -2, "send" );
688 826
689 lua_pushcfunction( L, LG_linda_receive ); 827 lua_pushcfunction( L, LG_linda_receive );
690 lua_setfield( L, -2, "receive" ); 828 lua_setfield( L, -2, "receive" );
691 829
692 lua_pushcfunction( L, LG_linda_limit ); 830 lua_pushcfunction( L, LG_linda_limit );
693 lua_setfield( L, -2, "limit" ); 831 lua_setfield( L, -2, "limit" );
694 832
695 lua_pushcfunction( L, LG_linda_set ); 833 lua_pushcfunction( L, LG_linda_set );
696 lua_setfield( L, -2, "set" ); 834 lua_setfield( L, -2, "set" );
697 835
836 lua_pushcfunction( L, LG_linda_count );
837 lua_setfield( L, -2, "count" );
838
698 lua_pushcfunction( L, LG_linda_get ); 839 lua_pushcfunction( L, LG_linda_get );
699 lua_setfield( L, -2, "get" ); 840 lua_setfield( L, -2, "get" );
700 841
701 lua_pushcfunction( L, LG_linda_deep ); 842 lua_pushcfunction( L, LG_linda_deep );
702 lua_setfield( L, -2, "deep" ); 843 lua_setfield( L, -2, "deep" );
703 844
845 lua_pushliteral( L, BATCH_SENTINEL);
846 lua_setfield(L, -2, "batched");
847
704 STACK_END(L,1) 848 STACK_END(L,1)
705 } 849 }
706 else if( strcmp( which, "module") == 0) 850 else if( strcmp( which, "module") == 0)
@@ -714,6 +858,11 @@ static void linda_id( lua_State *L, char const * const which)
714 } 858 }
715} 859}
716 860
861/*
862 * ud = lanes.linda()
863 *
864 * returns a linda object
865 */
717LUAG_FUNC( linda) 866LUAG_FUNC( linda)
718{ 867{
719 return luaG_deep_userdata( L, linda_id); 868 return luaG_deep_userdata( L, linda_id);
@@ -845,8 +994,9 @@ static void selfdestruct_add( struct s_lane *s ) {
845/* 994/*
846* A free-running lane has ended; remove it from selfdestruct chain 995* A free-running lane has ended; remove it from selfdestruct chain
847*/ 996*/
848static void selfdestruct_remove( struct s_lane *s ) { 997static bool_t selfdestruct_remove( struct s_lane *s )
849 998{
999 bool_t found = FALSE;
850 MUTEX_LOCK( &selfdestruct_cs ); 1000 MUTEX_LOCK( &selfdestruct_cs );
851 { 1001 {
852 // Make sure (within the MUTEX) that we actually are in the chain 1002 // Make sure (within the MUTEX) that we actually are in the chain
@@ -855,7 +1005,6 @@ static void selfdestruct_remove( struct s_lane *s ) {
855 // 1005 //
856 if (s->selfdestruct_next != NULL) { 1006 if (s->selfdestruct_next != NULL) {
857 struct s_lane **ref= (struct s_lane **) &selfdestruct_first; 1007 struct s_lane **ref= (struct s_lane **) &selfdestruct_first;
858 bool_t found= FALSE;
859 1008
860 while( *ref != SELFDESTRUCT_END ) { 1009 while( *ref != SELFDESTRUCT_END ) {
861 if (*ref == s) { 1010 if (*ref == s) {
@@ -870,6 +1019,7 @@ static void selfdestruct_remove( struct s_lane *s ) {
870 } 1019 }
871 } 1020 }
872 MUTEX_UNLOCK( &selfdestruct_cs ); 1021 MUTEX_UNLOCK( &selfdestruct_cs );
1022 return found;
873} 1023}
874 1024
875// Initialized by 'init_once_LOCKED()': the deep userdata Linda object 1025// Initialized by 'init_once_LOCKED()': the deep userdata Linda object
@@ -880,9 +1030,10 @@ volatile DEEP_PRELUDE *timer_deep; // = NULL
880/* 1030/*
881* Process end; cancel any still free-running threads 1031* Process end; cancel any still free-running threads
882*/ 1032*/
883static void selfdestruct_atexit( void ) 1033static int selfdestruct_atexit( lua_State *L)
884{ 1034{
885 if (selfdestruct_first == SELFDESTRUCT_END) return; // no free-running threads 1035 (void)L; // unused
1036 if (selfdestruct_first == SELFDESTRUCT_END) return 0; // no free-running threads
886 1037
887 // Signal _all_ still running threads to exit (including the timer thread) 1038 // Signal _all_ still running threads to exit (including the timer thread)
888 // 1039 //
@@ -899,7 +1050,7 @@ static void selfdestruct_atexit( void )
899 // signal the linda the wake up the thread so that it can react to the cancel query 1050 // signal the linda the wake up the thread so that it can react to the cancel query
900 // let us hope we never land here with a pointer on a linda that has been destroyed... 1051 // let us hope we never land here with a pointer on a linda that has been destroyed...
901 SIGNAL_T *waiting_on = s->waiting_on; 1052 SIGNAL_T *waiting_on = s->waiting_on;
902 s->waiting_on = NULL; 1053 //s->waiting_on = NULL; // useful, or not?
903 SIGNAL_ALL( waiting_on); 1054 SIGNAL_ALL( waiting_on);
904 } 1055 }
905 s = s->selfdestruct_next; 1056 s = s->selfdestruct_next;
@@ -969,6 +1120,7 @@ static void selfdestruct_atexit( void )
969 // 1120 //
970 if ( selfdestruct_first != SELFDESTRUCT_END ) { 1121 if ( selfdestruct_first != SELFDESTRUCT_END ) {
971 unsigned n=0; 1122 unsigned n=0;
1123#if 0
972 MUTEX_LOCK( &selfdestruct_cs ); 1124 MUTEX_LOCK( &selfdestruct_cs );
973 { 1125 {
974 struct s_lane *s= selfdestruct_first; 1126 struct s_lane *s= selfdestruct_first;
@@ -983,15 +1135,14 @@ static void selfdestruct_atexit( void )
983 // and works without the block (so let's leave those lanes running) 1135 // and works without the block (so let's leave those lanes running)
984 // 1136 //
985//we want to free memory and such when we exit. 1137//we want to free memory and such when we exit.
986#if 0
987 // 2.0.2: at least timer lane is still here 1138 // 2.0.2: at least timer lane is still here
988 // 1139 //
989 DEBUGEXEC(fprintf( stderr, "Left %d lane(s) with cancel request at process end.\n", n )); 1140 DEBUGEXEC(fprintf( stderr, "Left %d lane(s) with cancel request at process end.\n", n ));
1141 n=0;
990#else 1142#else
991 // first thing we did was to raise the linda signals the threads were waiting on (if any) 1143 // first thing we did was to raise the linda signals the threads were waiting on (if any)
992 // therefore, any well-behaved thread should be in CANCELLED state 1144 // therefore, any well-behaved thread should be in CANCELLED state
993 // these are not running, and the state can be closed 1145 // these are not running, and the state can be closed
994 n=0;
995 MUTEX_LOCK( &selfdestruct_cs ); 1146 MUTEX_LOCK( &selfdestruct_cs );
996 { 1147 {
997 struct s_lane *s= selfdestruct_first; 1148 struct s_lane *s= selfdestruct_first;
@@ -999,8 +1150,19 @@ static void selfdestruct_atexit( void )
999 { 1150 {
1000 struct s_lane *next_s= s->selfdestruct_next; 1151 struct s_lane *next_s= s->selfdestruct_next;
1001 s->selfdestruct_next= NULL; // detach from selfdestruct chain 1152 s->selfdestruct_next= NULL; // detach from selfdestruct chain
1002 THREAD_KILL( &s->thread); 1153 if( !THREAD_ISNULL( s->thread)) // can be NULL if previous 'soft' termination succeeded
1154 {
1155 THREAD_KILL( &s->thread);
1156#if THREADAPI == THREADAPI_PTHREAD
1157 // pthread: make sure the thread is really stopped!
1158 THREAD_WAIT( &s->thread, -1, &s->done_signal_, &s->done_lock_, &s->status);
1159#endif // THREADAPI == THREADAPI_PTHREAD
1160 }
1003 // NO lua_close() in this case because we don't know where execution of the state was interrupted 1161 // NO lua_close() in this case because we don't know where execution of the state was interrupted
1162#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
1163 SIGNAL_FREE( &s->done_signal_);
1164 MUTEX_FREE( &s->done_lock_);
1165#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
1004 free( s); 1166 free( s);
1005 s = next_s; 1167 s = next_s;
1006 n++; 1168 n++;
@@ -1013,6 +1175,7 @@ static void selfdestruct_atexit( void )
1013#endif 1175#endif
1014 } 1176 }
1015 close_keepers(); 1177 close_keepers();
1178 return 0;
1016} 1179}
1017 1180
1018 1181
@@ -1205,15 +1368,15 @@ void SetThreadName( DWORD dwThreadID, char const *_threadName)
1205 1368
1206LUAG_FUNC( set_debug_threadname) 1369LUAG_FUNC( set_debug_threadname)
1207{ 1370{
1208 char const *threadName;
1209 luaL_checktype( L, -1, LUA_TSTRING); 1371 luaL_checktype( L, -1, LUA_TSTRING);
1210 threadName = lua_tostring( L, -1);
1211
1212#if defined PLATFORM_WIN32 && !defined __GNUC__ 1372#if defined PLATFORM_WIN32 && !defined __GNUC__
1213 // to see thead name in Visual Studio C debugger 1373 {
1214 SetThreadName(-1, threadName); 1374 char const *threadName = lua_tostring( L, -1);
1215#endif
1216 1375
1376 // to see thead name in Visual Studio C debugger
1377 SetThreadName(-1, threadName);
1378 }
1379#endif // defined PLATFORM_WIN32 && !defined __GNUC__
1217 // to see VM name in Decoda debugger Virtual Machine window 1380 // to see VM name in Decoda debugger Virtual Machine window
1218 lua_setglobal( L, "decoda_name"); 1381 lua_setglobal( L, "decoda_name");
1219 1382
@@ -1221,11 +1384,7 @@ LUAG_FUNC( set_debug_threadname)
1221} 1384}
1222 1385
1223//--- 1386//---
1224#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 1387static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1225 static THREAD_RETURN_T __stdcall lane_main( void *vs )
1226#else
1227 static THREAD_RETURN_T lane_main( void *vs )
1228#endif
1229{ 1388{
1230 struct s_lane *s= (struct s_lane *)vs; 1389 struct s_lane *s= (struct s_lane *)vs;
1231 int rc, rc2; 1390 int rc, rc2;
@@ -1315,20 +1474,22 @@ LUAG_FUNC( set_debug_threadname)
1315 lua_newtable(L); 1474 lua_newtable(L);
1316 } 1475 }
1317 s->waiting_on = NULL; // just in case 1476 s->waiting_on = NULL; // just in case
1318 if (s->selfdestruct_next != NULL) { 1477 if( selfdestruct_remove( s)) // check and remove (under lock!)
1478 {
1319 // We're a free-running thread and no-one's there to clean us up. 1479 // We're a free-running thread and no-one's there to clean us up.
1320 // 1480 //
1321 lua_close( s->L ); 1481 lua_close( s->L );
1322 s->L = L = 0; 1482 s->L = L = 0;
1323 1483
1324 #if !( (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) ) 1484 #if THREADWAIT_METHOD == THREADWAIT_CONDVAR
1325 SIGNAL_FREE( &s->done_signal_ ); 1485 SIGNAL_FREE( &s->done_signal_);
1326 MUTEX_FREE( &s->done_lock_ ); 1486 MUTEX_FREE( &s->done_lock_);
1327 #endif 1487 #endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
1328 selfdestruct_remove(s); // away from selfdestruct chain
1329 free(s); 1488 free(s);
1330 1489
1331 } else { 1490 }
1491 else
1492 {
1332 // leave results (1..top) or error message + stack trace (1..2) on the stack - master will copy them 1493 // leave results (1..top) or error message + stack trace (1..2) on the stack - master will copy them
1333 1494
1334 enum e_status st= 1495 enum e_status st=
@@ -1339,16 +1500,16 @@ LUAG_FUNC( set_debug_threadname)
1339 // Posix no PTHREAD_TIMEDJOIN: 1500 // Posix no PTHREAD_TIMEDJOIN:
1340 // 'done_lock' protects the -> DONE|ERROR_ST|CANCELLED state change 1501 // 'done_lock' protects the -> DONE|ERROR_ST|CANCELLED state change
1341 // 1502 //
1342 #if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) 1503#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
1343 s->status= st; 1504 MUTEX_LOCK( &s->done_lock_);
1344 #else
1345 MUTEX_LOCK( &s->done_lock_ );
1346 { 1505 {
1347 s->status= st; 1506#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
1348 SIGNAL_ONE( &s->done_signal_ ); // wake up master (while 's->done_lock' is on) 1507 s->status = st;
1508#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
1509 SIGNAL_ONE( &s->done_signal_); // wake up master (while 's->done_lock' is on)
1349 } 1510 }
1350 MUTEX_UNLOCK( &s->done_lock_ ); 1511 MUTEX_UNLOCK( &s->done_lock_);
1351 #endif 1512#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
1352 } 1513 }
1353 return 0; // ignored 1514 return 0; // ignored
1354} 1515}
@@ -1359,22 +1520,52 @@ LUAG_FUNC( set_debug_threadname)
1359// [cancelstep_uint=0], 1520// [cancelstep_uint=0],
1360// [prio_int=0], 1521// [prio_int=0],
1361// [globals_tbl], 1522// [globals_tbl],
1523// [package_tbl],
1524// [required],
1362// [... args ...] ) 1525// [... args ...] )
1363// 1526//
1364// Upvalues: metatable to use for 'lane_ud' 1527// Upvalues: metatable to use for 'lane_ud'
1365// 1528//
1529
1530// helper function to require a module in the keeper states and in the target state
1531// source state contains module name at the top of the stack
1532static void require_one_module( lua_State *L, lua_State *L2, bool_t _fatal)
1533{
1534 size_t len;
1535 char const *name = lua_tolstring( L, -1, &len);
1536 // require the module in the target lane
1537 STACK_GROW( L2, 2);
1538 lua_getglobal( L2, "require");
1539 if( lua_isnil( L2, -1))
1540 {
1541 lua_pop( L2, 1);
1542 if( _fatal)
1543 luaL_error( L, "cannot pre-require modules without loading 'package' library first");
1544 }
1545 else
1546 {
1547 lua_pushlstring( L2, name, len);
1548 lua_pcall( L2, 1, 0, 0);
1549 // we need to require this module in the keeper states as well
1550 populate_keepers( L);
1551 }
1552}
1553
1366LUAG_FUNC( thread_new ) 1554LUAG_FUNC( thread_new )
1367{ 1555{
1368 lua_State *L2; 1556 lua_State *L2;
1369 struct s_lane *s; 1557 struct s_lane *s;
1370 struct s_lane **ud; 1558 struct s_lane **ud;
1371 1559
1372 const char *libs= lua_tostring( L, 2 ); 1560 char const* libs = lua_tostring( L, 2);
1373 uint_t cs= luaG_optunsigned( L, 3,0); 1561 lua_CFunction on_state_create = lua_iscfunction( L, 3) ? lua_tocfunction( L, 3) : NULL;
1374 int prio= (int)luaL_optinteger( L, 4,0); 1562 uint_t cs = luaG_optunsigned( L, 4, 0);
1375 uint_t glob= luaG_isany(L,5) ? 5:0; 1563 int prio = (int) luaL_optinteger( L, 5, 0);
1564 uint_t glob = luaG_isany( L, 6) ? 6 : 0;
1565 uint_t package = luaG_isany( L,7) ? 7 : 0;
1566 uint_t required = luaG_isany( L, 8) ? 8 : 0;
1376 1567
1377#define FIXED_ARGS (5) 1568#define FIXED_ARGS 8
1378 uint_t args= lua_gettop(L) - FIXED_ARGS; 1569 uint_t args= lua_gettop(L) - FIXED_ARGS;
1379 1570
1380 if (prio < THREAD_PRIO_MIN || prio > THREAD_PRIO_MAX) 1571 if (prio < THREAD_PRIO_MIN || prio > THREAD_PRIO_MAX)
@@ -1385,45 +1576,109 @@ LUAG_FUNC( thread_new )
1385 1576
1386 /* --- Create and prepare the sub state --- */ 1577 /* --- Create and prepare the sub state --- */
1387 1578
1388 L2 = luaL_newstate(); // uses standard 'realloc()'-based allocator, 1579 // populate with selected libraries at the same time
1389 // sets the panic callback 1580 //
1390 1581 L2 = luaG_newstate( libs, on_state_create);
1391 if (!L2) luaL_error( L, "'luaL_newstate()' failed; out of memory" ); 1582 if (!L2) luaL_error( L, "'luaL_newstate()' failed; out of memory" );
1392 1583
1393 STACK_GROW( L,2 ); 1584 STACK_GROW( L, 2);
1394 1585
1395 // Setting the globals table (needs to be done before loading stdlibs, 1586 ASSERT_L( lua_gettop(L2) == 0);
1396 // and the lane function)
1397 //
1398 if (glob!=0)
1399 {
1400 STACK_CHECK(L)
1401 if (!lua_istable(L,glob))
1402 luaL_error( L, "Expected table, got %s", luaG_typename(L,glob) );
1403 1587
1404 lua_pushvalue( L, glob ); 1588 // package.path
1589 STACK_CHECK(L)
1590 STACK_CHECK(L2)
1591 if( package)
1592 {
1593 if (lua_type(L,package) != LUA_TTABLE)
1594 luaL_error( L, "expected package as table, got %s", luaL_typename(L,package));
1595 lua_getglobal( L2, "package");
1596 if( !lua_isnil( L2, -1)) // package library not loaded: do nothing
1597 {
1598 int i;
1599 char const *entries[] = { "path", "cpath", "preload", "loaders", NULL};
1600 for( i = 0; entries[i]; ++ i)
1601 {
1602 lua_getfield( L, package, entries[i]);
1603 if( lua_isnil( L, -1))
1604 {
1605 lua_pop( L, 1);
1606 }
1607 else
1608 {
1609 luaG_inter_move( L, L2, 1); // moves the entry to L2
1610 lua_setfield( L2, -2, entries[i]); // set package[entries[i]]
1611 }
1612 }
1613 }
1614 lua_pop( L2, 1);
1615 }
1616 STACK_END(L2,0)
1617 STACK_END(L,0)
1405 1618
1406 luaG_inter_move( L, L2, 1); // moves the table to L2 1619 // modules to require in the target lane *before* the function is transfered!
1407 1620
1408 // L2 [-1]: table of globals 1621 //start by requiring lua51-lanes, since it is a bit special
1622 // it is not fatal if 'require' isn't loaded, just ignore (may cause function transfer errors later on if the lane pulls the lanes module itself)
1623 STACK_CHECK(L)
1624 STACK_CHECK(L2)
1625 lua_pushliteral( L, "lua51-lanes");
1626 require_one_module( L, L2, FALSE);
1627 lua_pop( L, 1);
1628 STACK_END(L2,0)
1629 STACK_END(L,0)
1409 1630
1410 // "You can change the global environment of a Lua thread using lua_replace" 1631 STACK_CHECK(L)
1411 // (refman-5.0.pdf p. 30) 1632 STACK_CHECK(L2)
1412 // 1633 if( required)
1413 lua_replace( L2, LUA_GLOBALSINDEX ); 1634 {
1414 STACK_END(L,0) 1635 int nbRequired = 1;
1636 // should not happen, was checked in lanes.lua before calling thread_new()
1637 if (lua_type(L, required) != LUA_TTABLE)
1638 luaL_error( L, "expected required module list as a table, got %s", luaL_typename( L, required));
1639 lua_pushnil( L);
1640 while( lua_next( L, required) != 0)
1641 {
1642 if (lua_type(L,-1) != LUA_TSTRING || lua_type(L,-2) != LUA_TNUMBER || lua_tonumber( L, -2) != nbRequired)
1643 {
1644 luaL_error( L, "required module list should be a list of strings.");
1645 }
1646 else
1647 {
1648 require_one_module( L, L2, TRUE);
1649 }
1650 lua_pop( L, 1);
1651 ++ nbRequired;
1652 }
1415 } 1653 }
1654 STACK_END(L2,0)
1655 STACK_END(L,0)
1416 1656
1417 // Selected libraries 1657 // Appending the specified globals to the global environment
1658 // *after* stdlibs have been loaded and modules required, in case we transfer references to native functions they exposed...
1418 // 1659 //
1419 if (libs) 1660 if (glob!=0)
1420 { 1661 {
1421 const char *err= luaG_openlibs( L2, libs ); 1662 STACK_CHECK(L)
1422 ASSERT_L( !err ); // bad libs should have been noticed by 'lanes.lua' 1663 STACK_CHECK(L2)
1664 if (!lua_istable(L,glob))
1665 luaL_error( L, "Expected table, got %s", luaL_typename(L,glob));
1423 1666
1424 serialize_require( L2 ); 1667 lua_pushnil( L);
1668 while( lua_next( L, glob))
1669 {
1670 luaG_inter_copy( L, L2, 2); // moves the key/value pair to the L2 stack
1671 // assign it in the globals table
1672 lua_rawset( L2, LUA_GLOBALSINDEX);
1673 lua_pop( L, 1);
1674 }
1675
1676 STACK_END(L2, 0)
1677 STACK_END(L, 0)
1425 } 1678 }
1426 1679
1680 ASSERT_L( lua_gettop(L2) == 0);
1681
1427 // Lane main function 1682 // Lane main function
1428 // 1683 //
1429 STACK_CHECK(L) 1684 STACK_CHECK(L)
@@ -1470,10 +1725,10 @@ LUAG_FUNC( thread_new )
1470 s->waiting_on = NULL; 1725 s->waiting_on = NULL;
1471 s->cancel_request= FALSE; 1726 s->cancel_request= FALSE;
1472 1727
1473#if !( (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) ) 1728#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
1474 MUTEX_INIT( &s->done_lock_ ); 1729 MUTEX_INIT( &s->done_lock_);
1475 SIGNAL_INIT( &s->done_signal_ ); 1730 SIGNAL_INIT( &s->done_signal_);
1476#endif 1731#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
1477 s->mstatus= NORMAL; 1732 s->mstatus= NORMAL;
1478 s->selfdestruct_next= NULL; 1733 s->selfdestruct_next= NULL;
1479 1734
@@ -1488,7 +1743,7 @@ LUAG_FUNC( thread_new )
1488 lua_newtable( L); 1743 lua_newtable( L);
1489 lua_setfenv( L, -2); 1744 lua_setfenv( L, -2);
1490 1745
1491 // Place 's' to registry, for 'cancel_test()' (even if 'cs'==0 we still 1746 // Place 's' in registry, for 'cancel_test()' (even if 'cs'==0 we still
1492 // do cancel tests at pending send/receive). 1747 // do cancel tests at pending send/receive).
1493 // 1748 //
1494 lua_pushlightuserdata( L2, CANCEL_TEST_KEY ); 1749 lua_pushlightuserdata( L2, CANCEL_TEST_KEY );
@@ -1545,6 +1800,7 @@ LUAG_FUNC( thread_gc )
1545 { 1800 {
1546 // Make sure a kill has proceeded, before cleaning up the data structure. 1801 // Make sure a kill has proceeded, before cleaning up the data structure.
1547 // 1802 //
1803 // NO lua_close() in this case because we don't know where execution of the state was interrupted
1548 // If not doing 'THREAD_WAIT()' we should close the Lua state here 1804 // If not doing 'THREAD_WAIT()' we should close the Lua state here
1549 // (can it be out of order, since we killed the lane abruptly?) 1805 // (can it be out of order, since we killed the lane abruptly?)
1550 // 1806 //
@@ -1553,11 +1809,7 @@ LUAG_FUNC( thread_gc )
1553 s->L = 0; 1809 s->L = 0;
1554#else // 0 1810#else // 0
1555 DEBUGEXEC(fprintf( stderr, "** Joining with a killed thread (needs testing) **" )); 1811 DEBUGEXEC(fprintf( stderr, "** Joining with a killed thread (needs testing) **" ));
1556#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) 1812 THREAD_WAIT( &s->thread, -1, &s->done_signal_, &s->done_lock_, &s->status);
1557 THREAD_WAIT( &s->thread, -1 );
1558#else
1559 THREAD_WAIT( &s->thread, &s->done_signal_, &s->done_lock_, &s->status, -1 );
1560#endif
1561 DEBUGEXEC(fprintf( stderr, "** Joined ok **" )); 1813 DEBUGEXEC(fprintf( stderr, "** Joined ok **" ));
1562#endif // 0 1814#endif // 0
1563 } 1815 }
@@ -1569,12 +1821,12 @@ LUAG_FUNC( thread_gc )
1569 1821
1570 // Clean up after a (finished) thread 1822 // Clean up after a (finished) thread
1571 // 1823 //
1572#if (! ((defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN))) 1824#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
1573 SIGNAL_FREE( &s->done_signal_ ); 1825 SIGNAL_FREE( &s->done_signal_);
1574 MUTEX_FREE( &s->done_lock_ ); 1826 MUTEX_FREE( &s->done_lock_);
1575#endif 1827#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
1576 1828
1577 free(s); 1829 free( s);
1578 1830
1579 return 0; 1831 return 0;
1580} 1832}
@@ -1603,13 +1855,19 @@ static bool_t thread_cancel( struct s_lane *s, double secs, bool_t force)
1603 // 1855 //
1604 if( s->status < DONE) 1856 if( s->status < DONE)
1605 { 1857 {
1606 s->cancel_request = TRUE; // it's now signalled to stop 1858 s->cancel_request = TRUE; // it's now signaled to stop
1607 done= 1859 // signal the linda the wake up the thread so that it can react to the cancel query
1608#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) 1860 // let us hope we never land here with a pointer on a linda that has been destroyed...
1609 THREAD_WAIT( &s->thread, secs); 1861 //MUTEX_LOCK( &selfdestruct_cs );
1610#else 1862 {
1611 THREAD_WAIT( &s->thread, &s->done_signal_, &s->done_lock_, &s->status, secs); 1863 SIGNAL_T *waiting_on = s->waiting_on;
1612#endif 1864 if( s->status == WAITING && waiting_on != NULL)
1865 {
1866 SIGNAL_ALL( waiting_on);
1867 }
1868 }
1869 //MUTEX_UNLOCK( &selfdestruct_cs );
1870 done = THREAD_WAIT( &s->thread, secs, &s->done_signal_, &s->done_lock_, &s->status);
1613 1871
1614 if ((!done) && force) 1872 if ((!done) && force)
1615 { 1873 {
@@ -1627,23 +1885,32 @@ static bool_t thread_cancel( struct s_lane *s, double secs, bool_t force)
1627 1885
1628LUAG_FUNC( thread_cancel) 1886LUAG_FUNC( thread_cancel)
1629{ 1887{
1630 struct s_lane *s= lua_toLane(L,1); 1888 if( lua_gettop( L) != 1 || lua_type( L, 1) != LUA_TUSERDATA)
1631 double secs= 0.0; 1889 {
1632 uint_t force_i=2; 1890 return luaL_error( L, "invalid argument #1, did you use ':' as you should?");
1633 bool_t force, done= TRUE; 1891 }
1892 else
1893 {
1894 struct s_lane *s = lua_toLane( L, 1);
1895 double secs = 0.0;
1896 uint_t force_i = 2;
1897 bool_t force, done= TRUE;
1634 1898
1635 if (lua_isnumber(L,2)) { 1899 if( lua_isnumber( L, 2))
1636 secs= lua_tonumber(L,2); 1900 {
1637 force_i++; 1901 secs = lua_tonumber( L, 2);
1638 } else if (lua_isnil(L,2)) 1902 ++ force_i;
1639 force_i++; 1903 }
1904 else if( lua_isnil( L, 2))
1905 ++ force_i;
1640 1906
1641 force= lua_toboolean(L,force_i); // FALSE if nothing there 1907 force = lua_toboolean( L, force_i); // FALSE if nothing there
1642 1908
1643 done = thread_cancel( s, secs, force); 1909 done = thread_cancel( s, secs, force);
1644 1910
1645 lua_pushboolean( L, done); 1911 lua_pushboolean( L, done);
1646 return 1; 1912 return 1;
1913 }
1647} 1914}
1648 1915
1649//--- 1916//---
@@ -1698,12 +1965,7 @@ LUAG_FUNC( thread_join )
1698 int ret; 1965 int ret;
1699 bool_t done; 1966 bool_t done;
1700 1967
1701 done = (s->thread == 0) || 1968 done = THREAD_ISNULL( s->thread) || THREAD_WAIT( &s->thread, wait_secs, &s->done_signal_, &s->done_lock_, &s->status);
1702#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN)
1703 THREAD_WAIT( &s->thread, wait_secs );
1704#else
1705 THREAD_WAIT( &s->thread, &s->done_signal_, &s->done_lock_, &s->status, wait_secs);
1706#endif
1707 if (!done || !L2) 1969 if (!done || !L2)
1708 return 0; // timeout: pushes none, leaves 'L2' alive 1970 return 0; // timeout: pushes none, leaves 'L2' alive
1709 1971
@@ -1915,7 +2177,8 @@ LUAG_FUNC( now_secs )
1915LUAG_FUNC( wakeup_conv ) 2177LUAG_FUNC( wakeup_conv )
1916{ 2178{
1917 int year, month, day, hour, min, sec, isdst; 2179 int year, month, day, hour, min, sec, isdst;
1918 struct tm tm= {0}; 2180 struct tm t;
2181 memset( &t, 0, sizeof( t));
1919 // 2182 //
1920 // .year (four digits) 2183 // .year (four digits)
1921 // .month (1..12) 2184 // .month (1..12)
@@ -1942,15 +2205,15 @@ LUAG_FUNC( wakeup_conv )
1942 lua_pop(L,1); 2205 lua_pop(L,1);
1943 STACK_END(L,0) 2206 STACK_END(L,0)
1944 2207
1945 tm.tm_year= year-1900; 2208 t.tm_year= year-1900;
1946 tm.tm_mon= month-1; // 0..11 2209 t.tm_mon= month-1; // 0..11
1947 tm.tm_mday= day; // 1..31 2210 t.tm_mday= day; // 1..31
1948 tm.tm_hour= hour; // 0..23 2211 t.tm_hour= hour; // 0..23
1949 tm.tm_min= min; // 0..59 2212 t.tm_min= min; // 0..59
1950 tm.tm_sec= sec; // 0..60 2213 t.tm_sec= sec; // 0..60
1951 tm.tm_isdst= isdst; // 0/1/negative 2214 t.tm_isdst= isdst; // 0/1/negative
1952 2215
1953 lua_pushnumber( L, (double) mktime( &tm ) ); // ms=0 2216 lua_pushnumber( L, (double) mktime( &t)); // ms=0
1954 return 1; 2217 return 1;
1955} 2218}
1956 2219
@@ -1968,7 +2231,7 @@ static const struct luaL_reg lanes_functions [] = {
1968/* 2231/*
1969* One-time initializations 2232* One-time initializations
1970*/ 2233*/
1971static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_ref, int const nbKeepers) 2234static void init_once_LOCKED( lua_State* L, volatile DEEP_PRELUDE** timer_deep_ref, int const nbKeepers, lua_CFunction _on_state_create)
1972{ 2235{
1973 const char *err; 2236 const char *err;
1974 2237
@@ -1994,7 +2257,7 @@ static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_
1994 // Selfdestruct chain handling 2257 // Selfdestruct chain handling
1995 // 2258 //
1996 MUTEX_INIT( &selfdestruct_cs ); 2259 MUTEX_INIT( &selfdestruct_cs );
1997 atexit( selfdestruct_atexit ); 2260 //atexit( selfdestruct_atexit );
1998 2261
1999 //--- 2262 //---
2000 // Linux needs SCHED_RR to change thread priorities, and that is only 2263 // Linux needs SCHED_RR to change thread priorities, and that is only
@@ -2019,7 +2282,7 @@ static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_
2019 } 2282 }
2020 #endif 2283 #endif
2021#endif 2284#endif
2022 err= init_keepers( nbKeepers); 2285 err = init_keepers( nbKeepers, _on_state_create);
2023 if (err) 2286 if (err)
2024 { 2287 {
2025 luaL_error( L, "Unable to initialize: %s", err ); 2288 luaL_error( L, "Unable to initialize: %s", err );
@@ -2044,7 +2307,17 @@ static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_
2044 2307
2045 // The host Lua state must always have a reference to this Linda object in order for our 'timer_deep_ref' to be valid. 2308 // The host Lua state must always have a reference to this Linda object in order for our 'timer_deep_ref' to be valid.
2046 // So store a reference that we will never actually use. 2309 // So store a reference that we will never actually use.
2047 lua_pushlightuserdata(L, (void *)init_once_LOCKED); 2310 // at the same time, use this object as a 'desinit' marker:
2311 // when the main lua State is closed, this object will be GC'ed
2312 {
2313 lua_newuserdata( L, 1);
2314 lua_newtable( L);
2315 lua_pushcfunction( L, selfdestruct_atexit);
2316 lua_setfield( L, -2, "__gc");
2317 lua_pushliteral( L, "AtExit");
2318 lua_setfield( L, -2, "__metatable");
2319 lua_setmetatable( L, -2);
2320 }
2048 lua_insert(L, -2); // Swap key with the Linda object 2321 lua_insert(L, -2); // Swap key with the Linda object
2049 lua_rawset(L, LUA_REGISTRYINDEX); 2322 lua_rawset(L, LUA_REGISTRYINDEX);
2050 2323
@@ -2052,15 +2325,15 @@ static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_
2052 STACK_END(L,0) 2325 STACK_END(L,0)
2053} 2326}
2054 2327
2055int 2328static volatile long s_initCount = 0;
2056#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 2329
2057__declspec(dllexport) 2330LUAG_FUNC( configure )
2058#endif
2059luaopen_lanes( lua_State *L )
2060{ 2331{
2061 static volatile int /*bool*/ go_ahead; // = 0 2332 char const* name = luaL_checkstring( L, lua_upvalueindex( 1));
2062 int const nbKeepers = luaL_optint( L, 2, 1); 2333 int const nbKeepers = luaL_optint( L, 1, 1);
2063 luaL_argcheck( L, nbKeepers > 0, 2, "Number of keeper states must be > 0"); 2334 lua_CFunction on_state_create = lua_iscfunction( L, 2) ? lua_tocfunction( L, 2) : NULL;
2335 luaL_argcheck( L, nbKeepers > 0, 1, "Number of keeper states must be > 0");
2336 luaL_argcheck( L, lua_iscfunction( L, 2) || lua_isnil( L, 2), 2, "on_state_create should be a C function");
2064 /* 2337 /*
2065 * Making one-time initializations. 2338 * Making one-time initializations.
2066 * 2339 *
@@ -2068,42 +2341,43 @@ luaopen_lanes( lua_State *L )
2068 * there is no problem. But if the host is multithreaded, we need to lock around the 2341 * there is no problem. But if the host is multithreaded, we need to lock around the
2069 * initializations. 2342 * initializations.
2070 */ 2343 */
2071#ifdef PLATFORM_WIN32 2344#if THREADAPI == THREADAPI_WINDOWS
2072 { 2345 {
2073 // TBD: Someone please replace this with reliable Win32 API code. Problem is, 2346 static volatile int /*bool*/ go_ahead; // = 0
2074 // there's no autoinitializing locks (s.a. PTHREAD_MUTEX_INITIALIZER) in 2347 if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0)
2075 // Windows so 'InterlockedIncrement' or something needs to be used. 2348 {
2076 // This is 99.9999% safe, though (and always safe if host is single-threaded) 2349 init_once_LOCKED( L, &timer_deep, nbKeepers, on_state_create);
2077 // -- AKa 24-Jun-2009
2078 //
2079 static volatile unsigned my_number; // = 0
2080
2081 if (my_number++ == 0) { // almost atomic
2082 init_once_LOCKED(L, &timer_deep, nbKeepers);
2083 go_ahead= 1; // let others pass 2350 go_ahead= 1; // let others pass
2084 } else { 2351 }
2352 else
2353 {
2085 while( !go_ahead ) { Sleep(1); } // changes threads 2354 while( !go_ahead ) { Sleep(1); } // changes threads
2086 } 2355 }
2087 } 2356 }
2088#else 2357#else // THREADAPI == THREADAPI_PTHREAD
2089 if (!go_ahead) { 2358 if( s_initCount == 0)
2359 {
2090 static pthread_mutex_t my_lock= PTHREAD_MUTEX_INITIALIZER; 2360 static pthread_mutex_t my_lock= PTHREAD_MUTEX_INITIALIZER;
2091 pthread_mutex_lock(&my_lock); 2361 pthread_mutex_lock( &my_lock);
2092 { 2362 {
2093 // Recheck now that we're within the lock 2363 // Recheck now that we're within the lock
2094 // 2364 //
2095 if (!go_ahead) { 2365 if( s_initCount == 0)
2096 init_once_LOCKED(L, &timer_deep, nbKeepers); 2366 {
2097 go_ahead= 1; 2367 init_once_LOCKED( L, &timer_deep, nbKeepers, on_state_create);
2368 s_initCount = 1;
2098 } 2369 }
2099 } 2370 }
2100 pthread_mutex_unlock(&my_lock); 2371 pthread_mutex_unlock(&my_lock);
2101 } 2372 }
2102#endif 2373#endif // THREADAPI == THREADAPI_PTHREAD
2103 assert( timer_deep != 0 ); 2374 assert( timer_deep != 0 );
2104 2375
2105 // Create main module interface table 2376 // Create main module interface table
2106 lua_newtable(L); 2377 lua_pushvalue( L, lua_upvalueindex( 2));
2378 // remove configure() (this function) from the module interface
2379 lua_pushnil( L);
2380 lua_setfield( L, -2, "configure");
2107 luaL_register(L, NULL, lanes_functions); 2381 luaL_register(L, NULL, lanes_functions);
2108 2382
2109 // metatable for threads 2383 // metatable for threads
@@ -2124,7 +2398,7 @@ luaopen_lanes( lua_State *L )
2124 lua_setfield( L, -2, "join"); 2398 lua_setfield( L, -2, "join");
2125 lua_pushcfunction( L, LG_thread_cancel); 2399 lua_pushcfunction( L, LG_thread_cancel);
2126 lua_setfield( L, -2, "cancel"); 2400 lua_setfield( L, -2, "cancel");
2127 lua_pushboolean( L, 0); 2401 lua_pushliteral( L, "Lane");
2128 lua_setfield( L, -2, "__metatable"); 2402 lua_setfield( L, -2, "__metatable");
2129 2403
2130 lua_pushcclosure( L, LG_thread_new, 1 ); // metatable as closure param 2404 lua_pushcclosure( L, LG_thread_new, 1 ); // metatable as closure param
@@ -2142,8 +2416,42 @@ luaopen_lanes( lua_State *L )
2142 lua_pushlightuserdata( L, CANCEL_ERROR ); 2416 lua_pushlightuserdata( L, CANCEL_ERROR );
2143 lua_setfield(L, -2, "cancel_error"); 2417 lua_setfield(L, -2, "cancel_error");
2144 2418
2145 // Return the local module table 2419 // register all native functions found in that module in the transferable functions database
2146 return 1; 2420 // we process it before _G because we don't want to find the module when scanning _G (this would generate longer names)
2421 populate_func_lookup_table( L, -1, name);
2422 // record all existing C/JIT-fast functions
2423 populate_func_lookup_table( L, LUA_GLOBALSINDEX, NULL);
2424 // Return nothing
2425 lua_pop( L, 1);
2426 return 0;
2427}
2428
2429int
2430#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
2431__declspec(dllexport)
2432#endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
2433luaopen_lanes( lua_State *L )
2434{
2435 // Create main module interface table
2436 // we only have 1 closure, which must be called to configure Lanes
2437 STACK_GROW( L, 3);
2438 STACK_CHECK( L)
2439 lua_newtable(L);
2440 lua_pushvalue(L, 1); // module name
2441 lua_pushvalue(L, -2); // module table
2442 lua_pushcclosure( L, LG_configure, 2);
2443 if( s_initCount == 0)
2444 {
2445 lua_setfield( L, -2, "configure");
2446 }
2447 else // already initialized: call it immediately and be done
2448 {
2449 lua_pushinteger( L, 666); // any value will do, it will be ignored
2450 lua_pushnil( L); // almost idem
2451 lua_call( L, 2, 0);
2452 }
2453 STACK_END( L, 1)
2454 return 1;
2147} 2455}
2148 2456
2149 2457