diff options
author | Benoit Germain <bnt.germain@gmail.com> | 2013-01-24 22:46:21 +0100 |
---|---|---|
committer | Benoit Germain <bnt.germain@gmail.com> | 2013-01-24 22:46:21 +0100 |
commit | 68d8db431ec2b739dc53233d6b4d8aeee9324e48 (patch) | |
tree | d8f0fbe0f8c4e1a07ac4248fd1b7673f49beb4d3 | |
parent | 623fb3c0cae9beb3d5e7d3f7424b47d80041c1ac (diff) | |
download | lanes-3.4.3.tar.gz lanes-3.4.3.tar.bz2 lanes-3.4.3.zip |
version 3.4.3v3.4.3
* raise an error if lane generator libs specification contains a lib more than once
* bit32 is a valid lib name in the libs specification (silently ignored by the Lua 5.1 build)
* improved lanes.nameof to search inside table- and userdata- metatables for an object's name
* fixed an unwarranted error when trying to discover a function name upon a failed transfer
* contents of package.[path,cpath,preload,loaders|searchers] are pulled *only once* inside keeper states at initialisation
* Lua function upvalues equal to the global environment aren't copied by value, but bound to the destination's global environment
especially useful for Lua 5.2 _ENV
* fixed loading of base libraries that didn't create the global tables when built for Lua 5.2
-rw-r--r-- | CHANGES | 13 | ||||
-rw-r--r-- | docs/index.html | 27 | ||||
-rw-r--r-- | src/keeper.c | 57 | ||||
-rw-r--r-- | src/keeper.h | 2 | ||||
-rw-r--r-- | src/lanes.c | 371 | ||||
-rw-r--r-- | src/lanes.lua | 18 | ||||
-rw-r--r-- | src/tools.c | 249 | ||||
-rw-r--r-- | src/tools.h | 20 | ||||
-rw-r--r-- | tests/basic.lua | 38 | ||||
-rw-r--r-- | tests/keeper.lua | 3 | ||||
-rw-r--r-- | tests/linda_perf.lua | 5 |
11 files changed, 489 insertions, 314 deletions
@@ -1,5 +1,16 @@ | |||
1 | CHANGES: | 1 | CHANGES: |
2 | 2 | ||
3 | CHANGE 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 | |||
3 | CHANGE 54: BGe 10-Jan-13 | 14 | CHANGE 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 | ||
93 | CHANGE 34 BGe 14-Nov-2011 | 104 | CHANGE 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 | ||
98 | CHANGE 33 BGe 5-Nov-2011: Lanes version 3.0-beta | 109 | CHANGE 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 © 2007-12 Asko Kauppi, Benoit Germain. All rights reserved.</i> | 66 | <i>Copyright © 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 | */ |
560 | char const* init_keepers( int const _nbKeepers, lua_CFunction _on_state_create) | 560 | char 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 |
622 | void populate_keepers( lua_State *L) | 628 | // do do this we simply require the module inside the keeper state, then populate the lookup database |
629 | void 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 | ||
670 | struct s_Keeper *keeper_acquire( const void *ptr) | 659 | struct 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 | ||
694 | void keeper_release( struct s_Keeper *K) | 683 | void 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 | ||
700 | void keeper_toggle_nil_sentinels( lua_State *L, int _val_i, int _nil_to_sentinel) | 689 | void 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 | ||
16 | char const* init_keepers( int const _nbKeepers, lua_CFunction _on_state_create); | 16 | char 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 |
18 | void close_keepers( void); | 18 | void 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 | ||
55 | char const* VERSION = "3.4.2"; | 55 | char const* VERSION = "3.4.3"; |
56 | 56 | ||
57 | /* | 57 | /* |
58 | =============================================================================== | 58 | =============================================================================== |
59 | 59 | ||
60 | Copyright (C) 2007-10 Asko Kauppi <akauppi@gmail.com> | 60 | Copyright (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 | ||
63 | Permission is hereby granted, free of charge, to any person obtaining a copy | 63 | Permission is hereby granted, free of charge, to any person obtaining a copy |
64 | of this software and associated documentation files (the "Software"), to deal | 64 | of 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 | // |
1272 | volatile DEEP_PRELUDE *timer_deep; // = NULL | 1273 | volatile 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 | ||
1661 | struct errcode_name | ||
1662 | { | ||
1663 | int code; | ||
1664 | char const* name; | ||
1665 | }; | ||
1666 | |||
1667 | static 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 | }; | ||
1677 | static 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 | //--- |
1658 | static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) | 1692 | static 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 |
1812 | static void require_one_module( lua_State*L, lua_State*L2, bool_t _fatal) | 1849 | static 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 | */ |
2550 | static 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) | 2559 | static 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 | ||
2654 | static volatile long s_initCount = 0; | 2663 | static volatile long s_initCount = 0; |
2655 | 2664 | ||
2656 | LUAG_FUNC( configure ) | 2665 | // upvalue 1: module name |
2666 | // upvalue 2: module table | ||
2667 | LUAG_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"); | 2786 | void 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 | ||
2759 | int | 2808 | int |
@@ -2762,6 +2811,8 @@ __declspec(dllexport) | |||
2762 | #endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) | 2811 | #endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) |
2763 | luaopen_lanes_core( lua_State* L) | 2812 | luaopen_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 | ||
45 | DEBUGSPEW_CODE( char const* debugspew_indent = "----+----!----+----!----+----!----+----!----+----!----+----!----+----!----+"); | ||
46 | |||
45 | MUTEX_T deep_lock; | 47 | MUTEX_T deep_lock; |
46 | MUTEX_T mtid_lock; | 48 | MUTEX_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 | ||
97 | static const luaL_Reg libs[] = { | 99 | static 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 | ||
111 | static bool_t openlib( lua_State *L, const char *name, size_t len ) { | 117 | static 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 | ||
138 | static int dummy_writer(lua_State *L, const void* p, size_t sz, void* ud) | 147 | static 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 | */ |
375 | void populate_func_lookup_table( lua_State *L, int _i, char const *_name) | 385 | void 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 | ||
424 | lua_State* luaG_newstate( char const* libs, lua_CFunction _on_state_create) | 434 | lua_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 | */ |
1129 | static void inter_copy_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ); | 1149 | static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i); |
1130 | 1150 | ||
1131 | static void push_cached_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ) | 1151 | static 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 | |||
1337 | LOG_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 | ||
1758 | int luaG_inter_move( lua_State* L, lua_State *L2, uint_t n ) | 1805 | int 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 | ||
1812 | void 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 | ||
40 | extern 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 | ||
76 | void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *deep_userdata ); | 83 | void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *deep_userdata); |
84 | void luaG_inter_copy_package( lua_State* L, lua_State* L2, int _idx); | ||
77 | 85 | ||
78 | int luaG_inter_copy( lua_State *L, lua_State *L2, uint_t n); | 86 | int luaG_inter_copy( lua_State *L, lua_State *L2, uint_t n); |
79 | int luaG_inter_move( lua_State *L, lua_State *L2, uint_t n); | 87 | int luaG_inter_move( lua_State *L, lua_State *L2, uint_t n); |
@@ -85,7 +93,7 @@ int luaG_nameof( lua_State* L); | |||
85 | extern MUTEX_T deep_lock; | 93 | extern MUTEX_T deep_lock; |
86 | extern MUTEX_T mtid_lock; | 94 | extern MUTEX_T mtid_lock; |
87 | 95 | ||
88 | void populate_func_lookup_table( lua_State *L, int _i, char const *_name); | 96 | void populate_func_lookup_table( lua_State* L, int _i, char const* _name); |
89 | void serialize_require( lua_State *L); | 97 | void serialize_require( lua_State *L); |
90 | extern MUTEX_T require_cs; | 98 | extern 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 | ||
10 | local lanes = require "lanes" | 10 | local lanes = require "lanes".configure{ with_timers = false} |
11 | lanes.configure() | ||
12 | require "assert" -- assert.fails() | 11 | require "assert" -- assert.fails() |
13 | 12 | ||
14 | local lanes_gen= assert( lanes.gen ) | 13 | local 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 |
50 | end | 49 | end |
51 | 50 | ||
52 | -- true when contents of 'a' and 'b' are identific | 51 | -- true when contents of 'a' and 'b' are identical |
53 | -- | 52 | -- |
54 | tables_match= function( a, b ) | 53 | tables_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 | ||
216 | local function PEEK() return linda:get("<-") end | 215 | local function PEEK() return linda:get("<-") end |
217 | local function SEND(...) linda:send( "->", ... ) end | 216 | local function SEND(...) linda:send( "->", ... ) end |
218 | local function RECEIVE() local k,v = linda:receive( "<-" ) return v end | 217 | local function RECEIVE() local k,v = linda:receive( 1, "<-" ) return v end |
219 | 218 | ||
220 | local t= lanes_gen("io",chunk)(linda) -- prepare & launch | 219 | local t= lanes_gen("io",chunk)(linda) -- prepare & launch |
221 | 220 | ||
@@ -228,7 +227,14 @@ end | |||
228 | SEND(3); WR( "3 sent\n" ) | 227 | SEND(3); WR( "3 sent\n" ) |
229 | 228 | ||
230 | local a,b,c= RECEIVE(), RECEIVE(), RECEIVE() | 229 | local a,b,c= RECEIVE(), RECEIVE(), RECEIVE() |
231 | WR( a..", "..b..", "..c.." received\n" ) | 230 | |
231 | print( "lane status: " .. t.status) | ||
232 | if t.status == "error" then | ||
233 | print( t:join()) | ||
234 | else | ||
235 | WR( a..", "..b..", "..c.." received\n" ) | ||
236 | end | ||
237 | |||
232 | assert( a==1 and b==2 and c==3 ) | 238 | assert( a==1 and b==2 and c==3 ) |
233 | 239 | ||
234 | local a= RECEIVE(); WR( a.." received\n" ) | 240 | local 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 | -- |
330 | local k,s= linda:receive( "up" ) | 336 | local k,s= linda:receive( 1, "up" ) |
337 | if t2.status == "error" then | ||
338 | print( "t2 error: " , t2:join()) | ||
339 | end | ||
331 | PRINT(s) | 340 | PRINT(s) |
332 | assert( s=="ready!" ) | 341 | assert( 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) | ||
359 | end ) | 369 | end ) |
360 | 370 | ||
361 | h= S { 12, 13, 14 } -- execution starts, h[1..3] will get the return values | 371 | h= S { 12, 13, 14 } -- execution starts, h[1..3] will get the return values |
362 | 372 | ||
363 | local a,b,c,d= h:join() | 373 | local a,b,c,d= h:join() |
364 | assert(a==14) | 374 | if h.status == "error" then |
365 | assert(b==13) | 375 | print( "h error: " , a, b, c, d) |
366 | assert(c==12) | 376 | else |
367 | assert(d==nil) | 377 | assert(a==14) |
378 | assert(b==13) | ||
379 | assert(c==12) | ||
380 | assert(d==nil) | ||
381 | end | ||
368 | 382 | ||
369 | -- | 383 | -- |
370 | io.stderr:write "Done! :)\n" | 384 | io.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 | ||
7 | local lanes = require "lanes" | 7 | local lanes = require "lanes".configure{ with_timers = false} |
8 | lanes.configure() | ||
9 | 8 | ||
10 | local function keeper(linda) | 9 | local 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 @@ | |||
1 | local lanes = require "lanes" | 1 | local lanes = require "lanes" |
2 | lanes.configure() | 2 | lanes.configure() |
3 | 3 | ||
4 | -- Lua 5.1/5.2 compatibility | ||
5 | local 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 |
5 | local eater = function( l, loop) | 8 | local 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) |