summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES13
-rw-r--r--docs/index.html27
-rw-r--r--src/keeper.c57
-rw-r--r--src/keeper.h2
-rw-r--r--src/lanes.c371
-rw-r--r--src/lanes.lua18
-rw-r--r--src/tools.c249
-rw-r--r--src/tools.h20
-rw-r--r--tests/basic.lua38
-rw-r--r--tests/keeper.lua3
-rw-r--r--tests/linda_perf.lua5
11 files changed, 489 insertions, 314 deletions
diff --git a/CHANGES b/CHANGES
index 6d44716..52ec52d 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,16 @@
1CHANGES: 1CHANGES:
2 2
3CHANGE 55: BGe 24-Jan-13
4 * version 3.4.3
5 * raise an error if lane generator libs specification contains a lib more than once
6 * bit32 is a valid lib name in the libs specification (silently ignored by the Lua 5.1 build)
7 * improved lanes.nameof to search inside table- and userdata- metatables for an object's name
8 * fixed an unwarranted error when trying to discover a function name upon a failed transfer
9 * contents of package.[path,cpath,preload,loaders|searchers] are pulled *only once* inside keeper states at initialisation
10 * Lua function upvalues equal to the global environment aren't copied by value, but bound to the destination's global environment
11 especially useful for Lua 5.2 _ENV
12 * fixed loading of base libraries that didn't create the global tables when built for Lua 5.2
13
3CHANGE 54: BGe 10-Jan-13 14CHANGE 54: BGe 10-Jan-13
4 * version 3.4.2 15 * version 3.4.2
5 * Don't pull "package" settings in the timer lane 16 * Don't pull "package" settings in the timer lane
@@ -92,7 +103,7 @@ CHANGE 35 BGe 17-Feb-2012
92 103
93CHANGE 34 BGe 14-Nov-2011 104CHANGE 34 BGe 14-Nov-2011
94 * removed packagepath and packagecpath options, replaced by a package table, whose fields path, cpath, loaders, preload are transfered 105 * removed packagepath and packagecpath options, replaced by a package table, whose fields path, cpath, loaders, preload are transfered
95 * code cleanup to facilitate transition between WIN32 and PTHREAD impleentations 106 * code cleanup to facilitate transition between WIN32 and PTHREAD implementations
96 * tentative fix for desinit crashes when free running lanes are killed at process shutdown 107 * tentative fix for desinit crashes when free running lanes are killed at process shutdown
97 108
98CHANGE 33 BGe 5-Nov-2011: Lanes version 3.0-beta 109CHANGE 33 BGe 5-Nov-2011: Lanes version 3.0-beta
diff --git a/docs/index.html b/docs/index.html
index 4d11371..8188fe9 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -63,13 +63,13 @@
63 <font size="-1"> 63 <font size="-1">
64 <p> 64 <p>
65 <br> 65 <br>
66 <i>Copyright &copy; 2007-12 Asko Kauppi, Benoit Germain. All rights reserved.</i> 66 <i>Copyright &copy; 2007-13 Asko Kauppi, Benoit Germain. All rights reserved.</i>
67 <br> 67 <br>
68 Lua Lanes is published under the same <a href="http://en.wikipedia.org/wiki/MIT_License">MIT license</a> as Lua 5.1 and 5.2. 68 Lua Lanes is published under the same <a href="http://en.wikipedia.org/wiki/MIT_License">MIT license</a> as Lua 5.1 and 5.2.
69 </p> 69 </p>
70 70
71 <p> 71 <p>
72 This document was revised on 10-Jan-13, and applies to version <tt>3.4.2</tt>. 72 This document was revised on 24-Jan-13, and applies to version <tt>3.4.3</tt>.
73 </p> 73 </p>
74 </font> 74 </font>
75 </center> 75 </center>
@@ -246,7 +246,7 @@
246 246
247 <tr valign=top> 247 <tr valign=top>
248 <td> 248 <td>
249 <code>.on_create_state</code> 249 <code>.on_state_create</code>
250 </td> 250 </td>
251 <td> 251 <td>
252 C function/<tt>nil</tt> 252 C function/<tt>nil</tt>
@@ -415,7 +415,7 @@
415 </td> 415 </td>
416 <td/> 416 <td/>
417 <td> 417 <td>
418 all standard libraries (including those specific to LuaJIT and not listed above) 418 All standard libraries (including those specific to LuaJIT and not listed above). This must be used alone.
419 </td> 419 </td>
420 </tr> 420 </tr>
421 </table> 421 </table>
@@ -487,9 +487,13 @@
487 </td> 487 </td>
488 <td> table</td> 488 <td> table</td>
489 <td> 489 <td>
490 Introduced at version 3.0.
491 <br>
490 Specifying it when <code>libs_str</code> doesn't cause the <code>package</code> library to be loaded will generate an error. 492 Specifying it when <code>libs_str</code> doesn't cause the <code>package</code> library to be loaded will generate an error.
491 <br> 493 <br>
492 If not specified, the created lane will receive the current values of <tt>package</tt>. Only <tt>path</tt>, <tt>cpath</tt>, <tt>preload</tt> and <tt>loaders</tt> (Lua 5.1)/<tt>searchers</tt> (Lua 5.2) are transfered. 494 If not specified, the created lane will receive the current values of <tt>package</tt>. Only <tt>path</tt>, <tt>cpath</tt>, <tt>preload</tt> and <tt>loaders</tt> (Lua 5.1)/<tt>searchers</tt> (Lua 5.2) are transfered.
495 <br>
496 IMPORTANT: The contents of whatever package table is actually provided to the lane won't be known to the keeper states: they will stick to whatever was found in the main state's package table when Lane was required.
493 </td> 497 </td>
494 </tr> 498 </tr>
495 </table> 499 </table>
@@ -1119,12 +1123,17 @@ events to a common Linda, but... :).</font>
1119 </ul> 1123 </ul>
1120 </li> 1124 </li>
1121 <li> 1125 <li>
1126 Lua 5.2 functions may have a special <tt>_ENV</tt> upvalue if they perform 'global namespace' lookups. Unless special care is taken, this upvalue defaults to the table found at <tt>LUA_RIDX_GLOBALS</tt>.
1127 Obviously, we don't want to transfer the whole global table along with each Lua function. Therefore, any upvalue equal to the global table is not transfered by value, but simply bound
1128 to the global table in the destination state. Note that this also applies when Lanes is built for Lua 5.1, as it doesn't hurt.
1129 </li>
1130 <li>
1122 Full userdata can be passed only if it's prepared using the <a href="#deep_userdata">deep userdata</a> system, which handles its lifespan management 1131 Full userdata can be passed only if it's prepared using the <a href="#deep_userdata">deep userdata</a> system, which handles its lifespan management
1123 <ul> 1132 <ul>
1124 <li>In particular, lane handles cannot be passed between lanes.</li> 1133 <li>In particular, lane handles cannot be passed between lanes.</li>
1125 </ul> 1134 </ul>
1126 </li> 1135 </li>
1127 <li>Coroutines cannot be passed. A coroutine's Lua state is tied to the Lua state that created it, and there is no way the mixed C/Lua stack of a couroutine can be transfered from one Lua state to another.</li> 1136 <li>Coroutines cannot be passed. A coroutine's Lua state is tied to the Lua state that created it, and there is no way the mixed C/Lua stack of a coroutine can be transfered from one Lua state to another.</li>
1128 </ul> 1137 </ul>
1129</p> 1138</p>
1130 1139
@@ -1158,7 +1167,7 @@ events to a common Linda, but... :).</font>
1158 // expects a C function on top of the source Lua stack 1167 // expects a C function on top of the source Lua stack
1159 copy_func( lua_State *dest, lua_State* source) 1168 copy_func( lua_State *dest, lua_State* source)
1160 { 1169 {
1161 // extract C function pointer from source 1170 // fetch function 'name' from source lookup database
1162 char const* funcname = lookup_func_name( source, -1); 1171 char const* funcname = lookup_func_name( source, -1);
1163 // lookup a function bound to this name in the destination state, and push it on the stack 1172 // lookup a function bound to this name in the destination state, and push it on the stack
1164 push_resolved_func( dest, funcname); 1173 push_resolved_func( dest, funcname);
@@ -1200,14 +1209,14 @@ events to a common Linda, but... :).</font>
1200 <li> 1209 <li>
1201 Lua 5.2 introduced a hash randomizer seed which causes table iteration to yield a different key order on different VMs even when the tables are populated the exact same way. 1210 Lua 5.2 introduced a hash randomizer seed which causes table iteration to yield a different key order on different VMs even when the tables are populated the exact same way.
1202 When Lua is built with compatibility options (such as LUA_COMPAT_ALL), this causes several base libraries to register functions under multiple names. 1211 When Lua is built with compatibility options (such as LUA_COMPAT_ALL), this causes several base libraries to register functions under multiple names.
1203 This, with the randomizer, can cause the first name of a function to be different on different VMs, which breaks function transfer. 1212 This, with the randomizer, can cause the first encountered name of a function to be different on different VMs, which breaks function transfer.
1204 <b>This means that Lua 5.2 must be built WITHOUT compatibility options to be able to use Lanes.</b> 1213 <b>This means that Lua 5.2 must be built WITHOUT compatibility options to be able to use Lanes.</b>
1205 Even under Lua 5.1, this may cause trouble (even if this would be much less frequent). 1214 Even under Lua 5.1, this may cause trouble (even if this would be much less frequent).
1206 Unfortunately, this fails with <tt>string.gfind</tt>/<tt>string.gmatch</tt> when Lua 5.1 is built with <tt>LUA_COMPAT_GFIND</tt> (which is the case of LuaBinaries), 1215 Unfortunately, we get bitten by <tt>string.gfind</tt>/<tt>string.gmatch</tt> when Lua 5.1 is built with <tt>LUA_COMPAT_GFIND</tt> (which is the case of LuaBinaries),
1207 so for the time being, Lanes fails only for Lua 5.2 as the randomizer is the real show breaker here. 1216 so for the time being, Lanes fails only for Lua 5.2 as the randomizer is the real show breaker here.
1208 </li> 1217 </li>
1209 </ul> 1218 </ul>
1210 Another more direct reason of failed transfer is that the destination state doesn't know about the C function that has to be transferred. This occurs if a function is transferred in a lane before it had a chance to scan the module. 1219 Another more immediate reason of failed transfer is when the destination state doesn't know about the C function that has to be transferred. This occurs if a function is transferred in a lane before it had a chance to scan the module.
1211 If the C function is sent through a linda, it is enough for the destination lane body to have required the module before the function is sent. 1220 If the C function is sent through a linda, it is enough for the destination lane body to have required the module before the function is sent.
1212 But if the lane body provided to the generator has a C function as upvalue, the transfer itself must succeed, therefore the module that imported that C function must be required in the destination lane before the lane body starts executing. This is where the <a href = "#.required"><tt>.required</tt></a> options play their role. 1221 But if the lane body provided to the generator has a C function as upvalue, the transfer itself must succeed, therefore the module that imported that C function must be required in the destination lane before the lane body starts executing. This is where the <a href = "#.required"><tt>.required</tt></a> options play their role.
1213</p> 1222</p>
diff --git a/src/keeper.c b/src/keeper.c
index 0be4fd3..a7c8647 100644
--- a/src/keeper.c
+++ b/src/keeper.c
@@ -557,7 +557,7 @@ void close_keepers( void)
557* unclosed, because it does not really matter. In production code, this 557* unclosed, because it does not really matter. In production code, this
558* function never fails. 558* function never fails.
559*/ 559*/
560char const* init_keepers( int const _nbKeepers, lua_CFunction _on_state_create) 560char const* init_keepers( lua_State* L, int const _nbKeepers, lua_CFunction _on_state_create)
561{ 561{
562 int i; 562 int i;
563 assert( _nbKeepers >= 1); 563 assert( _nbKeepers >= 1);
@@ -565,15 +565,16 @@ char const* init_keepers( int const _nbKeepers, lua_CFunction _on_state_create)
565 GKeepers = malloc( _nbKeepers * sizeof( struct s_Keeper)); 565 GKeepers = malloc( _nbKeepers * sizeof( struct s_Keeper));
566 for( i = 0; i < _nbKeepers; ++ i) 566 for( i = 0; i < _nbKeepers; ++ i)
567 { 567 {
568
569 // We need to load all base libraries in the keeper states so that the transfer databases are populated properly 568 // We need to load all base libraries in the keeper states so that the transfer databases are populated properly
570 // 569 //
571 // 'io' for debugging messages, 'package' because we need to require modules exporting idfuncs 570 // 'io' for debugging messages, 'package' because we need to require modules exporting idfuncs
572 // the others because they export functions that we may store in a keeper for transfer between lanes 571 // the others because they export functions that we may store in a keeper for transfer between lanes
573 lua_State* K = luaG_newstate( "*", _on_state_create); 572 lua_State* K = luaG_newstate( "*", _on_state_create);
574 if (!K) 573 if( !K)
575 return "out of memory"; 574 return "out of memory";
576 575
576 DEBUGSPEW_CODE( fprintf( stderr, "init_keepers %d\n", i));
577
577 STACK_CHECK( K) 578 STACK_CHECK( K)
578 // to see VM name in Decoda debugger 579 // to see VM name in Decoda debugger
579 lua_pushliteral( K, "Keeper #"); 580 lua_pushliteral( K, "Keeper #");
@@ -581,6 +582,11 @@ char const* init_keepers( int const _nbKeepers, lua_CFunction _on_state_create)
581 lua_concat( K, 2); 582 lua_concat( K, 2);
582 lua_setglobal( K, "decoda_name"); 583 lua_setglobal( K, "decoda_name");
583 584
585 // replace default 'package' contents with stuff gotten from the master state
586 lua_getglobal( L, "package");
587 luaG_inter_copy_package( L, K, -1);
588 lua_pop( L, 1);
589
584#if KEEPER_MODEL == KEEPER_MODEL_C 590#if KEEPER_MODEL == KEEPER_MODEL_C
585 // create the fifos table in the keeper state 591 // create the fifos table in the keeper state
586 lua_pushlightuserdata( K, fifos_key); 592 lua_pushlightuserdata( K, fifos_key);
@@ -589,7 +595,7 @@ char const* init_keepers( int const _nbKeepers, lua_CFunction _on_state_create)
589#endif // KEEPER_MODEL == KEEPER_MODEL_C 595#endif // KEEPER_MODEL == KEEPER_MODEL_C
590 596
591#if KEEPER_MODEL == KEEPER_MODEL_LUA 597#if KEEPER_MODEL == KEEPER_MODEL_LUA
592 // use package.loaders[2] to find keeper microcode 598 // use package.loaders[2] to find keeper microcode (NOTE: this works only if nobody tampered with the loaders table...)
593 lua_getglobal( K, "package"); // package 599 lua_getglobal( K, "package"); // package
594 lua_getfield( K, -1, "loaders"); // package package.loaders 600 lua_getfield( K, -1, "loaders"); // package package.loaders
595 lua_rawgeti( K, -1, 2); // package package.loaders package.loaders[2] 601 lua_rawgeti( K, -1, 2); // package package.loaders package.loaders[2]
@@ -619,55 +625,38 @@ char const* init_keepers( int const _nbKeepers, lua_CFunction _on_state_create)
619} 625}
620 626
621// cause each keeper state to populate its database of transferable functions with those from the specified module 627// cause each keeper state to populate its database of transferable functions with those from the specified module
622void populate_keepers( lua_State *L) 628// do do this we simply require the module inside the keeper state, then populate the lookup database
629void populate_keepers( lua_State* L)
623{ 630{
624 size_t name_len; 631 size_t name_len;
625 char const *name = luaL_checklstring( L, -1, &name_len); 632 char const* name = luaL_checklstring( L, -1, &name_len);
626 size_t package_path_len;
627 char const *package_path;
628 size_t package_cpath_len;
629 char const *package_cpath;
630 int i; 633 int i;
631 634
632 // we need to make sure that package.path & package.cpath are the same in the keepers 635 STACK_CHECK( L)
633// than what is currently in use when the module is required in the caller's Lua state
634 STACK_CHECK(L)
635 STACK_GROW( L, 3); 636 STACK_GROW( L, 3);
636 lua_getglobal( L, "package");
637 lua_getfield( L, -1, "path");
638 package_path = luaL_checklstring( L, -1, &package_path_len);
639 lua_getfield( L, -2, "cpath");
640 package_cpath = luaL_checklstring( L, -1, &package_cpath_len);
641 637
642 for( i = 0; i < GNbKeepers; ++ i) 638 for( i = 0; i < GNbKeepers; ++ i)
643 { 639 {
644 lua_State *K = GKeepers[i].L; 640 lua_State* K = GKeepers[i].L;
645 int res; 641 int res;
646 MUTEX_LOCK( &GKeepers[i].lock_); 642 MUTEX_LOCK( &GKeepers[i].lock_);
647 STACK_CHECK(K) 643 STACK_CHECK( K)
648 STACK_GROW( K, 2); 644 STACK_GROW( K, 2);
649 lua_getglobal( K, "package");
650 lua_pushlstring( K, package_path, package_path_len);
651 lua_setfield( K, -2, "path");
652 lua_pushlstring( K, package_cpath, package_cpath_len);
653 lua_setfield( K, -2, "cpath");
654 lua_pop( K, 1);
655 lua_getglobal( K, "require"); 645 lua_getglobal( K, "require");
656 lua_pushlstring( K, name, name_len); 646 lua_pushlstring( K, name, name_len);
657 res = lua_pcall( K, 1, 0, 0); 647 res = lua_pcall( K, 1, 0, 0);
658 if( res != 0) 648 if( res != 0)
659 { 649 {
660 char const *err = luaL_checkstring( K, -1); 650 char const* err = luaL_checkstring( K, -1);
661 luaL_error( L, "error requiring '%s' in keeper state: %s", name, err); 651 luaL_error( L, "error requiring '%s' in keeper state: %s", name, err);
662 } 652 }
663 STACK_END(K, 0) 653 STACK_END( K, 0)
664 MUTEX_UNLOCK( &GKeepers[i].lock_); 654 MUTEX_UNLOCK( &GKeepers[i].lock_);
665 } 655 }
666 lua_pop( L, 3); 656 STACK_END( L, 0)
667 STACK_END(L, 0)
668} 657}
669 658
670struct s_Keeper *keeper_acquire( const void *ptr) 659struct s_Keeper* keeper_acquire( void const* ptr)
671{ 660{
672 // can be 0 if this happens during main state shutdown (lanes is being GC'ed -> no keepers) 661 // can be 0 if this happens during main state shutdown (lanes is being GC'ed -> no keepers)
673 if( GNbKeepers == 0) 662 if( GNbKeepers == 0)
@@ -691,19 +680,19 @@ struct s_Keeper *keeper_acquire( const void *ptr)
691 } 680 }
692} 681}
693 682
694void keeper_release( struct s_Keeper *K) 683void keeper_release( struct s_Keeper* K)
695{ 684{
696 //-- K->count; 685 //-- K->count;
697 if( K) MUTEX_UNLOCK( &K->lock_); 686 if( K) MUTEX_UNLOCK( &K->lock_);
698} 687}
699 688
700void keeper_toggle_nil_sentinels( lua_State *L, int _val_i, int _nil_to_sentinel) 689void keeper_toggle_nil_sentinels( lua_State* L, int _val_i, int _nil_to_sentinel)
701{ 690{
702 int i, n = lua_gettop( L); 691 int i, n = lua_gettop( L);
703 /* We could use an empty table in 'keeper.lua' as the sentinel, but maybe 692 /* We could use an empty table in 'keeper.lua' as the sentinel, but maybe
704 * checking for a lightuserdata is faster. (any unique value will do -> take the address of some global of ours) 693 * checking for a lightuserdata is faster. (any unique value will do -> take the address of some global of ours)
705 */ 694 */
706 void *nil_sentinel = &GNbKeepers; 695 void* nil_sentinel = &GNbKeepers;
707 for( i = _val_i; i <= n; ++ i) 696 for( i = _val_i; i <= n; ++ i)
708 { 697 {
709 if( _nil_to_sentinel) 698 if( _nil_to_sentinel)
diff --git a/src/keeper.h b/src/keeper.h
index decae4a..15a5a41 100644
--- a/src/keeper.h
+++ b/src/keeper.h
@@ -13,7 +13,7 @@ struct s_Keeper
13// problem: maybe on some platforms (linux) atexit() is called after DLL/so are unloaded... 13// problem: maybe on some platforms (linux) atexit() is called after DLL/so are unloaded...
14#define HAVE_KEEPER_ATEXIT_DESINIT 0 14#define HAVE_KEEPER_ATEXIT_DESINIT 0
15 15
16char const* init_keepers( int const _nbKeepers, lua_CFunction _on_state_create); 16char const* init_keepers( lua_State* L, int const _nbKeepers, lua_CFunction _on_state_create);
17#if !HAVE_KEEPER_ATEXIT_DESINIT 17#if !HAVE_KEEPER_ATEXIT_DESINIT
18void close_keepers( void); 18void close_keepers( void);
19#endif // HAVE_KEEPER_ATEXIT_DESINIT 19#endif // HAVE_KEEPER_ATEXIT_DESINIT
diff --git a/src/lanes.c b/src/lanes.c
index 8a67621..6fec951 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -52,13 +52,13 @@
52 * ... 52 * ...
53 */ 53 */
54 54
55char const* VERSION = "3.4.2"; 55char const* VERSION = "3.4.3";
56 56
57/* 57/*
58=============================================================================== 58===============================================================================
59 59
60Copyright (C) 2007-10 Asko Kauppi <akauppi@gmail.com> 60Copyright (C) 2007-10 Asko Kauppi <akauppi@gmail.com>
61 2011-12 Benoit Germain <bnt.germain@gmail.com> 61 2011-13 Benoit Germain <bnt.germain@gmail.com>
62 62
63Permission is hereby granted, free of charge, to any person obtaining a copy 63Permission is hereby granted, free of charge, to any person obtaining a copy
64of this software and associated documentation files (the "Software"), to deal 64of this software and associated documentation files (the "Software"), to deal
@@ -1114,7 +1114,8 @@ static int run_finalizers( lua_State*L, int lua_rc )
1114 // 1114 //
1115 // LUA_ERRRUN / LUA_ERRMEM 1115 // LUA_ERRRUN / LUA_ERRMEM
1116 1116
1117 if (rc!=0) { 1117 if( rc != LUA_OK)
1118 {
1118 // [-1]: error message 1119 // [-1]: error message
1119 // 1120 //
1120 // If one finalizer fails, don't run the others. Return this 1121 // If one finalizer fails, don't run the others. Return this
@@ -1269,7 +1270,7 @@ static bool_t selfdestruct_remove( struct s_lane *s )
1269// Initialized by 'init_once_LOCKED()': the deep userdata Linda object 1270// Initialized by 'init_once_LOCKED()': the deep userdata Linda object
1270// used for timers (each lane will get a proxy to this) 1271// used for timers (each lane will get a proxy to this)
1271// 1272//
1272volatile DEEP_PRELUDE *timer_deep; // = NULL 1273volatile DEEP_PRELUDE* timer_deep; // = NULL
1273 1274
1274/* 1275/*
1275* Process end; cancel any still free-running threads 1276* Process end; cancel any still free-running threads
@@ -1349,7 +1350,7 @@ static int selfdestruct_gc( lua_State*L)
1349 t_now = now_secs(); 1350 t_now = now_secs();
1350 if( n == 0 || ( t_now >= t_until)) 1351 if( n == 0 || ( t_now >= t_until))
1351 { 1352 {
1352 DEBUGEXEC(fprintf( stderr, "%d uncancelled lane(s) remain after waiting %fs at process end.\n", n, shutdown_timeout - (t_until - t_now))); 1353 DEBUGSPEW_CODE( fprintf( stderr, "%d uncancelled lane(s) remain after waiting %fs at process end.\n", n, shutdown_timeout - (t_until - t_now)));
1353 break; 1354 break;
1354 } 1355 }
1355 } 1356 }
@@ -1379,7 +1380,7 @@ static int selfdestruct_gc( lua_State*L)
1379//we want to free memory and such when we exit. 1380//we want to free memory and such when we exit.
1380 // 2.0.2: at least timer lane is still here 1381 // 2.0.2: at least timer lane is still here
1381 // 1382 //
1382 DEBUGEXEC(fprintf( stderr, "Left %d lane(s) with cancel request at process end.\n", n )); 1383 DEBUGSPEW_CODE( fprintf( stderr, "Left %d lane(s) with cancel request at process end.\n", n ));
1383 n=0; 1384 n=0;
1384#else 1385#else
1385 // first thing we did was to raise the linda signals the threads were waiting on (if any) 1386 // first thing we did was to raise the linda signals the threads were waiting on (if any)
@@ -1409,7 +1410,7 @@ static int selfdestruct_gc( lua_State*L)
1409 } 1410 }
1410 MUTEX_UNLOCK( &selfdestruct_cs ); 1411 MUTEX_UNLOCK( &selfdestruct_cs );
1411 1412
1412 DEBUGEXEC(fprintf( stderr, "Killed %d lane(s) at process end.\n", n )); 1413 DEBUGSPEW_CODE( fprintf( stderr, "Killed %d lane(s) at process end.\n", n));
1413#endif 1414#endif
1414 } 1415 }
1415#if !HAVE_KEEPER_ATEXIT_DESINIT 1416#if !HAVE_KEEPER_ATEXIT_DESINIT
@@ -1654,6 +1655,39 @@ LUAG_FUNC( set_debug_threadname)
1654 return 0; 1655 return 0;
1655} 1656}
1656 1657
1658#if USE_DEBUG_SPEW
1659// can't use direct LUA_x errcode indexing because the sequence is not the same between Lua 5.1 and 5.2 :-(
1660// LUA_ERRERR doesn't have the same value
1661struct errcode_name
1662{
1663 int code;
1664 char const* name;
1665};
1666
1667static struct errcode_name s_errcodes[] =
1668{
1669 { LUA_OK, "LUA_OK"},
1670 { LUA_YIELD, "LUA_YIELD"},
1671 { LUA_ERRRUN, "LUA_ERRRUN"},
1672 { LUA_ERRSYNTAX, "LUA_ERRSYNTAX"},
1673 { LUA_ERRMEM, "LUA_ERRMEM"},
1674 { LUA_ERRGCMM, "LUA_ERRGCMM"},
1675 { LUA_ERRERR, "LUA_ERRERR"},
1676};
1677static char const* get_errcode_name( int _code)
1678{
1679 int i;
1680 for( i = 0; i < 7; ++ i)
1681 {
1682 if( s_errcodes[i].code == _code)
1683 {
1684 return s_errcodes[i].name;
1685 }
1686 }
1687 return "<NULL>";
1688}
1689#endif // USE_DEBUG_SPEW
1690
1657//--- 1691//---
1658static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) 1692static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1659{ 1693{
@@ -1713,7 +1747,8 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1713 // Lua 5.1 error handler is limited to one return value; taking stack trace 1747 // Lua 5.1 error handler is limited to one return value; taking stack trace
1714 // via registry 1748 // via registry
1715 // 1749 //
1716 if (rc!=0) { 1750 if( rc != 0)
1751 {
1717 STACK_GROW(L,1); 1752 STACK_GROW(L,1);
1718 lua_pushlightuserdata( L, STACK_TRACE_KEY ); 1753 lua_pushlightuserdata( L, STACK_TRACE_KEY );
1719 lua_gettable(L, LUA_REGISTRYINDEX); 1754 lua_gettable(L, LUA_REGISTRYINDEX);
@@ -1733,16 +1768,19 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1733 // [2..top]: parameters 1768 // [2..top]: parameters
1734 // 1769 //
1735 rc= lua_pcall( L, lua_gettop(L)-1, LUA_MULTRET, 0 /*no error handler*/ ); 1770 rc= lua_pcall( L, lua_gettop(L)-1, LUA_MULTRET, 0 /*no error handler*/ );
1736 // 0: no error 1771 // LUA_OK(0): no error
1737 // LUA_ERRRUN: a runtime error (error pushed on stack) 1772 // LUA_ERRRUN(2): a runtime error (error pushed on stack)
1738 // LUA_ERRMEM: memory allocation error 1773 // LUA_ERRMEM(4): memory allocation error
1739#endif 1774#endif
1740 1775
1741//STACK_DUMP(L); 1776 DEBUGSPEW_CODE( fprintf( stderr, "Lane %p body: %s\n", L, get_errcode_name( rc)));
1777 //STACK_DUMP(L);
1742 // Call finalizers, if the script has set them up. 1778 // Call finalizers, if the script has set them up.
1743 // 1779 //
1744 rc2= run_finalizers(L,rc); 1780 rc2 = run_finalizers( L, rc);
1745 if (rc2!=0) { 1781 DEBUGSPEW_CODE( fprintf( stderr, "Lane %p finalizer: %s\n", L, get_errcode_name( rc2)));
1782 if( rc2 != LUA_OK)
1783 {
1746 // Error within a finalizer! 1784 // Error within a finalizer!
1747 // 1785 //
1748 // [-1]: error message 1786 // [-1]: error message
@@ -1766,7 +1804,6 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1766 s->L = L = 0; 1804 s->L = L = 0;
1767 1805
1768 lane_cleanup( s); 1806 lane_cleanup( s);
1769
1770 } 1807 }
1771 else 1808 else
1772 { 1809 {
@@ -1809,10 +1846,10 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1809 1846
1810// helper function to require a module in the keeper states and in the target state 1847// helper function to require a module in the keeper states and in the target state
1811// source state contains module name at the top of the stack 1848// source state contains module name at the top of the stack
1812static void require_one_module( lua_State*L, lua_State*L2, bool_t _fatal) 1849static void require_one_module( lua_State* L, lua_State* L2, bool_t _fatal)
1813{ 1850{
1814 size_t len; 1851 size_t len;
1815 char const *name = lua_tolstring( L, -1, &len); 1852 char const* name = lua_tolstring( L, -1, &len);
1816 // require the module in the target lane 1853 // require the module in the target lane
1817 STACK_GROW( L2, 2); 1854 STACK_GROW( L2, 2);
1818 lua_getglobal( L2, "require"); 1855 lua_getglobal( L2, "require");
@@ -1872,39 +1909,11 @@ LUAG_FUNC( thread_new )
1872 1909
1873 ASSERT_L( lua_gettop(L2) == 0); 1910 ASSERT_L( lua_gettop(L2) == 0);
1874 1911
1875 // package.path 1912 // package
1876 STACK_CHECK(L)
1877 STACK_CHECK(L2)
1878 if( package) 1913 if( package)
1879 { 1914 {
1880 if( lua_type( L, package) != LUA_TTABLE) 1915 luaG_inter_copy_package( L, L2, package);
1881 {
1882 return luaL_error( L, "expected package as table, got %s", luaL_typename( L, package));
1883 }
1884 lua_getglobal( L2, "package");
1885 if( !lua_isnil( L2, -1)) // package library not loaded: do nothing
1886 {
1887 int i;
1888 // package.loaders is renamed package.searchers in Lua 5.2
1889 char const* entries[] = { "path", "cpath", "preload", (LUA_VERSION_NUM == 501) ? "loaders" : "searchers", NULL};
1890 for( i = 0; entries[i]; ++ i)
1891 {
1892 lua_getfield( L, package, entries[i]);
1893 if( lua_isnil( L, -1))
1894 {
1895 lua_pop( L, 1);
1896 }
1897 else
1898 {
1899 luaG_inter_move( L, L2, 1); // moves the entry to L2
1900 lua_setfield( L2, -2, entries[i]); // set package[entries[i]]
1901 }
1902 }
1903 }
1904 lua_pop( L2, 1);
1905 } 1916 }
1906 STACK_END(L2,0)
1907 STACK_END(L,0)
1908 1917
1909 // modules to require in the target lane *before* the function is transfered! 1918 // modules to require in the target lane *before* the function is transfered!
1910 1919
@@ -1924,14 +1933,14 @@ LUAG_FUNC( thread_new )
1924 { 1933 {
1925 int nbRequired = 1; 1934 int nbRequired = 1;
1926 // should not happen, was checked in lanes.lua before calling thread_new() 1935 // should not happen, was checked in lanes.lua before calling thread_new()
1927 if (lua_type(L, required) != LUA_TTABLE) 1936 if( lua_type( L, required) != LUA_TTABLE)
1928 { 1937 {
1929 return luaL_error( L, "expected required module list as a table, got %s", luaL_typename( L, required)); 1938 return luaL_error( L, "expected required module list as a table, got %s", luaL_typename( L, required));
1930 } 1939 }
1931 lua_pushnil( L); 1940 lua_pushnil( L);
1932 while( lua_next( L, required) != 0) 1941 while( lua_next( L, required) != 0)
1933 { 1942 {
1934 if (lua_type(L,-1) != LUA_TSTRING || lua_type(L,-2) != LUA_TNUMBER || lua_tonumber( L, -2) != nbRequired) 1943 if( lua_type( L, -1) != LUA_TSTRING || lua_type( L, -2) != LUA_TNUMBER || lua_tonumber( L, -2) != nbRequired)
1935 { 1944 {
1936 return luaL_error( L, "required module list should be a list of strings"); 1945 return luaL_error( L, "required module list should be a list of strings");
1937 } 1946 }
@@ -1949,13 +1958,13 @@ LUAG_FUNC( thread_new )
1949 // Appending the specified globals to the global environment 1958 // Appending the specified globals to the global environment
1950 // *after* stdlibs have been loaded and modules required, in case we transfer references to native functions they exposed... 1959 // *after* stdlibs have been loaded and modules required, in case we transfer references to native functions they exposed...
1951 // 1960 //
1952 if (glob!=0) 1961 if( glob != 0)
1953 { 1962 {
1954 STACK_CHECK(L) 1963 STACK_CHECK(L)
1955 STACK_CHECK(L2) 1964 STACK_CHECK(L2)
1956 if( !lua_istable( L, glob)) 1965 if( !lua_istable( L, glob))
1957 { 1966 {
1958 return luaL_error( L, "Expected table, got %s", luaL_typename(L,glob)); 1967 return luaL_error( L, "Expected table, got %s", luaL_typename( L, glob));
1959 } 1968 }
1960 1969
1961 lua_pushnil( L); 1970 lua_pushnil( L);
@@ -1987,7 +1996,7 @@ LUAG_FUNC( thread_new )
1987 } 1996 }
1988 STACK_MID(L,0) 1997 STACK_MID(L,0)
1989 } 1998 }
1990 else if( lua_type(L, 1) == LUA_TSTRING) 1999 else if( lua_type( L, 1) == LUA_TSTRING)
1991 { 2000 {
1992 // compile the string 2001 // compile the string
1993 if( luaL_loadstring( L2, lua_tostring( L, 1)) != 0) 2002 if( luaL_loadstring( L2, lua_tostring( L, 1)) != 0)
@@ -2089,7 +2098,7 @@ LUAG_FUNC( thread_gc)
2089 // Make sure a kill has proceeded, before cleaning up the data structure. 2098 // Make sure a kill has proceeded, before cleaning up the data structure.
2090 // 2099 //
2091 // NO lua_close() in this case because we don't know where execution of the state was interrupted 2100 // NO lua_close() in this case because we don't know where execution of the state was interrupted
2092 DEBUGEXEC(fprintf( stderr, "** Joining with a killed thread (needs testing) **" )); 2101 DEBUGSPEW_CODE( fprintf( stderr, "** Joining with a killed thread (needs testing) **"));
2093 // make sure the thread is no longer running, just like thread_join() 2102 // make sure the thread is no longer running, just like thread_join()
2094 if(! THREAD_ISNULL( s->thread)) 2103 if(! THREAD_ISNULL( s->thread))
2095 THREAD_WAIT( &s->thread, -1, &s->done_signal, &s->done_lock, &s->status); 2104 THREAD_WAIT( &s->thread, -1, &s->done_signal, &s->done_lock, &s->status);
@@ -2100,7 +2109,7 @@ LUAG_FUNC( thread_gc)
2100 lua_close( s->L); 2109 lua_close( s->L);
2101 s->L = 0; 2110 s->L = 0;
2102 } 2111 }
2103 DEBUGEXEC(fprintf( stderr, "** Joined ok **" )); 2112 DEBUGSPEW_CODE( fprintf( stderr, "** Joined ok **"));
2104 } 2113 }
2105 else if( s->status < DONE) 2114 else if( s->status < DONE)
2106 { 2115 {
@@ -2265,7 +2274,7 @@ LUAG_FUNC( thread_join)
2265 break; 2274 break;
2266 2275
2267 default: 2276 default:
2268 DEBUGEXEC(fprintf( stderr, "Status: %d\n", s->status)); 2277 DEBUGSPEW_CODE( fprintf( stderr, "Status: %d\n", s->status));
2269 ASSERT_L( FALSE ); ret= 0; 2278 ASSERT_L( FALSE ); ret= 0;
2270 } 2279 }
2271 lua_close( L2); 2280 lua_close( L2);
@@ -2547,9 +2556,9 @@ static const struct luaL_Reg lanes_functions [] = {
2547/* 2556/*
2548* One-time initializations 2557* One-time initializations
2549*/ 2558*/
2550static void init_once_LOCKED( lua_State* L, volatile DEEP_PRELUDE** timer_deep_ref, int const nbKeepers, lua_CFunction _on_state_create, lua_Number _shutdown_timeout, bool_t _track_lanes) 2559static void init_once_LOCKED( lua_State* L, int const nbKeepers, lua_CFunction _on_state_create, lua_Number _shutdown_timeout, bool_t _track_lanes)
2551{ 2560{
2552 const char *err; 2561 char const* err;
2553 2562
2554#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 2563#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
2555 now_secs(); // initialize 'now_secs()' internal offset 2564 now_secs(); // initialize 'now_secs()' internal offset
@@ -2604,7 +2613,7 @@ static void init_once_LOCKED( lua_State* L, volatile DEEP_PRELUDE** timer_deep_r
2604 } 2613 }
2605 #endif 2614 #endif
2606#endif 2615#endif
2607 err = init_keepers( nbKeepers, _on_state_create); 2616 err = init_keepers( L, nbKeepers, _on_state_create);
2608 if (err) 2617 if (err)
2609 { 2618 {
2610 (void) luaL_error( L, "Unable to initialize: %s", err ); 2619 (void) luaL_error( L, "Unable to initialize: %s", err );
@@ -2612,7 +2621,7 @@ static void init_once_LOCKED( lua_State* L, volatile DEEP_PRELUDE** timer_deep_r
2612 2621
2613 // Initialize 'timer_deep'; a common Linda object shared by all states 2622 // Initialize 'timer_deep'; a common Linda object shared by all states
2614 // 2623 //
2615 ASSERT_L( timer_deep_ref && (!(*timer_deep_ref)) ); 2624 ASSERT_L( timer_deep == NULL);
2616 2625
2617 STACK_CHECK(L) 2626 STACK_CHECK(L)
2618 { 2627 {
@@ -2627,8 +2636,8 @@ static void init_once_LOCKED( lua_State* L, volatile DEEP_PRELUDE** timer_deep_r
2627 2636
2628 // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer 2637 // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer
2629 // 2638 //
2630 *timer_deep_ref= * (DEEP_PRELUDE**) lua_touserdata( L, -1 ); 2639 timer_deep = * (DEEP_PRELUDE**) lua_touserdata( L, -1);
2631 ASSERT_L( (*timer_deep_ref) && (*timer_deep_ref)->refcount==1 && (*timer_deep_ref)->deep ); 2640 ASSERT_L( timer_deep && (timer_deep->refcount == 1) && timer_deep->deep);
2632 2641
2633 // The host Lua state must always have a reference to this Linda object in order for our 'timer_deep_ref' to be valid. 2642 // The host Lua state must always have a reference to this Linda object in order for our 'timer_deep_ref' to be valid.
2634 // So store a reference that we will never actually use. 2643 // So store a reference that we will never actually use.
@@ -2644,8 +2653,8 @@ static void init_once_LOCKED( lua_State* L, volatile DEEP_PRELUDE** timer_deep_r
2644 lua_setfield( L, -2, "__metatable"); 2653 lua_setfield( L, -2, "__metatable");
2645 lua_setmetatable( L, -2); 2654 lua_setmetatable( L, -2);
2646 } 2655 }
2647 lua_insert(L, -2); // Swap key with the Linda object 2656 lua_insert( L, -2); // Swap key with the Linda object
2648 lua_rawset(L, LUA_REGISTRYINDEX); 2657 lua_rawset( L, LUA_REGISTRYINDEX);
2649 2658
2650 } 2659 }
2651 STACK_END(L,0) 2660 STACK_END(L,0)
@@ -2653,107 +2662,147 @@ static void init_once_LOCKED( lua_State* L, volatile DEEP_PRELUDE** timer_deep_r
2653 2662
2654static volatile long s_initCount = 0; 2663static volatile long s_initCount = 0;
2655 2664
2656LUAG_FUNC( configure ) 2665// upvalue 1: module name
2666// upvalue 2: module table
2667LUAG_FUNC( configure)
2657{ 2668{
2658 char const* name = luaL_checkstring( L, lua_upvalueindex( 1)); 2669 char const* name = luaL_checkstring( L, lua_upvalueindex( 1));
2659 // all parameter checks are done lua-side 2670 // all parameter checks are done lua-side
2660 int const nbKeepers = (int)lua_tointeger( L, 1); 2671 int const nbKeepers = (int)lua_tointeger( L, 1);
2661 lua_CFunction on_state_create = lua_iscfunction( L, 2) ? lua_tocfunction( L, 2) : NULL; 2672 lua_CFunction on_state_create = lua_iscfunction( L, 2) ? lua_tocfunction( L, 2) : NULL;
2662 lua_Number shutdown_timeout = lua_tonumber( L, 3); 2673 lua_Number shutdown_timeout = lua_tonumber( L, 3);
2663 bool_t track_lanes = lua_toboolean( L, 4); 2674 bool_t track_lanes = lua_toboolean( L, 4);
2664 /* 2675
2665 * Making one-time initializations. 2676 STACK_CHECK( L)
2666 * 2677 // Create main module interface table
2667 * When the host application is single-threaded (and all threading happens via Lanes) 2678 lua_pushvalue( L, lua_upvalueindex( 2)); // ... M
2668 * there is no problem. But if the host is multithreaded, we need to lock around the 2679 // remove configure() (this function) from the module interface
2669 * initializations. 2680 lua_pushnil( L); // ... M nil
2670 */ 2681 lua_setfield( L, -2, "configure"); // ... M
2682 // add functions to the module's table
2683 luaG_registerlibfuncs( L, lanes_functions);
2684 STACK_MID( L, 1)
2685
2686 // metatable for threads
2687 // contains keys: { __gc, __index, cached_error, cached_tostring, cancel, join }
2688 //
2689 lua_newtable( L); // ... M mt
2690 lua_pushcfunction( L, LG_thread_gc); // ... M mt LG_thread_gc
2691 lua_setfield( L, -2, "__gc"); // ... M mt
2692 lua_pushcfunction( L, LG_thread_index); // ... M mt LG_thread_index
2693 lua_setfield( L, -2, "__index"); // ... M mt
2694 lua_getglobal( L, "error"); // ... M mt error
2695 ASSERT_L( lua_isfunction( L, -1));
2696 lua_setfield( L, -2, "cached_error"); // ... M mt
2697 lua_getglobal( L, "tostring"); // ... M mt tostring
2698 ASSERT_L( lua_isfunction( L, -1));
2699 lua_setfield( L, -2, "cached_tostring"); // ... M mt
2700 lua_pushcfunction( L, LG_thread_join); // ... M mt LG_thread_join
2701 lua_setfield( L, -2, "join"); // ... M mt
2702 lua_pushcfunction( L, LG_thread_cancel); // ... M mt LG_thread_cancel
2703 lua_setfield( L, -2, "cancel"); // ... M mt
2704 lua_pushliteral( L, "Lane"); // ... M mt "Lane"
2705 lua_setfield( L, -2, "__metatable"); // ... M mt
2706
2707 lua_pushcclosure( L, LG_thread_new, 1); // ... M LG_thread_new
2708 lua_setfield(L, -2, "thread_new"); // ... M
2709
2710 lua_pushstring(L, VERSION); // ... M VERSION
2711 lua_setfield(L, -2, "version"); // ... M
2712
2713 lua_pushinteger(L, THREAD_PRIO_MAX); // ... M THREAD_PRIO_MAX
2714 lua_setfield(L, -2, "max_prio"); // ... M
2715
2716 lua_pushlightuserdata( L, CANCEL_ERROR); // ... M CANCEL_ERROR
2717 lua_setfield(L, -2, "cancel_error"); // ... M
2718
2719 // register all native functions found in that module in the transferable functions database
2720 // we process it before _G because we don't want to find the module when scanning _G (this would generate longer names)
2721 // for example in package.loaded.lanes.core.*
2722 populate_func_lookup_table( L, -1, name);
2723
2724 // record all existing C/JIT-fast functions
2725 // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack
2726 lua_pushglobaltable( L); // ... M _G
2727 populate_func_lookup_table( L, -1, NULL);
2728 lua_pop( L, 1); // ... M
2729
2730 STACK_MID( L, 1)
2731 /*
2732 * Making one-time initializations.
2733 *
2734 * When the host application is single-threaded (and all threading happens via Lanes)
2735 * there is no problem. But if the host is multithreaded, we need to lock around the
2736 * initializations.
2737 *
2738 * we must do this after the populate_func_lookup_table is called, else populating the keepers will fail
2739 * because this makes a copy of packages.loaders, which requires the lookup tables to exist!
2740 */
2671#if THREADAPI == THREADAPI_WINDOWS 2741#if THREADAPI == THREADAPI_WINDOWS
2672 { 2742 {
2673 static volatile int /*bool*/ go_ahead; // = 0 2743 static volatile int /*bool*/ go_ahead; // = 0
2674 if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0) 2744 if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0)
2675 { 2745 {
2676 init_once_LOCKED( L, &timer_deep, nbKeepers, on_state_create, shutdown_timeout, track_lanes); 2746 init_once_LOCKED( L, nbKeepers, on_state_create, shutdown_timeout, track_lanes);
2677 go_ahead= 1; // let others pass 2747 go_ahead = 1; // let others pass
2678 } 2748 }
2679 else 2749 else
2680 { 2750 {
2681 while( !go_ahead ) { Sleep(1); } // changes threads 2751 while( !go_ahead ) { Sleep(1); } // changes threads
2682 } 2752 }
2683 } 2753 }
2684#else // THREADAPI == THREADAPI_PTHREAD 2754#else // THREADAPI == THREADAPI_PTHREAD
2685 if( s_initCount == 0) 2755 if( s_initCount == 0)
2686 { 2756 {
2687 static pthread_mutex_t my_lock= PTHREAD_MUTEX_INITIALIZER; 2757 static pthread_mutex_t my_lock = PTHREAD_MUTEX_INITIALIZER;
2688 pthread_mutex_lock( &my_lock); 2758 pthread_mutex_lock( &my_lock);
2689 { 2759 {
2690 // Recheck now that we're within the lock 2760 // Recheck now that we're within the lock
2691 // 2761 //
2692 if( s_initCount == 0) 2762 if( s_initCount == 0)
2693 { 2763 {
2694 init_once_LOCKED( L, &timer_deep, nbKeepers, on_state_create, shutdown_timeout, track_lanes); 2764 init_once_LOCKED( L, nbKeepers, on_state_create, shutdown_timeout, track_lanes);
2695 s_initCount = 1; 2765 s_initCount = 1;
2696 } 2766 }
2697 } 2767 }
2698 pthread_mutex_unlock(&my_lock); 2768 pthread_mutex_unlock( &my_lock);
2699 } 2769 }
2700#endif // THREADAPI == THREADAPI_PTHREAD 2770#endif // THREADAPI == THREADAPI_PTHREAD
2701 assert( timer_deep != 0 ); 2771 assert( timer_deep != NULL);
2702 2772 STACK_MID( L, 1)
2703 // Create main module interface table 2773
2704 lua_pushvalue( L, lua_upvalueindex( 2)); 2774 // init_once_LOCKED initializes timer_deep, so we must do this after, of course
2705 // remove configure() (this function) from the module interface 2775 luaG_push_proxy( L, linda_id, (DEEP_PRELUDE*) timer_deep); // ... M timer_deep
2706 lua_pushnil( L); 2776 lua_setfield( L, -2, "timer_gateway"); // ... M
2707 lua_setfield( L, -2, "configure"); 2777
2708 // add functions to the module's table 2778 lua_pop( L, 1); // ...
2709 luaG_registerlibfuncs(L, lanes_functions); 2779 STACK_END( L, 0)
2710 2780 // Return nothing
2711 // metatable for threads 2781 return 0;
2712 // contains keys: { __gc, __index, cached_error, cached_tostring, cancel, join } 2782}
2713 // 2783
2714 lua_newtable( L); 2784// helper to have correct callstacks when crashing a Win32 running on 64 bits Windows
2715 lua_pushcfunction( L, LG_thread_gc); 2785// don't forget to toggle Debug/Exceptions/Win32 in visual Studio too!
2716 lua_setfield( L, -2, "__gc"); 2786void EnableCrashingOnCrashes()
2717 lua_pushcfunction( L, LG_thread_index); 2787{
2718 lua_setfield( L, -2, "__index"); 2788#if 0 && defined PLATFORM_WIN32
2719 lua_getglobal( L, "error"); 2789 typedef BOOL (WINAPI *tGetPolicy)(LPDWORD lpFlags);
2720 ASSERT_L( lua_isfunction( L, -1)); 2790 typedef BOOL (WINAPI *tSetPolicy)(DWORD dwFlags);
2721 lua_setfield( L, -2, "cached_error"); 2791 const DWORD EXCEPTION_SWALLOWING = 0x1;
2722 lua_getglobal( L, "tostring"); 2792
2723 ASSERT_L( lua_isfunction( L, -1)); 2793 HMODULE kernel32 = LoadLibraryA("kernel32.dll");
2724 lua_setfield( L, -2, "cached_tostring"); 2794 tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32, "GetProcessUserModeExceptionPolicy");
2725 lua_pushcfunction( L, LG_thread_join); 2795 tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32, "SetProcessUserModeExceptionPolicy");
2726 lua_setfield( L, -2, "join"); 2796 if (pGetPolicy && pSetPolicy)
2727 lua_pushcfunction( L, LG_thread_cancel); 2797 {
2728 lua_setfield( L, -2, "cancel"); 2798 DWORD dwFlags;
2729 lua_pushliteral( L, "Lane"); 2799 if (pGetPolicy(&dwFlags))
2730 lua_setfield( L, -2, "__metatable"); 2800 {
2731 2801 // Turn off the filter
2732 lua_pushcclosure( L, LG_thread_new, 1 ); // metatable as closure param 2802 pSetPolicy(dwFlags & ~EXCEPTION_SWALLOWING);
2733 lua_setfield(L, -2, "thread_new"); 2803 }
2734 2804 }
2735 luaG_push_proxy( L, linda_id, (DEEP_PRELUDE *) timer_deep ); 2805#endif // PLATFORM_WIN32
2736 lua_setfield(L, -2, "timer_gateway");
2737
2738 lua_pushstring(L, VERSION);
2739 lua_setfield(L, -2, "version");
2740
2741 lua_pushinteger(L, THREAD_PRIO_MAX);
2742 lua_setfield(L, -2, "max_prio");
2743
2744 lua_pushlightuserdata( L, CANCEL_ERROR );
2745 lua_setfield(L, -2, "cancel_error");
2746
2747 // register all native functions found in that module in the transferable functions database
2748 // we process it before _G because we don't want to find the module when scanning _G (this would generate longer names)
2749 populate_func_lookup_table( L, -1, name);
2750 lua_pop( L, 1);
2751 // record all existing C/JIT-fast functions
2752 lua_pushglobaltable( L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack
2753 populate_func_lookup_table( L, -1, NULL);
2754 lua_pop( L, 1); // done with globals table, pop it
2755 // Return nothing
2756 return 0;
2757} 2806}
2758 2807
2759int 2808int
@@ -2762,6 +2811,8 @@ __declspec(dllexport)
2762#endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 2811#endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
2763luaopen_lanes_core( lua_State* L) 2812luaopen_lanes_core( lua_State* L)
2764{ 2813{
2814 EnableCrashingOnCrashes();
2815
2765 STACK_GROW( L, 3); 2816 STACK_GROW( L, 3);
2766 STACK_CHECK( L) 2817 STACK_CHECK( L)
2767 2818
diff --git a/src/lanes.lua b/src/lanes.lua
index 8c135c2..6bd9e44 100644
--- a/src/lanes.lua
+++ b/src/lanes.lua
@@ -210,10 +210,10 @@ local valid_libs= {
210 ["string"]= true, 210 ["string"]= true,
211 ["math"]= true, 211 ["math"]= true,
212 ["debug"]= true, 212 ["debug"]= true,
213 ["bit32"]= true, -- Lua 5.2 only, ignored silently under 5.1
213 -- 214 --
214 ["base"]= true, 215 ["base"]= true,
215 ["coroutine"]= true, 216 ["coroutine"]= true
216 ["*"]= true
217} 217}
218 218
219-- PUBLIC LANES API 219-- PUBLIC LANES API
@@ -251,11 +251,19 @@ local function gen( ... )
251 251
252 -- Check 'libs' already here, so the error goes in the right place 252 -- Check 'libs' already here, so the error goes in the right place
253 -- (otherwise will be noticed only once the generator is called) 253 -- (otherwise will be noticed only once the generator is called)
254 -- "*" is a special case that doesn't require individual checking
254 -- 255 --
255 if libs then 256 if libs and libs ~= "*" then
256 for s in string_gmatch(libs, "[%a*]+") do 257 local found = {}
258 -- check that the caller only provides reserved library names
259 for s in string_gmatch(libs, "[%a%d]+") do
257 if not valid_libs[s] then 260 if not valid_libs[s] then
258 error( "Bad library name: "..s ) 261 error( "Bad library name: " .. s)
262 else
263 found[s] = (found[s] or 0) + 1
264 if found[s] > 1 then
265 error( "libs specification contains '" .. s .. "' more than once")
266 end
259 end 267 end
260 end 268 end
261 end 269 end
diff --git a/src/tools.c b/src/tools.c
index 2629fd3..fe1728d 100644
--- a/src/tools.c
+++ b/src/tools.c
@@ -42,6 +42,8 @@ THE SOFTWARE.
42#include <ctype.h> 42#include <ctype.h>
43#include <stdlib.h> 43#include <stdlib.h>
44 44
45DEBUGSPEW_CODE( char const* debugspew_indent = "----+----!----+----!----+----!----+----!----+----!----+----!----+----!----+");
46
45MUTEX_T deep_lock; 47MUTEX_T deep_lock;
46MUTEX_T mtid_lock; 48MUTEX_T mtid_lock;
47 49
@@ -94,45 +96,52 @@ void luaG_dump( lua_State* L ) {
94 96
95/*---=== luaG_newstate ===---*/ 97/*---=== luaG_newstate ===---*/
96 98
97static const luaL_Reg libs[] = { 99static const luaL_Reg libs[] =
98 { LUA_LOADLIBNAME, luaopen_package }, 100{
99 { LUA_TABLIBNAME, luaopen_table }, 101 { LUA_LOADLIBNAME, luaopen_package},
100 { LUA_IOLIBNAME, luaopen_io }, 102 { LUA_TABLIBNAME, luaopen_table},
101 { LUA_OSLIBNAME, luaopen_os }, 103 { LUA_IOLIBNAME, luaopen_io},
102 { LUA_STRLIBNAME, luaopen_string }, 104 { LUA_OSLIBNAME, luaopen_os},
103 { LUA_MATHLIBNAME, luaopen_math }, 105 { LUA_STRLIBNAME, luaopen_string},
104 { LUA_DBLIBNAME, luaopen_debug }, 106 { LUA_MATHLIBNAME, luaopen_math},
105 // 107#if LUA_VERSION_NUM >= 502
106 { "base", NULL }, // ignore "base" (already acquired it) 108 { LUA_BITLIBNAME, luaopen_bit32},
107 { "coroutine", NULL }, // part of Lua 5.1 base package 109#endif // LUA_VERSION_NUM
108 { NULL, NULL } 110 { LUA_DBLIBNAME, luaopen_debug},
111 //
112 { "base", NULL }, // ignore "base" (already acquired it)
113 { LUA_COLIBNAME, NULL }, // part of Lua 5.[1|2] base package
114 { NULL, NULL }
109}; 115};
110 116
111static bool_t openlib( lua_State *L, const char *name, size_t len ) { 117static void open1lib( lua_State* L, char const* name, size_t len)
112 118{
113 unsigned i; 119 int i;
114 bool_t all= strncmp( name, "*", len ) == 0; 120 for( i = 0; libs[i].name; ++ i)
115
116 for( i=0; libs[i].name; i++ )
117 { 121 {
118 if (all || (strncmp(name, libs[i].name, len) ==0)) 122 if( strncmp( name, libs[i].name, len) == 0)
119 { 123 {
120 if (libs[i].func) 124 if( libs[i].func)
121 { 125 {
122 STACK_GROW(L,1); 126 DEBUGSPEW_CODE( fprintf( stderr, "opening %.*s library\n", len, name));
123 STACK_CHECK(L) 127 STACK_GROW( L, 1);
128 STACK_CHECK( L)
124 lua_pushcfunction( L, libs[i].func); 129 lua_pushcfunction( L, libs[i].func);
125 // pushes the module table on the stack 130 // pushes the module table on the stack
126 lua_call( L, 0, 1); 131 lua_call( L, 0, 1);
127 populate_func_lookup_table( L, -1, libs[i].name); 132 populate_func_lookup_table( L, -1, libs[i].name);
128 // remove the module when we are done 133#if LUA_VERSION_NUM >= 502
134 // Lua 5.2: luaopen_x doesn't create the global, we have to do it ourselves!
135 lua_setglobal( L, libs[i].name);
136#else // LUA_VERSION_NUM
137 // Lua 5.1: remove the module when we are done
129 lua_pop( L, 1); 138 lua_pop( L, 1);
130 STACK_END(L, 0) 139#endif // LUA_VERSION_NUM
140 STACK_END( L, 0)
131 } 141 }
132 if (!all) return TRUE; 142 break;
133 } 143 }
134 } 144 }
135 return all;
136} 145}
137 146
138static int dummy_writer(lua_State *L, const void* p, size_t sz, void* ud) 147static int dummy_writer(lua_State *L, const void* p, size_t sz, void* ud)
@@ -323,6 +332,7 @@ static void populate_func_lookup_table_recur( lua_State* L, int _ctx_base, int _
323 // remove table name from fqn stack 332 // remove table name from fqn stack
324 lua_pushnil( L); // ... {_i} {bfc} k nil 333 lua_pushnil( L); // ... {_i} {bfc} k nil
325 lua_rawseti( L, fqn, _depth); // ... {_i} {bfc} k 334 lua_rawseti( L, fqn, _depth); // ... {_i} {bfc} k
335 DEBUGSPEW_CODE( fprintf( stderr, "%.*spopulating: %s\n", _i, debugspew_indent, newName));
326 -- _depth; 336 -- _depth;
327 } 337 }
328 else 338 else
@@ -372,12 +382,12 @@ static void populate_func_lookup_table_recur( lua_State* L, int _ctx_base, int _
372/* 382/*
373 * create a "fully.qualified.name" <-> function equivalence database 383 * create a "fully.qualified.name" <-> function equivalence database
374 */ 384 */
375void populate_func_lookup_table( lua_State *L, int _i, char const *_name) 385void populate_func_lookup_table( lua_State* L, int _i, char const* _name)
376{ 386{
377 int const ctx_base = lua_gettop( L) + 1; 387 int const ctx_base = lua_gettop( L) + 1;
378 int const in_base = lua_absindex( L, _i); 388 int const in_base = lua_absindex( L, _i);
379 int const start_depth = _name ? 1 : 0; 389 int const start_depth = _name ? 1 : 0;
380 //printf( "%p: populate_func_lookup_table('%s')\n", L, _name ? _name : "NULL"); 390 DEBUGSPEW_CODE( fprintf( stderr, "%p: populate_func_lookup_table('%s')\n", L, _name ? _name : "NULL"));
381 STACK_GROW( L, 3); 391 STACK_GROW( L, 3);
382 STACK_CHECK( L) 392 STACK_CHECK( L)
383 lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY); // {}? 393 lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY); // {}?
@@ -423,8 +433,6 @@ void populate_func_lookup_table( lua_State *L, int _i, char const *_name)
423 433
424lua_State* luaG_newstate( char const* libs, lua_CFunction _on_state_create) 434lua_State* luaG_newstate( char const* libs, lua_CFunction _on_state_create)
425{ 435{
426 char const* p;
427 unsigned int len;
428 lua_State* const L = luaL_newstate(); 436 lua_State* const L = luaL_newstate();
429 437
430 // no libs, or special init func (not even 'base') 438 // no libs, or special init func (not even 'base')
@@ -447,31 +455,43 @@ lua_State* luaG_newstate( char const* libs, lua_CFunction _on_state_create)
447 { 455 {
448 if( libs[0] == '*' && libs[1] == 0) // special "*" case (mainly to help with LuaJIT compatibility) 456 if( libs[0] == '*' && libs[1] == 0) // special "*" case (mainly to help with LuaJIT compatibility)
449 { 457 {
458 DEBUGSPEW_CODE( fprintf( stderr, "opening ALL base libraries\n"));
450 luaL_openlibs( L); 459 luaL_openlibs( L);
451 libs = NULL; // done with libs 460 libs = NULL; // done with libs
452 } 461 }
453 else 462 else
454 { 463 {
464 DEBUGSPEW_CODE( fprintf( stderr, "opening base library\n"));
455 lua_pushcfunction( L, luaopen_base); 465 lua_pushcfunction( L, luaopen_base);
456 lua_call( L, 0, 0); 466 lua_call( L, 0, 0);
457 } 467 }
458 } 468 }
469
459 // after opening base, register the functions it exported in our name<->function database 470 // after opening base, register the functions it exported in our name<->function database
460 lua_pushglobaltable( L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack 471 lua_pushglobaltable( L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack
461 populate_func_lookup_table( L, -1, NULL); 472 populate_func_lookup_table( L, -1, NULL);
462 lua_pop( L, 1); 473 lua_pop( L, 1);
474
463 STACK_MID( L, 0); 475 STACK_MID( L, 0);
464 if( libs)
465 { 476 {
466 for( p = libs; *p; p += len) 477 char const* p;
478 unsigned int len = 0;
479 if( libs)
467 { 480 {
468 len=0; 481 for( p = libs; *p; p += len)
469 while (*p && !is_name_char(*p)) p++; // bypass delimiters 482 {
470 while (is_name_char(p[len])) len++; // bypass name 483 len = 0;
471 if (len && (!openlib( L, p, len ))) 484 // skip delimiters
472 break; 485 while( *p && !is_name_char( *p))
486 ++ p;
487 // skip name
488 while( is_name_char( p[len]))
489 ++ len;
490 // open library
491 open1lib( L, p, len);
492 }
493 serialize_require( L);
473 } 494 }
474 serialize_require( L);
475 } 495 }
476 STACK_END(L,0) 496 STACK_END(L,0)
477 lua_gc( L, LUA_GCRESTART, 0); 497 lua_gc( L, LUA_GCRESTART, 0);
@@ -1126,9 +1146,9 @@ static bool_t push_cached_table( lua_State *L2, uint_t L2_cache_i, lua_State *L,
1126 * 1146 *
1127 * Always pushes a function to 'L2'. 1147 * Always pushes a function to 'L2'.
1128 */ 1148 */
1129static void inter_copy_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ); 1149static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i);
1130 1150
1131static void push_cached_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ) 1151static void push_cached_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i)
1132{ 1152{
1133 void * const aspointer = (void*)lua_topointer( L, i); 1153 void * const aspointer = (void*)lua_topointer( L, i);
1134 // TBD: Merge this and same code for tables 1154 // TBD: Merge this and same code for tables
@@ -1228,6 +1248,27 @@ int discover_object_name_recur( lua_State* L, int _shortest, int _length)
1228 else if( lua_istable( L, -1)) 1248 else if( lua_istable( L, -1))
1229 { 1249 {
1230 _shortest = discover_object_name_recur( L, _shortest, _length); 1250 _shortest = discover_object_name_recur( L, _shortest, _length);
1251 // search in the table's metatable too
1252 if( lua_getmetatable( L, -1))
1253 {
1254 if( lua_istable( L, -1))
1255 {
1256 _shortest = discover_object_name_recur( L, _shortest, _length);
1257 }
1258 lua_pop( L, 1);
1259 }
1260 }
1261 else if( lua_isuserdata( L, -1))
1262 {
1263 // search in the object's metatable (some modules are built that way)
1264 if( lua_getmetatable( L, -1))
1265 {
1266 if( lua_istable( L, -1))
1267 {
1268 _shortest = discover_object_name_recur( L, _shortest, _length);
1269 }
1270 lua_pop( L, 1);
1271 }
1231 } 1272 }
1232 // make ready for next iteration 1273 // make ready for next iteration
1233 lua_pop( L, 1); // o "r" {c} {fqn} ... {?} k 1274 lua_pop( L, 1); // o "r" {c} {fqn} ... {?} k
@@ -1298,9 +1339,10 @@ static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i)
1298 if( !fqn) 1339 if( !fqn)
1299 { 1340 {
1300 char const* from; 1341 char const* from;
1301 lua_pushvalue( L, i); // ... f ... f
1302 // try to discover the name of the function we want to send 1342 // try to discover the name of the function we want to send
1303 luaG_nameof( L); // ... f ... "type" "name" 1343 lua_pushcfunction( L, luaG_nameof); // ... f ...luaG_nameof
1344 lua_pushvalue( L, i); // ... f ... luaG_nameof f
1345 lua_call( L, 1, 2); // ... f ... "type" "name"
1304 lua_getglobal( L, "decoda_name"); // ... f ... "type" "name" decoda_name 1346 lua_getglobal( L, "decoda_name"); // ... f ... "type" "name" decoda_name
1305 from = lua_tostring( L, -1); 1347 from = lua_tostring( L, -1);
1306 (void) luaL_error( L, "%s '%s' not found in %s origin transfer database.", lua_tostring( L, -3), lua_tostring( L, -2), from ? from : "main"); 1348 (void) luaL_error( L, "%s '%s' not found in %s origin transfer database.", lua_tostring( L, -3), lua_tostring( L, -2), from ? from : "main");
@@ -1327,15 +1369,6 @@ static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i)
1327 STACK_END( L2, 1) 1369 STACK_END( L2, 1)
1328} 1370}
1329 1371
1330#define LOG_FUNC_INFO 0
1331#if LOG_FUNC_INFO
1332#define LOG_FUNC_INFO_CODE(_code) _code
1333#else // LOG_FUNC_INFO
1334#define LOG_FUNC_INFO_CODE(_code)
1335#endif // LOG_FUNC_INFO
1336
1337LOG_FUNC_INFO_CODE( static char const* s_indent = "----+----!----+----!----+----!----+----!----+----!----+----!----+----!----+");
1338
1339/* 1372/*
1340 * Copy a function over, which has not been found in the cache. 1373 * Copy a function over, which has not been found in the cache.
1341 * L2 has the cache key for this function at the top of the stack 1374 * L2 has the cache key for this function at the top of the stack
@@ -1350,7 +1383,7 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin
1350 FuncSubType funcSubType; 1383 FuncSubType funcSubType;
1351 lua_CFunction cfunc = luaG_tocfunction( L, i, &funcSubType); // NULL for LuaJIT-fast && bytecode functions 1384 lua_CFunction cfunc = luaG_tocfunction( L, i, &funcSubType); // NULL for LuaJIT-fast && bytecode functions
1352 1385
1353 ASSERT_L( L2_cache_i != 0); // ... {cache} ... p 1386 ASSERT_L( L2_cache_i != 0); // ... {cache} ... p
1354 STACK_GROW(L,2); 1387 STACK_GROW(L,2);
1355 STACK_CHECK(L) 1388 STACK_CHECK(L)
1356 1389
@@ -1362,7 +1395,7 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin
1362 // if already on top of the stack, no need to push again 1395 // if already on top of the stack, no need to push again
1363 int needToPush = (i != (uint_t)lua_gettop( L)); 1396 int needToPush = (i != (uint_t)lua_gettop( L));
1364 if( needToPush) 1397 if( needToPush)
1365 lua_pushvalue( L, i); 1398 lua_pushvalue( L, i); // ... f
1366 1399
1367 luaL_buffinit( L, &b); 1400 luaL_buffinit( L, &b);
1368 // 1401 //
@@ -1374,12 +1407,13 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin
1374 luaL_error( L, "internal error: function dump failed."); 1407 luaL_error( L, "internal error: function dump failed.");
1375 } 1408 }
1376 1409
1377 luaL_pushresult( &b); // pushes dumped string on 'L' 1410 // pushes dumped string on 'L'
1411 luaL_pushresult( &b); // ... f b
1378 1412
1379 // if not pushed, no need to pop 1413 // if not pushed, no need to pop
1380 if( needToPush) 1414 if( needToPush)
1381 { 1415 {
1382 lua_remove( L, -2); 1416 lua_remove( L, -2); // ... b
1383 } 1417 }
1384 1418
1385 // transfer the bytecode, then the upvalues, to create a similar closure 1419 // transfer the bytecode, then the upvalues, to create a similar closure
@@ -1392,15 +1426,16 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin
1392 // 1426 //
1393 { 1427 {
1394 lua_Debug ar; 1428 lua_Debug ar;
1395 lua_pushvalue( L, i); 1429 lua_pushvalue( L, i); // ... b f
1396 lua_getinfo(L, ">nS", &ar); // fills 'name' 'namewhat' and 'linedefined', pops function 1430 // fills 'name' 'namewhat' and 'linedefined', pops function
1431 lua_getinfo(L, ">nS", &ar); // ... b
1397 name = ar.namewhat; 1432 name = ar.namewhat;
1398 fprintf( stderr, "%.*sFNAME: %s @ %d\n", i, s_indent, ar.short_src, ar.linedefined); // just gives NULL 1433 fprintf( stderr, "%.*sFNAME: %s @ %d\n", i, s_indent, ar.short_src, ar.linedefined); // just gives NULL
1399 } 1434 }
1400 #endif // LOG_FUNC_INFO 1435 #endif // LOG_FUNC_INFO
1401 { 1436 {
1402 size_t sz; 1437 size_t sz;
1403 char const* s = lua_tolstring( L, -1, &sz); 1438 char const* s = lua_tolstring( L, -1, &sz); // ... b
1404 ASSERT_L( s && sz); 1439 ASSERT_L( s && sz);
1405 STACK_GROW( L2, 2); 1440 STACK_GROW( L2, 2);
1406 // Note: Line numbers seem to be taken precisely from the 1441 // Note: Line numbers seem to be taken precisely from the
@@ -1409,7 +1444,7 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin
1409 // 1444 //
1410 // TBD: Can we get the function's original name through, as well? 1445 // TBD: Can we get the function's original name through, as well?
1411 // 1446 //
1412 if( luaL_loadbuffer( L2, s, sz, name) != 0) // ... {cache} ... p function 1447 if( luaL_loadbuffer( L2, s, sz, name) != 0) // ... {cache} ... p function
1413 { 1448 {
1414 // chunk is precompiled so only LUA_ERRMEM can happen 1449 // chunk is precompiled so only LUA_ERRMEM can happen
1415 // "Otherwise, it pushes an error message" 1450 // "Otherwise, it pushes an error message"
@@ -1417,38 +1452,50 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin
1417 STACK_GROW( L, 1); 1452 STACK_GROW( L, 1);
1418 luaL_error( L, "%s", lua_tostring( L2, -1)); 1453 luaL_error( L, "%s", lua_tostring( L2, -1));
1419 } 1454 }
1420 lua_pop( L, 1); // remove the dumped string 1455 // remove the dumped string
1456 lua_pop( L, 1); // ...
1421 // now set the cache as soon as we can. 1457 // now set the cache as soon as we can.
1422 // this is necessary if one of the function's upvalues references it indirectly 1458 // this is necessary if one of the function's upvalues references it indirectly
1423 // we need to find it in the cache even if it isn't fully transfered yet 1459 // we need to find it in the cache even if it isn't fully transfered yet
1424 lua_insert( L2, -2); // ... {cache} ... function p 1460 lua_insert( L2, -2); // ... {cache} ... function p
1425 lua_pushvalue( L2, -2); // ... {cache} ... function p function 1461 lua_pushvalue( L2, -2); // ... {cache} ... function p function
1426 // cache[p] = function 1462 // cache[p] = function
1427 lua_rawset( L2, L2_cache_i); // ... {cache} ... function 1463 lua_rawset( L2, L2_cache_i); // ... {cache} ... function
1428 } 1464 }
1429 STACK_MID( L, 0) 1465 STACK_MID( L, 0)
1430 1466
1431 /* push over any upvalues; references to this function will come from 1467 /* push over any upvalues; references to this function will come from
1432 * cache so we don't end up in eternal loop. 1468 * cache so we don't end up in eternal loop.
1469 * Lua5.2: one of the upvalues is _ENV, which we don't want to copy!
1470 * instead, the function shall have LUA_RIDX_GLOBALS taken in the destination state!
1433 */ 1471 */
1434 { 1472 {
1435 LOG_FUNC_INFO_CODE( char const* upname); 1473 DEBUGSPEW_CODE( char const* upname);
1436 for( n = 0; (LOG_FUNC_INFO_CODE( upname =) lua_getupvalue( L, i, 1 + n)) != NULL; ++ n) 1474#if LUA_VERSION_NUM == 502
1437 { 1475 // With Lua 5.2, each Lua function gets its environment as one of its upvalues (named LUA_ENV, aka "_ENV" by default)
1438 LOG_FUNC_INFO_CODE( fprintf( stderr, "%.*sUPNAME[%d]: %s\n", i, s_indent, n, upname)); 1476 // Generally this is LUA_RIDX_GLOBALS, which we don't want to copy from the source to the destination state...
1439 // v 3.4.2: we now longer need to handle this special case, because the general mechanism can take care of it just fine 1477 // -> if we encounter an upvalue equal to the global table in the source, bind it to the destination's global table
1440 /*if( (!cfunc) && lua_equal( L, i, -1)) 1478 lua_pushglobaltable( L); // ... _G
1479#endif // LUA_VERSION_NUM
1480 for( n = 0; (DEBUGSPEW_CODE( upname =) lua_getupvalue( L, i, 1 + n)) != NULL; ++ n)
1481 { // ... _G up[n]
1482 DEBUGSPEW_CODE( fprintf( stderr, "%.*sUPNAME[%d]: %s\n", i, debugspew_indent, n, upname));
1483#if LUA_VERSION_NUM == 502
1484 if( lua_rawequal( L, -1, -2)) // is the upvalue equal to the global table?
1441 { 1485 {
1442 // Lua closure that has a (recursive) upvalue to itself 1486 lua_pushglobaltable( L2); // ... {cache} ... function <upvalues>
1443 lua_pushvalue( L2, -n - 1); // ... {cache} ... function upvalues...
1444 } 1487 }
1445 else*/ 1488 else
1489#endif // LUA_VERSION_NUM
1446 { 1490 {
1447 if( !inter_copy_one_( L2, L2_cache_i, L, lua_gettop( L), VT_NORMAL)) 1491 if( !inter_copy_one_( L2, L2_cache_i, L, lua_gettop( L), VT_NORMAL)) // ... {cache} ... function <upvalues>
1448 luaL_error( L, "Cannot copy upvalue type '%s'", luaL_typename( L, -1)); 1492 luaL_error( L, "Cannot copy upvalue type '%s'", luaL_typename( L, -1));
1449 } 1493 }
1450 lua_pop( L, 1); 1494 lua_pop( L, 1); // ... _G
1451 } 1495 }
1496#if LUA_VERSION_NUM == 502
1497 lua_pop( L, 1); // ...
1498#endif // LUA_VERSION_NUM
1452 } 1499 }
1453 // L2: function + 'n' upvalues (>=0) 1500 // L2: function + 'n' upvalues (>=0)
1454 1501
@@ -1459,7 +1506,7 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin
1459 int func_index = lua_gettop( L2) - n; 1506 int func_index = lua_gettop( L2) - n;
1460 for( ; n > 0; -- n) 1507 for( ; n > 0; -- n)
1461 { 1508 {
1462 char const* rc = lua_setupvalue( L2, func_index, n); // ... {cache} ... function 1509 char const* rc = lua_setupvalue( L2, func_index, n); // ... {cache} ... function
1463 // 1510 //
1464 // "assigns the value at the top of the stack to the upvalue and returns its name. 1511 // "assigns the value at the top of the stack to the upvalue and returns its name.
1465 // It also pops the value from the stack." 1512 // It also pops the value from the stack."
@@ -1467,16 +1514,16 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin
1467 ASSERT_L( rc); // not having enough slots? 1514 ASSERT_L( rc); // not having enough slots?
1468 } 1515 }
1469 // once all upvalues have been set we are left 1516 // once all upvalues have been set we are left
1470 // with the function at the top of the stack // ... {cache} ... function 1517 // with the function at the top of the stack // ... {cache} ... function
1471 } 1518 }
1472 } 1519 }
1473 } 1520 }
1474 else // C function OR LuaJIT fast function!!! 1521 else // C function OR LuaJIT fast function!!!
1475 { 1522 {
1476 lua_pop( L2, 1); // ... {cache} ... 1523 lua_pop( L2, 1); // ... {cache} ...
1477 LOG_FUNC_INFO_CODE( fprintf( stderr, "%.*sFNAME: [C] function %p \n", i, s_indent, cfunc)); 1524 DEBUGSPEW_CODE( fprintf( stderr, "%.*sFNAME: [C] function %p \n", i, debugspew_indent, cfunc));
1478 // No need to transfer upvalues for C/JIT functions since they weren't actually copied, only looked up 1525 // No need to transfer upvalues for C/JIT functions since they weren't actually copied, only looked up
1479 lookup_native_func( L2, L, i); // ... {cache} ... function 1526 lookup_native_func( L2, L, i); // ... {cache} ... function
1480 } 1527 }
1481 STACK_END( L, 0) 1528 STACK_END( L, 0)
1482} 1529}
@@ -1518,8 +1565,8 @@ static bool_t inter_copy_one_( lua_State *L2, uint_t L2_cache_i, lua_State *L, u
1518 break; 1565 break;
1519 1566
1520 case LUA_TSTRING: { 1567 case LUA_TSTRING: {
1521 size_t len; const char *s = lua_tolstring( L, i, &len ); 1568 size_t len; const char* s = lua_tolstring( L, i, &len);
1522 LOG_FUNC_INFO_CODE( if( vt == VT_KEY) fprintf( stderr, "%.*sKEY: %s\n", i, s_indent, s)); 1569 DEBUGSPEW_CODE( if( vt == VT_KEY) fprintf( stderr, "%.*sKEY: %s\n", i, debugspew_indent, s));
1523 lua_pushlstring( L2, s, len ); 1570 lua_pushlstring( L2, s, len );
1524 } break; 1571 } break;
1525 1572
@@ -1735,7 +1782,7 @@ int luaG_inter_copy( lua_State* L, lua_State *L2, uint_t n)
1735 } 1782 }
1736 1783
1737 /* 1784 /*
1738 * Remove the cache table. Persistant caching would cause i.e. multiple 1785 * Remove the cache table. Persistent caching would cause i.e. multiple
1739 * messages passed in the same table to use the same table also in receiving 1786 * messages passed in the same table to use the same table also in receiving
1740 * end. 1787 * end.
1741 */ 1788 */
@@ -1755,13 +1802,49 @@ int luaG_inter_copy( lua_State* L, lua_State *L2, uint_t n)
1755} 1802}
1756 1803
1757 1804
1758int luaG_inter_move( lua_State* L, lua_State *L2, uint_t n ) 1805int luaG_inter_move( lua_State* L, lua_State* L2, uint_t n)
1759{ 1806{
1760 int ret = luaG_inter_copy( L, L2, n); 1807 int ret = luaG_inter_copy( L, L2, n);
1761 lua_pop( L, (int) n); 1808 lua_pop( L, (int) n);
1762 return ret; 1809 return ret;
1763} 1810}
1764 1811
1812void luaG_inter_copy_package( lua_State* L, lua_State* L2, int _idx)
1813{
1814 // package
1815 STACK_CHECK( L)
1816 STACK_CHECK( L2)
1817 _idx = lua_absindex( L, _idx);
1818 if( lua_type( L, _idx) != LUA_TTABLE)
1819 {
1820 (void) luaL_error( L, "expected package as table, got %s", luaL_typename( L, _idx));
1821 }
1822 lua_getglobal( L2, "package");
1823 if( !lua_isnil( L2, -1)) // package library not loaded: do nothing
1824 {
1825 int i;
1826 // package.loaders is renamed package.searchers in Lua 5.2
1827 char const* entries[] = { "path", "cpath", "preload", (LUA_VERSION_NUM == 501) ? "loaders" : "searchers", NULL};
1828 for( i = 0; entries[i]; ++ i)
1829 {
1830 lua_getfield( L, _idx, entries[i]);
1831 if( lua_isnil( L, -1))
1832 {
1833 lua_pop( L, 1);
1834 }
1835 else
1836 {
1837 luaG_inter_move( L, L2, 1); // moves the entry to L2
1838 lua_setfield( L2, -2, entries[i]); // set package[entries[i]]
1839 }
1840 }
1841 }
1842 lua_pop( L2, 1);
1843 STACK_END( L2, 0)
1844 STACK_END( L, 0)
1845}
1846
1847
1765/*---=== Serialize require ===--- 1848/*---=== Serialize require ===---
1766*/ 1849*/
1767 1850
diff --git a/src/tools.h b/src/tools.h
index 4a77a6a..d0169cf 100644
--- a/src/tools.h
+++ b/src/tools.h
@@ -25,6 +25,8 @@
25#define lua_getuservalue lua_getfenv 25#define lua_getuservalue lua_getfenv
26#define lua_rawlen lua_objlen 26#define lua_rawlen lua_objlen
27#define luaG_registerlibfuncs( L, _funcs) luaL_register( L, NULL, _funcs) 27#define luaG_registerlibfuncs( L, _funcs) luaL_register( L, NULL, _funcs)
28#define LUA_OK 0
29#define LUA_ERRGCMM 666 // doesn't exist in Lua 5.1, we don't care about the actual value
28#endif // LUA_VERSION_NUM == 501 30#endif // LUA_VERSION_NUM == 501
29 31
30// wrap Lua 5.2 calls under Lua 5.1 API when it is simpler that way 32// wrap Lua 5.2 calls under Lua 5.1 API when it is simpler that way
@@ -33,14 +35,21 @@
33#define luaG_registerlibfuncs( L, _funcs) luaL_setfuncs( L, _funcs, 0) 35#define luaG_registerlibfuncs( L, _funcs) luaL_setfuncs( L, _funcs, 0)
34#endif // LUA_VERSION_NUM == 502 36#endif // LUA_VERSION_NUM == 502
35 37
38#define USE_DEBUG_SPEW 0
39#if USE_DEBUG_SPEW
40extern char const* debugspew_indent;
41#define DEBUGSPEW_CODE(_code) _code
42#else // USE_DEBUG_SPEW
43#define DEBUGSPEW_CODE(_code)
44#endif // USE_DEBUG_SPEW
45
46
36#ifdef NDEBUG 47#ifdef NDEBUG
37 #define _ASSERT_L(lua,c) /*nothing*/ 48 #define _ASSERT_L(lua,c) /*nothing*/
38 #define STACK_CHECK(L) /*nothing*/ 49 #define STACK_CHECK(L) /*nothing*/
39 #define STACK_MID(L,c) /*nothing*/ 50 #define STACK_MID(L,c) /*nothing*/
40 #define STACK_END(L,c) /*nothing*/ 51 #define STACK_END(L,c) /*nothing*/
41 #define STACK_DUMP(L) /*nothing*/ 52 #define STACK_DUMP(L) /*nothing*/
42 #define DEBUG() /*nothing*/
43 #define DEBUGEXEC(_code) {} /*nothing*/
44#else 53#else
45 #define _ASSERT_L(lua,c) do { if (!(c)) luaL_error( lua, "ASSERT failed: %s:%d '%s'", __FILE__, __LINE__, #c ); } while( 0) 54 #define _ASSERT_L(lua,c) do { if (!(c)) luaL_error( lua, "ASSERT failed: %s:%d '%s'", __FILE__, __LINE__, #c ); } while( 0)
46 // 55 //
@@ -50,8 +59,6 @@
50 #define STACK_END(L,change) STACK_MID(L,change) } 59 #define STACK_END(L,change) STACK_MID(L,change) }
51 60
52 #define STACK_DUMP(L) luaG_dump(L); 61 #define STACK_DUMP(L) luaG_dump(L);
53 #define DEBUG() fprintf( stderr, "<<%s %d>>\n", __FILE__, __LINE__ );
54 #define DEBUGEXEC(_code) {_code;} /*nothing*/
55#endif 62#endif
56#define ASSERT_L(c) _ASSERT_L(L,c) 63#define ASSERT_L(c) _ASSERT_L(L,c)
57 64
@@ -73,7 +80,8 @@ typedef struct {
73 void *deep; 80 void *deep;
74} DEEP_PRELUDE; 81} DEEP_PRELUDE;
75 82
76void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *deep_userdata ); 83void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *deep_userdata);
84void luaG_inter_copy_package( lua_State* L, lua_State* L2, int _idx);
77 85
78int luaG_inter_copy( lua_State *L, lua_State *L2, uint_t n); 86int luaG_inter_copy( lua_State *L, lua_State *L2, uint_t n);
79int luaG_inter_move( lua_State *L, lua_State *L2, uint_t n); 87int luaG_inter_move( lua_State *L, lua_State *L2, uint_t n);
@@ -85,7 +93,7 @@ int luaG_nameof( lua_State* L);
85extern MUTEX_T deep_lock; 93extern MUTEX_T deep_lock;
86extern MUTEX_T mtid_lock; 94extern MUTEX_T mtid_lock;
87 95
88void populate_func_lookup_table( lua_State *L, int _i, char const *_name); 96void populate_func_lookup_table( lua_State* L, int _i, char const* _name);
89void serialize_require( lua_State *L); 97void serialize_require( lua_State *L);
90extern MUTEX_T require_cs; 98extern MUTEX_T require_cs;
91 99
diff --git a/tests/basic.lua b/tests/basic.lua
index e913906..c35f16a 100644
--- a/tests/basic.lua
+++ b/tests/basic.lua
@@ -7,8 +7,7 @@
7-- - ... 7-- - ...
8-- 8--
9 9
10local lanes = require "lanes" 10local lanes = require "lanes".configure{ with_timers = false}
11lanes.configure()
12require "assert" -- assert.fails() 11require "assert" -- assert.fails()
13 12
14local lanes_gen= assert( lanes.gen ) 13local lanes_gen= assert( lanes.gen )
@@ -49,7 +48,7 @@ local function subtable( a, b )
49 return true -- is a subtable 48 return true -- is a subtable
50end 49end
51 50
52-- true when contents of 'a' and 'b' are identific 51-- true when contents of 'a' and 'b' are identical
53-- 52--
54tables_match= function( a, b ) 53tables_match= function( a, b )
55 return subtable( a, b ) and subtable( b, a ) 54 return subtable( a, b ) and subtable( b, a )
@@ -215,7 +214,7 @@ assert( type(linda) == "userdata" )
215 214
216local function PEEK() return linda:get("<-") end 215local function PEEK() return linda:get("<-") end
217local function SEND(...) linda:send( "->", ... ) end 216local function SEND(...) linda:send( "->", ... ) end
218local function RECEIVE() local k,v = linda:receive( "<-" ) return v end 217local function RECEIVE() local k,v = linda:receive( 1, "<-" ) return v end
219 218
220local t= lanes_gen("io",chunk)(linda) -- prepare & launch 219local t= lanes_gen("io",chunk)(linda) -- prepare & launch
221 220
@@ -228,7 +227,14 @@ end
228SEND(3); WR( "3 sent\n" ) 227SEND(3); WR( "3 sent\n" )
229 228
230local a,b,c= RECEIVE(), RECEIVE(), RECEIVE() 229local a,b,c= RECEIVE(), RECEIVE(), RECEIVE()
231 WR( a..", "..b..", "..c.." received\n" ) 230
231print( "lane status: " .. t.status)
232if t.status == "error" then
233 print( t:join())
234else
235 WR( a..", "..b..", "..c.." received\n" )
236end
237
232assert( a==1 and b==2 and c==3 ) 238assert( a==1 and b==2 and c==3 )
233 239
234local a= RECEIVE(); WR( a.." received\n" ) 240local a= RECEIVE(); WR( a.." received\n" )
@@ -299,7 +305,7 @@ local function chunk2( linda )
299 -- 305 --
300 for k,v in pairs(info) do PRINT(k,v) end 306 for k,v in pairs(info) do PRINT(k,v) end
301 307
302 assert( info.nups == 2 ) -- one upvalue + PRINT 308 assert( info.nups == (_VERSION == "Lua 5.1" and 2 or 3) ) -- one upvalue + PRINT + _ENV (Lua 5.2 only)
303 assert( info.what == "Lua" ) 309 assert( info.what == "Lua" )
304 --assert( info.name == "chunk2" ) -- name does not seem to come through 310 --assert( info.name == "chunk2" ) -- name does not seem to come through
305 assert( string.match( info.source, "^@.*basic.lua$" ) ) 311 assert( string.match( info.source, "^@.*basic.lua$" ) )
@@ -327,7 +333,10 @@ linda:send( "down", function(linda) linda:send( "up", "ready!" ) end,
327 "ok" ) 333 "ok" )
328-- wait to see if the tiny function gets executed 334-- wait to see if the tiny function gets executed
329-- 335--
330local k,s= linda:receive( "up" ) 336local k,s= linda:receive( 1, "up" )
337if t2.status == "error" then
338 print( "t2 error: " , t2:join())
339end
331PRINT(s) 340PRINT(s)
332assert( s=="ready!" ) 341assert( s=="ready!" )
333 342
@@ -355,16 +364,21 @@ local S= lanes_gen( "table",
355 for i, v in ipairs(arg) do 364 for i, v in ipairs(arg) do
356 table.insert (aux, 1, v) 365 table.insert (aux, 1, v)
357 end 366 end
358 return unpack(aux) 367 -- unpack was renamed table.unpack in Lua 5.2: cater for both!
368 return (unpack or table.unpack)(aux)
359end ) 369end )
360 370
361h= S { 12, 13, 14 } -- execution starts, h[1..3] will get the return values 371h= S { 12, 13, 14 } -- execution starts, h[1..3] will get the return values
362 372
363local a,b,c,d= h:join() 373local a,b,c,d= h:join()
364assert(a==14) 374if h.status == "error" then
365assert(b==13) 375 print( "h error: " , a, b, c, d)
366assert(c==12) 376else
367assert(d==nil) 377 assert(a==14)
378 assert(b==13)
379 assert(c==12)
380 assert(d==nil)
381end
368 382
369-- 383--
370io.stderr:write "Done! :)\n" 384io.stderr:write "Done! :)\n"
diff --git a/tests/keeper.lua b/tests/keeper.lua
index 40c9e11..73ed3cf 100644
--- a/tests/keeper.lua
+++ b/tests/keeper.lua
@@ -4,8 +4,7 @@
4-- Test program for Lua Lanes 4-- Test program for Lua Lanes
5-- 5--
6 6
7local lanes = require "lanes" 7local lanes = require "lanes".configure{ with_timers = false}
8lanes.configure()
9 8
10local function keeper(linda) 9local function keeper(linda)
11 local mt= { 10 local mt= {
diff --git a/tests/linda_perf.lua b/tests/linda_perf.lua
index 87e0da7..be582ce 100644
--- a/tests/linda_perf.lua
+++ b/tests/linda_perf.lua
@@ -1,6 +1,9 @@
1local lanes = require "lanes" 1local lanes = require "lanes"
2lanes.configure() 2lanes.configure()
3 3
4-- Lua 5.1/5.2 compatibility
5local table_unpack = unpack or table.unpack
6
4-- this lane eats items in the linda one by one 7-- this lane eats items in the linda one by one
5local eater = function( l, loop) 8local eater = function( l, loop)
6 local key, val = l:receive( "go") 9 local key, val = l:receive( "go")
@@ -131,7 +134,7 @@ local function ziva2( preloop, loop, batch)
131 end 134 end
132 -- create a function that can send several values in one shot 135 -- create a function that can send several values in one shot
133 batch_send = function() 136 batch_send = function()
134 l:send( "key", unpack( batch_values)) 137 l:send( "key", table_unpack( batch_values))
135 end 138 end
136 batch_read = function() 139 batch_read = function()
137 l:receive( l.batched, "key", batch) 140 l:receive( l.batched, "key", batch)