diff options
author | Benoit Germain <bnt period germain arrobase gmail period com> | 2014-02-17 11:05:19 +0100 |
---|---|---|
committer | Benoit Germain <bnt period germain arrobase gmail period com> | 2014-02-17 11:05:19 +0100 |
commit | 47eb3f94373a13ac9f204ca65dfde602f53bdc1a (patch) | |
tree | 95d7d7a52ca92e6527d46d97207d3f079611a355 | |
parent | 32ad991eb8c590472607d61e9a831d2ca9db05c5 (diff) | |
download | lanes-47eb3f94373a13ac9f204ca65dfde602f53bdc1a.tar.gz lanes-47eb3f94373a13ac9f204ca65dfde602f53bdc1a.tar.bz2 lanes-47eb3f94373a13ac9f204ca65dfde602f53bdc1a.zip |
Deep userdata support improvements
* bumped version to 3.9.0
* keepers now require "package", receive package.path & package.cpath,
and call on_state_create() if it is a C function
* changed the deep public API (improved deep idfunc signature, renamed
luaG_deep_userdata to luaG_newdeepuserdata)
* if an error occurs while copying a deep userdata, don't raise inside
the keeper state
* fixed situations where raised errors could lead to memory leaks (deep
gc)
-rw-r--r-- | CHANGES | 7 | ||||
-rw-r--r-- | docs/index.html | 32 | ||||
-rw-r--r-- | src/deep.h | 12 | ||||
-rw-r--r-- | src/keeper.c | 44 | ||||
-rw-r--r-- | src/lanes.c | 286 | ||||
-rw-r--r-- | src/tools.c | 791 | ||||
-rw-r--r-- | src/tools.h | 16 |
7 files changed, 604 insertions, 584 deletions
@@ -1,5 +1,12 @@ | |||
1 | CHANGES: | 1 | CHANGES: |
2 | 2 | ||
3 | CHANGE 99: BGe 17-Feb-14 | ||
4 | * version 3.9.0 | ||
5 | * keepers now require "package", receive package.path & package.cpath, and call on_state_create() if it is a C function | ||
6 | * changed the deep public API (improved deep idfunc signature, renamed luaG_deep_userdata to luaG_newdeepuserdata) | ||
7 | * if an error occurs while copying a deep userdata, don't raise inside the keeper state | ||
8 | * fixed situations where raised errors could lead to memory leaks (deep gc) | ||
9 | |||
3 | CHANGE 98: BGe 13-Feb-14 | 10 | CHANGE 98: BGe 13-Feb-14 |
4 | * version 3.8.5 | 11 | * version 3.8.5 |
5 | * linda:limit() returns lanes.cancel_error on a limited linda | 12 | * linda:limit() returns lanes.cancel_error on a limited linda |
diff --git a/docs/index.html b/docs/index.html index 2468ad8..051f9d0 100644 --- a/docs/index.html +++ b/docs/index.html | |||
@@ -70,7 +70,7 @@ | |||
70 | </p> | 70 | </p> |
71 | 71 | ||
72 | <p> | 72 | <p> |
73 | This document was revised on 13-Feb-14, and applies to version <tt>3.8.5</tt>. | 73 | This document was revised on 17-Feb-14, and applies to version <tt>3.9.0</tt>. |
74 | </p> | 74 | </p> |
75 | </font> | 75 | </font> |
76 | </center> | 76 | </center> |
@@ -355,7 +355,9 @@ | |||
355 | function/<tt>nil</tt> | 355 | function/<tt>nil</tt> |
356 | </td> | 356 | </td> |
357 | <td> | 357 | <td> |
358 | If provided, will be called in every created Lua state (keepers and lanes) right after initializing the base libraries. | 358 | If provided, will be called in every created Lua state right after initializing the base libraries. |
359 | <br/> | ||
360 | Keeper states will call it as well, but only if it is a C function (keeper states are not able to execute any user Lua code). | ||
359 | <br/> | 361 | <br/> |
360 | Typical usage is twofold: | 362 | Typical usage is twofold: |
361 | <ul> | 363 | <ul> |
@@ -1493,18 +1495,18 @@ events to a common Linda, but... :).</font> | |||
1493 | <ol> | 1495 | <ol> |
1494 | <li> | 1496 | <li> |
1495 | Provide an <i>identity function</i> for your userdata, in C. This function is used for creation and deletion of your deep userdata (the shared resource), and for making metatables for the state-specific proxies for accessing it. The prototype is | 1497 | Provide an <i>identity function</i> for your userdata, in C. This function is used for creation and deletion of your deep userdata (the shared resource), and for making metatables for the state-specific proxies for accessing it. The prototype is |
1496 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> void idfunc( lua_State *L, char const * const which);</pre></td></tr></table> | 1498 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> void* idfunc( lua_State* L, enum eDeepOp op_);</pre></td></tr></table> |
1497 | <tt>which</tt> can be one of: | 1499 | <tt>op_</tt> can be one of: |
1498 | <ul> | 1500 | <ul> |
1499 | <li><tt>"new"</tt>: requests the creation of a new object, whose pointer is pushed on the stack as a light userdata.</li> | 1501 | <li><tt>eDO_new</tt>: requests the creation of a new object, whose pointer is returned.</li> |
1500 | <li><tt>"delete"</tt>: receives this same pointer on the stack, and should cleanup the object.</li> | 1502 | <li><tt>eDO_delete</tt>: receives this same pointer on the stack as a light userdata, and should cleanup the object.</li> |
1501 | <li><tt>"metatable"</tt>: should build a metatable for the object. Don't cache the metatable yourself, Lanes takes care of it ("metatable" should only be invoked once).</li> | 1503 | <li><tt>eDO_metatable</tt>: should build a metatable for the object. Don't cache the metatable yourself, Lanes takes care of it (<tt>eDO_metatable</tt> should only be invoked once per state).</li> |
1502 | <li><tt>"module"</tt>: is the name of the module that exports the idfunc, to be pushed on the stack as a string. It is necessary so that Lanes can require it in any Lane and keeper state that receives a userdata. This is to prevent crashes in situations where the module could be unloaded while the idfunc pointer is still held.</li> | 1504 | <li><tt>eDO_module</tt>: requests the name of the module that exports the idfunc, to be returned. It is necessary so that Lanes can require it in any lane state that receives a userdata. This is to prevent crashes in situations where the module could be unloaded while the idfunc pointer is still held.</li> |
1503 | </ul> | 1505 | </ul> |
1504 | Take a look at <tt>linda_id</tt> in <tt>lanes.c</tt>. | 1506 | Take a look at <tt>linda_id</tt> in <tt>lanes.c</tt>. |
1505 | </li> | 1507 | </li> |
1506 | <li>Include <tt>"deep.h"</tt> and link against Lanes. | 1508 | <li>Include <tt>"deep.h"</tt> and link against Lanes. |
1507 | <li>Instanciate your userdata using <tt>luaG_deep_userdata()</tt>, instead of the regular <tt>lua_newuserdata()</tt>. Given an <tt>idfunc</tt>, it sets up the support structures and returns a state-specific proxy userdata for accessing your data. This proxy can also be copied over to other lanes.</li> | 1509 | <li>Instanciate your userdata using <tt>luaG_newdeepuserdata()</tt>, instead of the regular <tt>lua_newuserdata()</tt>. Given an <tt>idfunc</tt>, it sets up the support structures and returns a state-specific proxy userdata for accessing your data. This proxy can also be copied over to other lanes.</li> |
1508 | <li>Accessing the deep userdata from your C code, use <tt>luaG_todeep()</tt> instead of the regular <tt>lua_touserdata()</tt>.</li> | 1510 | <li>Accessing the deep userdata from your C code, use <tt>luaG_todeep()</tt> instead of the regular <tt>lua_touserdata()</tt>.</li> |
1509 | </ol> | 1511 | </ol> |
1510 | 1512 | ||
@@ -1513,7 +1515,17 @@ events to a common Linda, but... :).</font> | |||
1513 | </p> | 1515 | </p> |
1514 | 1516 | ||
1515 | <p> | 1517 | <p> |
1516 | <b>NOTE</b>: The lifespan of deep userdata may exceed that of the Lua state that created it. The allocation of the data storage should not be tied to the Lua state used. In other words, use <tt>malloc</tt>/<tt>free</tt> or similar memory handling mechanism. | 1518 | Deep userdata in transit inside keeper states (sent in a linda but not yet consumed) don't call <tt>idfunc(eDO_delete)</tt> and aren't considered by reference counting. The rationale is the following: |
1519 | <br/> | ||
1520 | If some non-keeper state holds a deep userdata for some deep object, then even if the keeper collects its own deep userdata, it shouldn't be cleaned up since the refcount is not 0. | ||
1521 | <br/> | ||
1522 | OTOH, if a keeper state holds the last deep userdata for some deep object, then no lane can do actual work with it. But as it happens, deep userdata are only copied to and from keeper states. Most notably, the object's <tt>idfunc()</tt> is never called from a keeper state. | ||
1523 | <br/> | ||
1524 | Therefore, Lanes can just call <tt>idfunc(eDO_delete)</tt> when the last non-keeper-held deep userdata is collected, as long as it doens't do the same in a keeper state after that, since any remaining deep userdata in keeper states now hold stale pointers. | ||
1525 | </p> | ||
1526 | |||
1527 | <p> | ||
1528 | <b>NOTE</b>: The lifespan of deep userdata may exceed that of the Lua state that created it. The allocation of the data storage should not be tied to the Lua state used. In other words, use <tt>malloc()</tt>/<tt>free()</tt> or similar memory handling mechanism. | ||
1517 | </p> | 1529 | </p> |
1518 | 1530 | ||
1519 | 1531 | ||
@@ -15,9 +15,17 @@ | |||
15 | #define LANES_API | 15 | #define LANES_API |
16 | #endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) | 16 | #endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) |
17 | 17 | ||
18 | typedef void (*luaG_IdFunction)( lua_State* L, char const* const which); | 18 | enum eDeepOp |
19 | { | ||
20 | eDO_new, | ||
21 | eDO_delete, | ||
22 | eDO_metatable, | ||
23 | eDO_module, | ||
24 | }; | ||
19 | 25 | ||
20 | extern LANES_API int luaG_deep_userdata( lua_State* L, luaG_IdFunction idfunc); | 26 | typedef void* (*luaG_IdFunction)( lua_State* L, enum eDeepOp op_); |
27 | |||
28 | extern LANES_API int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc); | ||
21 | extern LANES_API void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index); | 29 | extern LANES_API void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index); |
22 | 30 | ||
23 | #endif // __LANES_DEEP_H__ | 31 | #endif // __LANES_DEEP_H__ |
diff --git a/src/keeper.c b/src/keeper.c index c22bfed..4eb8bb3 100644 --- a/src/keeper.c +++ b/src/keeper.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <ctype.h> | 44 | #include <ctype.h> |
45 | 45 | ||
46 | #include "lua.h" | 46 | #include "lua.h" |
47 | #include "lualib.h" | ||
47 | #include "lauxlib.h" | 48 | #include "lauxlib.h" |
48 | 49 | ||
49 | #include "threading.h" | 50 | #include "threading.h" |
@@ -623,11 +624,10 @@ char const* init_keepers( lua_State* L) | |||
623 | int i; | 624 | int i; |
624 | PROPAGATE_ALLOCF_PREP( L); | 625 | PROPAGATE_ALLOCF_PREP( L); |
625 | 626 | ||
626 | STACK_CHECK( L); | 627 | STACK_CHECK( L); // L K |
627 | lua_getfield( L, 1, "nb_keepers"); | 628 | lua_getfield( L, 1, "nb_keepers"); // nb_keepers |
628 | GNbKeepers = (int) lua_tointeger( L, -1); | 629 | GNbKeepers = (int) lua_tointeger( L, -1); |
629 | lua_pop( L, 1); | 630 | lua_pop( L, 1); // |
630 | STACK_END( L, 0); | ||
631 | assert( GNbKeepers >= 1); | 631 | assert( GNbKeepers >= 1); |
632 | 632 | ||
633 | GKeepers = malloc( GNbKeepers * sizeof( struct s_Keeper)); | 633 | GKeepers = malloc( GNbKeepers * sizeof( struct s_Keeper)); |
@@ -640,16 +640,37 @@ char const* init_keepers( lua_State* L) | |||
640 | } | 640 | } |
641 | STACK_CHECK( K); | 641 | STACK_CHECK( K); |
642 | 642 | ||
643 | // make sure 'package' is initialized in keeper states, so that we have require() | ||
644 | // this because this is needed when transfering deep userdata object | ||
645 | luaL_requiref( K, "package", luaopen_package, 1); // package | ||
646 | lua_pop( K, 1); // | ||
647 | STACK_MID( K, 0); | ||
648 | serialize_require( K); | ||
649 | STACK_MID( K, 0); | ||
650 | |||
651 | // copy package.path and package.cpath from the source state | ||
652 | lua_getglobal( L, "package"); // package | ||
653 | if( !lua_isnil( L, -1)) | ||
654 | { | ||
655 | luaG_inter_copy_package( L, K, -1, eLM_ToKeeper); | ||
656 | } | ||
657 | lua_pop( L, 1); // | ||
658 | STACK_MID( L, 0); | ||
659 | |||
660 | // attempt to call on_state_create(), if we have one and it is a C function | ||
661 | // (only support a C function because we can't transfer executable Lua code in keepers) | ||
662 | call_on_state_create( K, L, eLM_ToKeeper); | ||
663 | |||
643 | // to see VM name in Decoda debugger | 664 | // to see VM name in Decoda debugger |
644 | lua_pushliteral( K, "Keeper #"); | 665 | lua_pushliteral( K, "Keeper #"); // "Keeper #" |
645 | lua_pushinteger( K, i + 1); | 666 | lua_pushinteger( K, i + 1); // "Keeper #" n |
646 | lua_concat( K, 2); | 667 | lua_concat( K, 2); // "Keeper #n" |
647 | lua_setglobal( K, "decoda_name"); | 668 | lua_setglobal( K, "decoda_name"); // |
648 | 669 | ||
649 | // create the fifos table in the keeper state | 670 | // create the fifos table in the keeper state |
650 | lua_pushlightuserdata( K, fifos_key); | 671 | lua_pushlightuserdata( K, fifos_key); // fifo_key |
651 | lua_newtable( K); | 672 | lua_newtable( K); // fifo_key {} |
652 | lua_rawset( K, LUA_REGISTRYINDEX); | 673 | lua_rawset( K, LUA_REGISTRYINDEX); // |
653 | 674 | ||
654 | STACK_END( K, 0); | 675 | STACK_END( K, 0); |
655 | // we can trigger a GC from inside keeper_call(), where a keeper is acquired | 676 | // we can trigger a GC from inside keeper_call(), where a keeper is acquired |
@@ -660,6 +681,7 @@ char const* init_keepers( lua_State* L) | |||
660 | #if HAVE_KEEPER_ATEXIT_DESINIT | 681 | #if HAVE_KEEPER_ATEXIT_DESINIT |
661 | atexit( atexit_close_keepers); | 682 | atexit( atexit_close_keepers); |
662 | #endif // HAVE_KEEPER_ATEXIT_DESINIT | 683 | #endif // HAVE_KEEPER_ATEXIT_DESINIT |
684 | STACK_END( L, 0); | ||
663 | return NULL; // ok | 685 | return NULL; // ok |
664 | } | 686 | } |
665 | 687 | ||
diff --git a/src/lanes.c b/src/lanes.c index dbb0a82..597ac4b 100644 --- a/src/lanes.c +++ b/src/lanes.c | |||
@@ -52,7 +52,7 @@ | |||
52 | * ... | 52 | * ... |
53 | */ | 53 | */ |
54 | 54 | ||
55 | char const* VERSION = "3.8.5"; | 55 | char const* VERSION = "3.9.0"; |
56 | 56 | ||
57 | /* | 57 | /* |
58 | =============================================================================== | 58 | =============================================================================== |
@@ -422,11 +422,11 @@ struct s_Linda | |||
422 | char name[1]; | 422 | char name[1]; |
423 | }; | 423 | }; |
424 | 424 | ||
425 | static void linda_id( lua_State*, char const * const which); | 425 | static void* linda_id( lua_State*, enum eDeepOp); |
426 | 426 | ||
427 | static inline struct s_Linda* lua_toLinda( lua_State* L, int idx_) | 427 | static inline struct s_Linda* lua_toLinda( lua_State* L, int idx_) |
428 | { | 428 | { |
429 | struct s_Linda* linda = luaG_todeep( L, linda_id, idx_); | 429 | struct s_Linda* linda = (struct s_Linda*) luaG_todeep( L, linda_id, idx_); |
430 | luaL_argcheck( L, linda != NULL, idx_, "expecting a linda object"); | 430 | luaL_argcheck( L, linda != NULL, idx_, "expecting a linda object"); |
431 | return linda; | 431 | return linda; |
432 | } | 432 | } |
@@ -996,7 +996,7 @@ LUAG_FUNC( linda_deep) | |||
996 | 996 | ||
997 | static int linda_tostring( lua_State* L, int idx_, bool_t opt_) | 997 | static int linda_tostring( lua_State* L, int idx_, bool_t opt_) |
998 | { | 998 | { |
999 | struct s_Linda* linda = luaG_todeep( L, linda_id, idx_); | 999 | struct s_Linda* linda = (struct s_Linda*) luaG_todeep( L, linda_id, idx_); |
1000 | if( !opt_) | 1000 | if( !opt_) |
1001 | { | 1001 | { |
1002 | luaL_argcheck( L, linda, idx_, "expecting a linda object"); | 1002 | luaL_argcheck( L, linda, idx_, "expecting a linda object"); |
@@ -1084,122 +1084,127 @@ LUAG_FUNC( linda_dump) | |||
1084 | * For any other strings, the ID function must not react at all. This allows | 1084 | * For any other strings, the ID function must not react at all. This allows |
1085 | * future extensions of the system. | 1085 | * future extensions of the system. |
1086 | */ | 1086 | */ |
1087 | static void linda_id( lua_State* L, char const* const which) | 1087 | static void* linda_id( lua_State* L, enum eDeepOp op_) |
1088 | { | 1088 | { |
1089 | if( strcmp( which, "new" ) == 0) | 1089 | switch( op_) |
1090 | { | 1090 | { |
1091 | struct s_Linda* s; | 1091 | case eDO_new: |
1092 | size_t name_len = 0; | ||
1093 | char const* linda_name = NULL; | ||
1094 | int const top = lua_gettop( L); | ||
1095 | |||
1096 | if( top > 0 && lua_type( L, top) == LUA_TSTRING) | ||
1097 | { | 1092 | { |
1098 | linda_name = lua_tostring( L, top); | 1093 | struct s_Linda* s; |
1099 | name_len = strlen( linda_name); | 1094 | size_t name_len = 0; |
1100 | } | 1095 | char const* linda_name = NULL; |
1096 | int const top = lua_gettop( L); | ||
1101 | 1097 | ||
1102 | /* The deep data is allocated separately of Lua stack; we might no | 1098 | if( top > 0 && lua_type( L, top) == LUA_TSTRING) |
1103 | * longer be around when last reference to it is being released. | 1099 | { |
1104 | * One can use any memory allocation scheme. | 1100 | linda_name = lua_tolstring( L, top, &name_len); |
1105 | */ | 1101 | } |
1106 | s = (struct s_Linda*) malloc( sizeof(struct s_Linda) + name_len); // terminating 0 is already included | ||
1107 | ASSERT_L( s); | ||
1108 | |||
1109 | SIGNAL_INIT( &s->read_happened); | ||
1110 | SIGNAL_INIT( &s->write_happened); | ||
1111 | s->simulate_cancel = CANCEL_NONE; | ||
1112 | s->name[0] = 0; | ||
1113 | memcpy( s->name, linda_name, name_len ? name_len + 1 : 0); | ||
1114 | 1102 | ||
1115 | lua_pushlightuserdata( L, s); | 1103 | /* The deep data is allocated separately of Lua stack; we might no |
1116 | } | 1104 | * longer be around when last reference to it is being released. |
1117 | else if( strcmp( which, "delete") == 0) | 1105 | * One can use any memory allocation scheme. |
1118 | { | 1106 | */ |
1119 | struct s_Keeper* K; | 1107 | s = (struct s_Linda*) malloc( sizeof(struct s_Linda) + name_len); // terminating 0 is already included |
1120 | struct s_Linda* l = lua_touserdata( L, 1); | 1108 | ASSERT_L( s); |
1121 | ASSERT_L( l); | 1109 | |
1110 | SIGNAL_INIT( &s->read_happened); | ||
1111 | SIGNAL_INIT( &s->write_happened); | ||
1112 | s->simulate_cancel = CANCEL_NONE; | ||
1113 | s->name[0] = 0; | ||
1114 | memcpy( s->name, linda_name, name_len ? name_len + 1 : 0); | ||
1115 | return s; | ||
1116 | } | ||
1122 | 1117 | ||
1123 | /* Clean associated structures in the keeper state. | 1118 | case eDO_delete: |
1124 | */ | ||
1125 | K = keeper_acquire( l); | ||
1126 | if( K && K->L) // can be NULL if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup) | ||
1127 | { | 1119 | { |
1128 | keeper_call( K->L, KEEPER_API( clear), L, l, 0); | 1120 | struct s_Keeper* K; |
1121 | struct s_Linda* l = lua_touserdata( L, 1); | ||
1122 | ASSERT_L( l); | ||
1123 | |||
1124 | /* Clean associated structures in the keeper state. | ||
1125 | */ | ||
1126 | K = keeper_acquire( l); | ||
1127 | if( K && K->L) // can be NULL if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup) | ||
1128 | { | ||
1129 | keeper_call( K->L, KEEPER_API( clear), L, l, 0); | ||
1130 | } | ||
1131 | keeper_release( K); | ||
1132 | |||
1133 | /* There aren't any lanes waiting on these lindas, since all proxies | ||
1134 | * have been gc'ed. Right? | ||
1135 | */ | ||
1136 | SIGNAL_FREE( &l->read_happened); | ||
1137 | SIGNAL_FREE( &l->write_happened); | ||
1138 | free( l); | ||
1139 | return NULL; | ||
1129 | } | 1140 | } |
1130 | keeper_release( K); | ||
1131 | 1141 | ||
1132 | /* There aren't any lanes waiting on these lindas, since all proxies | 1142 | case eDO_metatable: |
1133 | * have been gc'ed. Right? | 1143 | { |
1134 | */ | ||
1135 | SIGNAL_FREE( &l->read_happened); | ||
1136 | SIGNAL_FREE( &l->write_happened); | ||
1137 | free( l); | ||
1138 | } | ||
1139 | else if( strcmp( which, "metatable" ) == 0) | ||
1140 | { | ||
1141 | 1144 | ||
1142 | STACK_CHECK( L); | 1145 | STACK_CHECK( L); |
1143 | lua_newtable( L); | 1146 | lua_newtable( L); |
1144 | // metatable is its own index | 1147 | // metatable is its own index |
1145 | lua_pushvalue( L, -1); | 1148 | lua_pushvalue( L, -1); |
1146 | lua_setfield( L, -2, "__index"); | 1149 | lua_setfield( L, -2, "__index"); |
1147 | 1150 | ||
1148 | // protect metatable from external access | 1151 | // protect metatable from external access |
1149 | lua_pushliteral( L, "Linda"); | 1152 | lua_pushliteral( L, "Linda"); |
1150 | lua_setfield( L, -2, "__metatable"); | 1153 | lua_setfield( L, -2, "__metatable"); |
1151 | 1154 | ||
1152 | lua_pushcfunction( L, LG_linda_tostring); | 1155 | lua_pushcfunction( L, LG_linda_tostring); |
1153 | lua_setfield( L, -2, "__tostring"); | 1156 | lua_setfield( L, -2, "__tostring"); |
1154 | 1157 | ||
1155 | // Decoda __towatch support | 1158 | // Decoda __towatch support |
1156 | lua_pushcfunction( L, LG_linda_dump); | 1159 | lua_pushcfunction( L, LG_linda_dump); |
1157 | lua_setfield( L, -2, "__towatch"); | 1160 | lua_setfield( L, -2, "__towatch"); |
1158 | 1161 | ||
1159 | lua_pushcfunction( L, LG_linda_concat); | 1162 | lua_pushcfunction( L, LG_linda_concat); |
1160 | lua_setfield( L, -2, "__concat"); | 1163 | lua_setfield( L, -2, "__concat"); |
1161 | 1164 | ||
1162 | // [-1]: linda metatable | 1165 | // [-1]: linda metatable |
1163 | lua_pushcfunction( L, LG_linda_send); | 1166 | lua_pushcfunction( L, LG_linda_send); |
1164 | lua_setfield( L, -2, "send"); | 1167 | lua_setfield( L, -2, "send"); |
1165 | 1168 | ||
1166 | lua_pushcfunction( L, LG_linda_receive); | 1169 | lua_pushcfunction( L, LG_linda_receive); |
1167 | lua_setfield( L, -2, "receive"); | 1170 | lua_setfield( L, -2, "receive"); |
1168 | 1171 | ||
1169 | lua_pushcfunction( L, LG_linda_limit); | 1172 | lua_pushcfunction( L, LG_linda_limit); |
1170 | lua_setfield( L, -2, "limit"); | 1173 | lua_setfield( L, -2, "limit"); |
1171 | 1174 | ||
1172 | lua_pushcfunction( L, LG_linda_set); | 1175 | lua_pushcfunction( L, LG_linda_set); |
1173 | lua_setfield( L, -2, "set"); | 1176 | lua_setfield( L, -2, "set"); |
1174 | 1177 | ||
1175 | lua_pushcfunction( L, LG_linda_count); | 1178 | lua_pushcfunction( L, LG_linda_count); |
1176 | lua_setfield( L, -2, "count"); | 1179 | lua_setfield( L, -2, "count"); |
1177 | 1180 | ||
1178 | lua_pushcfunction( L, LG_linda_get); | 1181 | lua_pushcfunction( L, LG_linda_get); |
1179 | lua_setfield( L, -2, "get"); | 1182 | lua_setfield( L, -2, "get"); |
1180 | 1183 | ||
1181 | lua_pushcfunction( L, LG_linda_cancel); | 1184 | lua_pushcfunction( L, LG_linda_cancel); |
1182 | lua_setfield( L, -2, "cancel"); | 1185 | lua_setfield( L, -2, "cancel"); |
1183 | 1186 | ||
1184 | lua_pushcfunction( L, LG_linda_deep); | 1187 | lua_pushcfunction( L, LG_linda_deep); |
1185 | lua_setfield( L, -2, "deep"); | 1188 | lua_setfield( L, -2, "deep"); |
1186 | 1189 | ||
1187 | lua_pushcfunction( L, LG_linda_dump); | 1190 | lua_pushcfunction( L, LG_linda_dump); |
1188 | lua_setfield( L, -2, "dump"); | 1191 | lua_setfield( L, -2, "dump"); |
1189 | 1192 | ||
1190 | lua_pushliteral( L, BATCH_SENTINEL); | 1193 | lua_pushliteral( L, BATCH_SENTINEL); |
1191 | lua_setfield(L, -2, "batched"); | 1194 | lua_setfield(L, -2, "batched"); |
1192 | 1195 | ||
1193 | STACK_END( L, 1); | 1196 | STACK_END( L, 1); |
1194 | } | 1197 | return NULL; |
1195 | else if( strcmp( which, "module") == 0) | 1198 | } |
1196 | { | 1199 | |
1200 | case eDO_module: | ||
1197 | // linda is a special case because we know lanes must be loaded from the main lua state | 1201 | // linda is a special case because we know lanes must be loaded from the main lua state |
1198 | // to be able to ever get here, so we know it will remain loaded as long a the main state is around | 1202 | // to be able to ever get here, so we know it will remain loaded as long a the main state is around |
1199 | // in other words, forever. | 1203 | // in other words, forever. |
1200 | lua_pushnil( L); | 1204 | default: |
1201 | // other idfuncs must push a string naming the module they come from | 1205 | { |
1202 | //lua_pushliteral( L, "lanes.core"); | 1206 | return NULL; |
1207 | } | ||
1203 | } | 1208 | } |
1204 | } | 1209 | } |
1205 | 1210 | ||
@@ -1214,7 +1219,7 @@ LUAG_FUNC( linda) | |||
1214 | luaL_argcheck( L, top <= 1, top, "too many arguments"); | 1219 | luaL_argcheck( L, top <= 1, top, "too many arguments"); |
1215 | if( top == 1) | 1220 | if( top == 1) |
1216 | luaL_checktype( L, 1, LUA_TSTRING); | 1221 | luaL_checktype( L, 1, LUA_TSTRING); |
1217 | return luaG_deep_userdata( L, linda_id); | 1222 | return luaG_newdeepuserdata( L, linda_id); |
1218 | } | 1223 | } |
1219 | 1224 | ||
1220 | /* | 1225 | /* |
@@ -2199,7 +2204,7 @@ LUAG_FUNC( thread_new) | |||
2199 | // which might not be the case if the libs list didn't include lanes.core or "*" | 2204 | // which might not be the case if the libs list didn't include lanes.core or "*" |
2200 | if( strncmp( name, "lanes.core", len) == 0) // this works both both "lanes" and "lanes.core" because of len | 2205 | if( strncmp( name, "lanes.core", len) == 0) // this works both both "lanes" and "lanes.core" because of len |
2201 | { | 2206 | { |
2202 | luaG_copy_one_time_settings( L, L2, name); | 2207 | luaG_copy_one_time_settings( L, L2); |
2203 | } | 2208 | } |
2204 | lua_pushlstring( L2, name, len); // require() name | 2209 | lua_pushlstring( L2, name, len); // require() name |
2205 | if( lua_pcall( L2, 1, 1, 0) != LUA_OK) // ret/errcode | 2210 | if( lua_pcall( L2, 1, 1, 0) != LUA_OK) // ret/errcode |
@@ -2324,8 +2329,8 @@ LUAG_FUNC( thread_new) | |||
2324 | MUTEX_INIT( &s->done_lock); | 2329 | MUTEX_INIT( &s->done_lock); |
2325 | SIGNAL_INIT( &s->done_signal); | 2330 | SIGNAL_INIT( &s->done_signal); |
2326 | #endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR | 2331 | #endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR |
2327 | s->mstatus= NORMAL; | 2332 | s->mstatus = NORMAL; |
2328 | s->selfdestruct_next= NULL; | 2333 | s->selfdestruct_next = NULL; |
2329 | #if HAVE_LANE_TRACKING | 2334 | #if HAVE_LANE_TRACKING |
2330 | s->tracking_next = NULL; | 2335 | s->tracking_next = NULL; |
2331 | #endif // HAVE_LANE_TRACKING | 2336 | #endif // HAVE_LANE_TRACKING |
@@ -2969,7 +2974,7 @@ static void init_once_LOCKED( lua_State* L) | |||
2969 | // proxy_ud= deep_userdata( idfunc ) | 2974 | // proxy_ud= deep_userdata( idfunc ) |
2970 | // | 2975 | // |
2971 | lua_pushliteral( L, "lanes-timer"); // push a name for debug purposes | 2976 | lua_pushliteral( L, "lanes-timer"); // push a name for debug purposes |
2972 | luaG_deep_userdata( L, linda_id); | 2977 | luaG_newdeepuserdata( L, linda_id); |
2973 | STACK_MID( L, 2); | 2978 | STACK_MID( L, 2); |
2974 | lua_remove( L, -2); // remove the name as we no longer need it | 2979 | lua_remove( L, -2); // remove the name as we no longer need it |
2975 | 2980 | ||
@@ -2978,7 +2983,7 @@ static void init_once_LOCKED( lua_State* L) | |||
2978 | // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer | 2983 | // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer |
2979 | // | 2984 | // |
2980 | timer_deep = * (DEEP_PRELUDE**) lua_touserdata( L, -1); | 2985 | timer_deep = * (DEEP_PRELUDE**) lua_touserdata( L, -1); |
2981 | ASSERT_L( timer_deep && (timer_deep->refcount == 1) && timer_deep->deep); | 2986 | ASSERT_L( timer_deep && (timer_deep->refcount == 1) && timer_deep->deep && timer_deep->idfunc == linda_id); |
2982 | 2987 | ||
2983 | // The host Lua state must always have a reference to this Linda object in order for the timer_deep pointer to be valid. | 2988 | // The host Lua state must always have a reference to this Linda object in order for the timer_deep pointer to be valid. |
2984 | // So store a reference that we will never actually use. | 2989 | // So store a reference that we will never actually use. |
@@ -3019,7 +3024,7 @@ LUAG_FUNC( configure) | |||
3019 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); | 3024 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); |
3020 | 3025 | ||
3021 | // not in init_once_LOCKED because we can have several hosted "master" Lua states where Lanes is require()d. | 3026 | // not in init_once_LOCKED because we can have several hosted "master" Lua states where Lanes is require()d. |
3022 | lua_getfield( L, 1, "protect_allocator"); // settings protect_allocator | 3027 | lua_getfield( L, 1, "protect_allocator"); // settings protect_allocator |
3023 | if( lua_toboolean( L, -1)) | 3028 | if( lua_toboolean( L, -1)) |
3024 | { | 3029 | { |
3025 | void* ud; | 3030 | void* ud; |
@@ -3033,7 +3038,7 @@ LUAG_FUNC( configure) | |||
3033 | lua_setallocf( L, protected_lua_Alloc, s); | 3038 | lua_setallocf( L, protected_lua_Alloc, s); |
3034 | } | 3039 | } |
3035 | } | 3040 | } |
3036 | lua_pop( L, 1); // settings | 3041 | lua_pop( L, 1); // settings |
3037 | STACK_MID( L, 0); | 3042 | STACK_MID( L, 0); |
3038 | 3043 | ||
3039 | /* | 3044 | /* |
@@ -3075,68 +3080,75 @@ LUAG_FUNC( configure) | |||
3075 | #endif // THREADAPI == THREADAPI_PTHREAD | 3080 | #endif // THREADAPI == THREADAPI_PTHREAD |
3076 | 3081 | ||
3077 | // Retrieve main module interface table | 3082 | // Retrieve main module interface table |
3078 | lua_pushvalue( L, lua_upvalueindex( 2)); // settings M | 3083 | lua_pushvalue( L, lua_upvalueindex( 2)); // settings M |
3079 | // remove configure() (this function) from the module interface | 3084 | // remove configure() (this function) from the module interface |
3080 | lua_pushnil( L); // settings M nil | 3085 | lua_pushnil( L); // settings M nil |
3081 | lua_setfield( L, -2, "configure"); // settings M | 3086 | lua_setfield( L, -2, "configure"); // settings M |
3082 | // add functions to the module's table | 3087 | // add functions to the module's table |
3083 | luaG_registerlibfuncs( L, lanes_functions); | 3088 | luaG_registerlibfuncs( L, lanes_functions); |
3084 | #if HAVE_LANE_TRACKING | 3089 | #if HAVE_LANE_TRACKING |
3085 | // register core.threads() only if settings say it should be available | 3090 | // register core.threads() only if settings say it should be available |
3086 | if( tracking_first != NULL) | 3091 | if( tracking_first != NULL) |
3087 | { | 3092 | { |
3088 | lua_pushcfunction( L, LG_threads); // settings M LG_threads() | 3093 | lua_pushcfunction( L, LG_threads); // settings M LG_threads() |
3089 | lua_setfield( L, -2, "threads"); | 3094 | lua_setfield( L, -2, "threads"); // settings M |
3090 | } | 3095 | } |
3091 | #endif // HAVE_LANE_TRACKING | 3096 | #endif // HAVE_LANE_TRACKING |
3092 | STACK_MID( L, 1); | 3097 | STACK_MID( L, 1); |
3093 | 3098 | ||
3094 | ASSERT_L( timer_deep != NULL); // initialized by init_once_LOCKED | 3099 | { |
3095 | luaG_push_proxy( L, linda_id, (DEEP_PRELUDE*) timer_deep); // settings M timer_deep | 3100 | char const* errmsg; |
3096 | lua_setfield( L, -2, "timer_gateway"); // settings M | 3101 | ASSERT_L( timer_deep != NULL); // initialized by init_once_LOCKED |
3102 | errmsg = push_deep_proxy( L, (DEEP_PRELUDE*) timer_deep, eLM_LaneBody); // settings M timer_deep | ||
3103 | if( errmsg != NULL) | ||
3104 | { | ||
3105 | luaL_error( L, errmsg); | ||
3106 | } | ||
3107 | lua_setfield( L, -2, "timer_gateway"); // settings M | ||
3108 | } | ||
3097 | STACK_MID( L, 1); | 3109 | STACK_MID( L, 1); |
3098 | 3110 | ||
3099 | // prepare the metatable for threads | 3111 | // prepare the metatable for threads |
3100 | // contains keys: { __gc, __index, cached_error, cached_tostring, cancel, join, get_debug_threadname } | 3112 | // contains keys: { __gc, __index, cached_error, cached_tostring, cancel, join, get_debug_threadname } |
3101 | // | 3113 | // |
3102 | if( luaL_newmetatable( L, "Lane")) // settings M mt | 3114 | if( luaL_newmetatable( L, "Lane")) // settings M mt |
3103 | { | 3115 | { |
3104 | lua_pushcfunction( L, LG_thread_gc); // settings M mt LG_thread_gc | 3116 | lua_pushcfunction( L, LG_thread_gc); // settings M mt LG_thread_gc |
3105 | lua_setfield( L, -2, "__gc"); // settings M mt | 3117 | lua_setfield( L, -2, "__gc"); // settings M mt |
3106 | lua_pushcfunction( L, LG_thread_index); // settings M mt LG_thread_index | 3118 | lua_pushcfunction( L, LG_thread_index); // settings M mt LG_thread_index |
3107 | lua_setfield( L, -2, "__index"); // settings M mt | 3119 | lua_setfield( L, -2, "__index"); // settings M mt |
3108 | lua_getglobal( L, "error"); // settings M mt error | 3120 | lua_getglobal( L, "error"); // settings M mt error |
3109 | ASSERT_L( lua_isfunction( L, -1)); | 3121 | ASSERT_L( lua_isfunction( L, -1)); |
3110 | lua_setfield( L, -2, "cached_error"); // settings M mt | 3122 | lua_setfield( L, -2, "cached_error"); // settings M mt |
3111 | lua_getglobal( L, "tostring"); // settings M mt tostring | 3123 | lua_getglobal( L, "tostring"); // settings M mt tostring |
3112 | ASSERT_L( lua_isfunction( L, -1)); | 3124 | ASSERT_L( lua_isfunction( L, -1)); |
3113 | lua_setfield( L, -2, "cached_tostring"); // settings M mt | 3125 | lua_setfield( L, -2, "cached_tostring"); // settings M mt |
3114 | lua_pushcfunction( L, LG_thread_join); // settings M mt LG_thread_join | 3126 | lua_pushcfunction( L, LG_thread_join); // settings M mt LG_thread_join |
3115 | lua_setfield( L, -2, "join"); // settings M mt | 3127 | lua_setfield( L, -2, "join"); // settings M mt |
3116 | lua_pushcfunction( L, LG_get_debug_threadname); // settings M mt LG_get_debug_threadname | 3128 | lua_pushcfunction( L, LG_get_debug_threadname); // settings M mt LG_get_debug_threadname |
3117 | lua_setfield( L, -2, "get_debug_threadname"); // settings M mt | 3129 | lua_setfield( L, -2, "get_debug_threadname"); // settings M mt |
3118 | lua_pushcfunction( L, LG_thread_cancel); // settings M mt LG_thread_cancel | 3130 | lua_pushcfunction( L, LG_thread_cancel); // settings M mt LG_thread_cancel |
3119 | lua_setfield( L, -2, "cancel"); // settings M mt | 3131 | lua_setfield( L, -2, "cancel"); // settings M mt |
3120 | lua_pushliteral( L, "Lane"); // settings M mt "Lane" | 3132 | lua_pushliteral( L, "Lane"); // settings M mt "Lane" |
3121 | lua_setfield( L, -2, "__metatable"); // settings M mt | 3133 | lua_setfield( L, -2, "__metatable"); // settings M mt |
3122 | } | 3134 | } |
3123 | 3135 | ||
3124 | lua_pushcclosure( L, LG_thread_new, 1); // settings M LG_thread_new | 3136 | lua_pushcclosure( L, LG_thread_new, 1); // settings M LG_thread_new |
3125 | lua_setfield( L, -2, "thread_new"); // settings M | 3137 | lua_setfield( L, -2, "thread_new"); // settings M |
3126 | 3138 | ||
3127 | // we can't register 'lanes.require' normally because we want to create an upvalued closure | 3139 | // we can't register 'lanes.require' normally because we want to create an upvalued closure |
3128 | lua_getglobal( L, "require"); // settings M require | 3140 | lua_getglobal( L, "require"); // settings M require |
3129 | lua_pushcclosure( L, LG_require, 1); // settings M lanes.require | 3141 | lua_pushcclosure( L, LG_require, 1); // settings M lanes.require |
3130 | lua_setfield( L, -2, "require"); // settings M | 3142 | lua_setfield( L, -2, "require"); // settings M |
3131 | 3143 | ||
3132 | lua_pushstring(L, VERSION); // settings M VERSION | 3144 | lua_pushstring(L, VERSION); // settings M VERSION |
3133 | lua_setfield(L, -2, "version"); // settings M | 3145 | lua_setfield(L, -2, "version"); // settings M |
3134 | 3146 | ||
3135 | lua_pushinteger(L, THREAD_PRIO_MAX); // settings M THREAD_PRIO_MAX | 3147 | lua_pushinteger(L, THREAD_PRIO_MAX); // settings M THREAD_PRIO_MAX |
3136 | lua_setfield(L, -2, "max_prio"); // settings M | 3148 | lua_setfield(L, -2, "max_prio"); // settings M |
3137 | 3149 | ||
3138 | lua_pushlightuserdata( L, CANCEL_ERROR); // settings M CANCEL_ERROR | 3150 | lua_pushlightuserdata( L, CANCEL_ERROR); // settings M CANCEL_ERROR |
3139 | lua_setfield(L, -2, "cancel_error"); // settings M | 3151 | lua_setfield(L, -2, "cancel_error"); // settings M |
3140 | 3152 | ||
3141 | // register all native functions found in that module in the transferable functions database | 3153 | // register all native functions found in that module in the transferable functions database |
3142 | // we process it before _G because we don't want to find the module when scanning _G (this would generate longer names) | 3154 | // we process it before _G because we don't want to find the module when scanning _G (this would generate longer names) |
@@ -3151,7 +3163,7 @@ LUAG_FUNC( configure) | |||
3151 | // set _R[CONFIG_REGKEY] = settings | 3163 | // set _R[CONFIG_REGKEY] = settings |
3152 | lua_pushvalue( L, -2); // settings M settings | 3164 | lua_pushvalue( L, -2); // settings M settings |
3153 | lua_setfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); // settings M | 3165 | lua_setfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); // settings M |
3154 | lua_pop( L, 1); // settings | 3166 | lua_pop( L, 1); // settings |
3155 | STACK_END( L, 0); | 3167 | STACK_END( L, 0); |
3156 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() END\n" INDENT_END, L)); | 3168 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() END\n" INDENT_END, L)); |
3157 | DEBUGSPEW_CODE( -- debugspew_indent_depth); | 3169 | DEBUGSPEW_CODE( -- debugspew_indent_depth); |
diff --git a/src/tools.c b/src/tools.c index fc3e7e0..2aa9b82 100644 --- a/src/tools.c +++ b/src/tools.c | |||
@@ -195,14 +195,14 @@ int initialize_on_state_create( lua_State* L) | |||
195 | } | 195 | } |
196 | 196 | ||
197 | // just like lua_xmove, args are (from, to) | 197 | // just like lua_xmove, args are (from, to) |
198 | void luaG_copy_one_time_settings( lua_State* L, lua_State* L2, char const* name_) | 198 | void luaG_copy_one_time_settings( lua_State* L, lua_State* L2) |
199 | { | 199 | { |
200 | STACK_GROW( L, 1); | 200 | STACK_GROW( L, 1); |
201 | // copy settings from from source to destination registry | 201 | // copy settings from from source to destination registry |
202 | lua_getfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); | 202 | lua_getfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); |
203 | if( luaG_inter_move( L, L2, 1, eLM_LaneBody) < 0) // error? | 203 | if( luaG_inter_move( L, L2, 1, eLM_LaneBody) < 0) // error? |
204 | { | 204 | { |
205 | (void) luaL_error( L, "failed to copy settings when loading %s", name_); | 205 | (void) luaL_error( L, "failed to copy settings when loading lanes.core"); |
206 | } | 206 | } |
207 | lua_setfield( L2, LUA_REGISTRYINDEX, CONFIG_REGKEY); | 207 | lua_setfield( L2, LUA_REGISTRYINDEX, CONFIG_REGKEY); |
208 | } | 208 | } |
@@ -258,7 +258,7 @@ static void open1lib( lua_State* L, char const* name_, size_t len_, lua_State* f | |||
258 | if( isLanesCore == TRUE) | 258 | if( isLanesCore == TRUE) |
259 | { | 259 | { |
260 | // copy settings from from source to destination registry | 260 | // copy settings from from source to destination registry |
261 | luaG_copy_one_time_settings( from_, L, name_); | 261 | luaG_copy_one_time_settings( from_, L); |
262 | } | 262 | } |
263 | // open the library as if through require(), and create a global as well if necessary (the library table is left on the stack) | 263 | // open the library as if through require(), and create a global as well if necessary (the library table is left on the stack) |
264 | luaL_requiref( L, name_, libfunc, !isLanesCore); | 264 | luaL_requiref( L, name_, libfunc, !isLanesCore); |
@@ -591,28 +591,61 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* name_) | |||
591 | DEBUGSPEW_CODE( -- debugspew_indent_depth); | 591 | DEBUGSPEW_CODE( -- debugspew_indent_depth); |
592 | } | 592 | } |
593 | 593 | ||
594 | void call_on_state_create( lua_State* L, lua_State* from_, enum eLookupMode mode_) | ||
595 | { | ||
596 | if( s_on_state_create_func != NULL) | ||
597 | { | ||
598 | STACK_CHECK( L); | ||
599 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "calling on_state_create()\n" INDENT_END)); | ||
600 | if( s_on_state_create_func != initialize_on_state_create) | ||
601 | { | ||
602 | // C function: recreate a closure in the new state, bypassing the lookup scheme | ||
603 | lua_pushcfunction( L, s_on_state_create_func); | ||
604 | } | ||
605 | else // Lua function located in the config table, copied when we opened "lanes.core" | ||
606 | { | ||
607 | if( mode_ != eLM_LaneBody) | ||
608 | { | ||
609 | // if attempting to call in a keeper state, do nothing because the function doesn't exist there | ||
610 | return; | ||
611 | } | ||
612 | lua_getfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); | ||
613 | lua_getfield( L, -1, "on_state_create"); | ||
614 | lua_remove( L, -2); | ||
615 | } | ||
616 | // capture error and forward it to main state | ||
617 | if( lua_pcall( L, 0, 0, 0) != LUA_OK) | ||
618 | { | ||
619 | (void) luaL_error( from_, "on_state_create failed: \"%s\"", lua_isstring( L, -1) ? lua_tostring( L, -1) : lua_typename( L, lua_type( L, -1))); | ||
620 | } | ||
621 | STACK_END( L, 0); | ||
622 | } | ||
623 | } | ||
624 | |||
594 | /* | 625 | /* |
595 | * Like 'luaL_openlibs()' but allows the set of libraries be selected | 626 | * Like 'luaL_openlibs()' but allows the set of libraries be selected |
596 | * | 627 | * |
597 | * NULL no libraries, not even base | 628 | * NULL no libraries, not even base |
598 | * "" base library only | 629 | * "" base library only |
599 | * "io,string" named libraries | 630 | * "io,string" named libraries |
600 | * "*" all libraries | 631 | * "*" all libraries |
601 | * | 632 | * |
602 | * Base ("unpack", "print" etc.) is always added, unless 'libs' is NULL. | 633 | * Base ("unpack", "print" etc.) is always added, unless 'libs' is NULL. |
603 | * | 634 | * |
604 | */ | 635 | * *NOT* called for keeper states! |
605 | lua_State* luaG_newstate( lua_State* _from, char const* libs) | 636 | * |
637 | */ | ||
638 | lua_State* luaG_newstate( lua_State* from_, char const* libs_) | ||
606 | { | 639 | { |
607 | // reuse alloc function from the originating state | 640 | // reuse alloc function from the originating state |
608 | #if PROPAGATE_ALLOCF | 641 | #if PROPAGATE_ALLOCF |
609 | PROPAGATE_ALLOCF_PREP( _from); | 642 | PROPAGATE_ALLOCF_PREP( from_); |
610 | #endif // PROPAGATE_ALLOCF | 643 | #endif // PROPAGATE_ALLOCF |
611 | lua_State* L = PROPAGATE_ALLOCF_ALLOC(); | 644 | lua_State* L = PROPAGATE_ALLOCF_ALLOC(); |
612 | 645 | ||
613 | if( L == NULL) | 646 | if( L == NULL) |
614 | { | 647 | { |
615 | (void) luaL_error( _from, "luaG_newstate() failed while creating state; out of memory"); | 648 | (void) luaL_error( from_, "luaG_newstate() failed while creating state; out of memory"); |
616 | } | 649 | } |
617 | 650 | ||
618 | // we'll need this everytime we transfer some C function from/to this state | 651 | // we'll need this everytime we transfer some C function from/to this state |
@@ -620,7 +653,7 @@ lua_State* luaG_newstate( lua_State* _from, char const* libs) | |||
620 | lua_setfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY); | 653 | lua_setfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY); |
621 | 654 | ||
622 | // neither libs (not even 'base') nor special init func: we are done | 655 | // neither libs (not even 'base') nor special init func: we are done |
623 | if( libs == NULL && s_on_state_create_func == NULL) | 656 | if( libs_ == NULL && s_on_state_create_func == NULL) |
624 | { | 657 | { |
625 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_newstate(NULL)\n" INDENT_END)); | 658 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_newstate(NULL)\n" INDENT_END)); |
626 | return L; | 659 | return L; |
@@ -636,17 +669,17 @@ lua_State* luaG_newstate( lua_State* _from, char const* libs) | |||
636 | 669 | ||
637 | // Anything causes 'base' to be taken in | 670 | // Anything causes 'base' to be taken in |
638 | // | 671 | // |
639 | if( libs != NULL) | 672 | if( libs_ != NULL) |
640 | { | 673 | { |
641 | // special "*" case (mainly to help with LuaJIT compatibility) | 674 | // special "*" case (mainly to help with LuaJIT compatibility) |
642 | // as we are called from luaopen_lanes_core() already, and that would deadlock | 675 | // as we are called from luaopen_lanes_core() already, and that would deadlock |
643 | if( libs[0] == '*' && libs[1] == 0) | 676 | if( libs_[0] == '*' && libs_[1] == 0) |
644 | { | 677 | { |
645 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening ALL standard libraries\n" INDENT_END)); | 678 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening ALL standard libraries\n" INDENT_END)); |
646 | luaL_openlibs( L); | 679 | luaL_openlibs( L); |
647 | // don't forget lanes.core for regular lane states | 680 | // don't forget lanes.core for regular lane states |
648 | open1lib( L, "lanes.core", 10, _from); | 681 | open1lib( L, "lanes.core", 10, from_); |
649 | libs = NULL; // done with libs | 682 | libs_ = NULL; // done with libs |
650 | } | 683 | } |
651 | else | 684 | else |
652 | { | 685 | { |
@@ -665,11 +698,11 @@ lua_State* luaG_newstate( lua_State* _from, char const* libs) | |||
665 | STACK_END( L, 0); | 698 | STACK_END( L, 0); |
666 | 699 | ||
667 | // scan all libraries, open them one by one | 700 | // scan all libraries, open them one by one |
668 | if( libs) | 701 | if( libs_) |
669 | { | 702 | { |
670 | char const* p; | 703 | char const* p; |
671 | unsigned int len = 0; | 704 | unsigned int len = 0; |
672 | for( p = libs; *p; p += len) | 705 | for( p = libs_; *p; p += len) |
673 | { | 706 | { |
674 | // skip delimiters ('.' can be part of name for "lanes.core") | 707 | // skip delimiters ('.' can be part of name for "lanes.core") |
675 | while( *p && !isalnum( *p) && *p != '.') | 708 | while( *p && !isalnum( *p) && *p != '.') |
@@ -679,37 +712,17 @@ lua_State* luaG_newstate( lua_State* _from, char const* libs) | |||
679 | while( isalnum( p[len]) || p[len] == '.') | 712 | while( isalnum( p[len]) || p[len] == '.') |
680 | ++ len; | 713 | ++ len; |
681 | // open library | 714 | // open library |
682 | open1lib( L, p, len, _from); | 715 | open1lib( L, p, len, from_); |
683 | } | 716 | } |
684 | serialize_require( L); | 717 | serialize_require( L); |
685 | } | 718 | } |
686 | 719 | ||
687 | lua_gc( L, LUA_GCRESTART, 0); | 720 | lua_gc( L, LUA_GCRESTART, 0); |
688 | 721 | ||
689 | STACK_CHECK( L); | ||
690 | // call this after the base libraries are loaded and GC is restarted | 722 | // call this after the base libraries are loaded and GC is restarted |
691 | if( s_on_state_create_func != NULL) | 723 | call_on_state_create( L, from_, eLM_LaneBody); |
692 | { | ||
693 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "calling on_state_create()\n" INDENT_END)); | ||
694 | if( s_on_state_create_func != initialize_on_state_create) | ||
695 | { | ||
696 | // C function: recreate a closure in the new state, bypassing the lookup scheme | ||
697 | lua_pushcfunction( L, s_on_state_create_func); | ||
698 | } | ||
699 | else // Lua function located in the config table | ||
700 | { | ||
701 | lua_getfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); | ||
702 | lua_getfield( L, -1, "on_state_create"); | ||
703 | lua_remove( L, -2); | ||
704 | } | ||
705 | // capture error and forward it to main state | ||
706 | if( lua_pcall( L, 0, 0, 0) != LUA_OK) | ||
707 | { | ||
708 | (void) luaL_error( _from, "on_state_create failed: \"%s\"", lua_isstring( L, -1) ? lua_tostring( L, -1) : lua_typename( L, lua_type( L, -1))); | ||
709 | } | ||
710 | STACK_MID( L, 0); | ||
711 | } | ||
712 | 724 | ||
725 | STACK_CHECK( L); | ||
713 | // after all this, register everything we find in our name<->function database | 726 | // after all this, register everything we find in our name<->function database |
714 | lua_pushglobaltable( L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack | 727 | lua_pushglobaltable( L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack |
715 | populate_func_lookup_table( L, -1, NULL); | 728 | populate_func_lookup_table( L, -1, NULL); |
@@ -743,7 +756,7 @@ lua_State* luaG_newstate( lua_State* _from, char const* libs) | |||
743 | /* | 756 | /* |
744 | * The deep proxy cache is a weak valued table listing all deep UD proxies indexed by the deep UD that they are proxying | 757 | * The deep proxy cache is a weak valued table listing all deep UD proxies indexed by the deep UD that they are proxying |
745 | */ | 758 | */ |
746 | #define DEEP_PROXY_CACHE_KEY ((void*)luaG_push_proxy) | 759 | #define DEEP_PROXY_CACHE_KEY ((void*)push_deep_proxy) |
747 | 760 | ||
748 | static void push_registry_subtable_mode( lua_State *L, void *token, const char* mode ); | 761 | static void push_registry_subtable_mode( lua_State *L, void *token, const char* mode ); |
749 | static void push_registry_subtable( lua_State *L, void *token ); | 762 | static void push_registry_subtable( lua_State *L, void *token ); |
@@ -752,107 +765,76 @@ static void push_registry_subtable( lua_State *L, void *token ); | |||
752 | * Sets up [-1]<->[-2] two-way lookups, and ensures the lookup table exists. | 765 | * Sets up [-1]<->[-2] two-way lookups, and ensures the lookup table exists. |
753 | * Pops the both values off the stack. | 766 | * Pops the both values off the stack. |
754 | */ | 767 | */ |
755 | void set_deep_lookup( lua_State *L ) { | 768 | static void set_deep_lookup( lua_State* L) |
756 | 769 | { | |
757 | STACK_GROW(L,3); | 770 | STACK_GROW( L, 3); |
758 | 771 | STACK_CHECK( L); // a b | |
759 | STACK_CHECK( L); | 772 | push_registry_subtable( L, DEEP_LOOKUP_KEY); // a b {} |
760 | #if 1 | 773 | STACK_MID( L, 1); |
761 | push_registry_subtable( L, DEEP_LOOKUP_KEY ); | 774 | lua_insert( L, -3); // {} a b |
762 | #else | 775 | lua_pushvalue( L, -1); // {} a b b |
763 | /* ..to be removed.. */ | 776 | lua_pushvalue( L,-3); // {} a b b a |
764 | lua_pushlightuserdata( L, DEEP_LOOKUP_KEY ); | 777 | lua_rawset( L, -5); // {} a b |
765 | lua_rawget( L, LUA_REGISTRYINDEX ); | 778 | lua_rawset( L, -3); // {} |
766 | 779 | lua_pop( L, 1); // | |
767 | if (lua_isnil(L,-1)) { | 780 | STACK_END( L, -2); |
768 | // First time here; let's make the lookup | ||
769 | // | ||
770 | lua_pop(L,1); | ||
771 | |||
772 | lua_newtable(L); | ||
773 | lua_pushlightuserdata( L, DEEP_LOOKUP_KEY ); | ||
774 | lua_pushvalue(L,-2); | ||
775 | // | ||
776 | // [-3]: {} (2nd ref) | ||
777 | // [-2]: DEEP_LOOKUP_KEY | ||
778 | // [-1]: {} | ||
779 | |||
780 | lua_rawset( L, LUA_REGISTRYINDEX ); | ||
781 | // | ||
782 | // [-1]: lookup table (empty) | ||
783 | } | ||
784 | #endif | ||
785 | STACK_MID( L, 1); | ||
786 | |||
787 | lua_insert(L,-3); | ||
788 | |||
789 | // [-3]: lookup table | ||
790 | // [-2]: A | ||
791 | // [-1]: B | ||
792 | |||
793 | lua_pushvalue( L,-1 ); // B | ||
794 | lua_pushvalue( L,-3 ); // A | ||
795 | lua_rawset( L, -5 ); // B->A | ||
796 | lua_rawset( L, -3 ); // A->B | ||
797 | lua_pop( L,1 ); | ||
798 | |||
799 | STACK_END( L, -2); | ||
800 | } | 781 | } |
801 | 782 | ||
802 | /* | 783 | /* |
803 | * Pops the key (metatable or idfunc) off the stack, and replaces with the | 784 | * Pops the key (metatable or idfunc) off the stack, and replaces with the |
804 | * deep lookup value (idfunc/metatable/nil). | 785 | * deep lookup value (idfunc/metatable/nil). |
805 | */ | 786 | */ |
806 | void get_deep_lookup( lua_State *L ) { | 787 | static void get_deep_lookup( lua_State* L) |
807 | 788 | { | |
808 | STACK_GROW(L,1); | 789 | STACK_GROW( L, 1); |
790 | STACK_CHECK( L); // a | ||
791 | lua_pushlightuserdata( L, DEEP_LOOKUP_KEY); // a DLK | ||
792 | lua_rawget( L, LUA_REGISTRYINDEX); // a {} | ||
809 | 793 | ||
810 | STACK_CHECK( L); | 794 | if( !lua_isnil( L, -1)) |
811 | lua_pushlightuserdata( L, DEEP_LOOKUP_KEY ); | 795 | { |
812 | lua_rawget( L, LUA_REGISTRYINDEX ); | 796 | lua_insert( L, -2); // {} a |
813 | 797 | lua_rawget( L, -2); // {} b | |
814 | if (!lua_isnil(L,-1)) { | 798 | } |
815 | // [-2]: key (metatable or idfunc) | 799 | lua_remove( L, -2); // a|b |
816 | // [-1]: lookup table | 800 | STACK_END( L, 0); |
817 | |||
818 | lua_insert( L, -2 ); | ||
819 | lua_rawget( L, -2 ); | ||
820 | |||
821 | // [-2]: lookup table | ||
822 | // [-1]: value (metatable / idfunc / nil) | ||
823 | } | ||
824 | lua_remove(L,-2); | ||
825 | // remove lookup, or unused key | ||
826 | STACK_END( L, 0); | ||
827 | } | 801 | } |
828 | 802 | ||
829 | /* | 803 | /* |
830 | * Return the registered ID function for 'index' (deep userdata proxy), | 804 | * Return the registered ID function for 'index' (deep userdata proxy), |
831 | * or NULL if 'index' is not a deep userdata proxy. | 805 | * or NULL if 'index' is not a deep userdata proxy. |
832 | */ | 806 | */ |
833 | static | 807 | static inline luaG_IdFunction get_idfunc( lua_State* L, int index, enum eLookupMode mode_) |
834 | luaG_IdFunction get_idfunc( lua_State *L, int index ) | ||
835 | { | 808 | { |
836 | luaG_IdFunction ret; | 809 | // when looking inside a keeper, we are 100% sure the object is a deep userdata |
837 | 810 | if( mode_ == eLM_FromKeeper) | |
838 | index = lua_absindex( L, index); | 811 | { |
839 | 812 | DEEP_PRELUDE** proxy = (DEEP_PRELUDE**) lua_touserdata( L, index); | |
840 | STACK_GROW(L,1); | 813 | // we can (and must) cast and fetch the internally stored idfunc |
841 | 814 | return (*proxy)->idfunc; | |
842 | STACK_CHECK( L); | 815 | } |
843 | if (!lua_getmetatable( L, index )) | 816 | else |
844 | return NULL; // no metatable | 817 | { |
845 | 818 | // essentially we are making sure that the metatable of the object we want to copy is stored in our metatable/idfunc database | |
846 | // [-1]: metatable of [index] | 819 | // it is the only way to ensure that the userdata is indeed a deep userdata! |
820 | // of course, we could just trust the caller, but we won't | ||
821 | luaG_IdFunction ret; | ||
822 | STACK_GROW( L, 1); | ||
823 | STACK_CHECK( L); | ||
824 | |||
825 | if( !lua_getmetatable( L, index)) // deep ... metatable? | ||
826 | { | ||
827 | return NULL; // no metatable: can't be a deep userdata object! | ||
828 | } | ||
847 | 829 | ||
848 | get_deep_lookup(L); | 830 | // replace metatable with the idfunc pointer, if it is actually a deep userdata |
849 | // | 831 | get_deep_lookup( L); // deep ... idfunc|nil |
850 | // [-1]: idfunc/nil | ||
851 | 832 | ||
852 | ret= (luaG_IdFunction)lua_touserdata(L,-1); | 833 | ret = (luaG_IdFunction) lua_touserdata( L, -1); // NULL if not a userdata |
853 | lua_pop(L,1); | 834 | lua_pop( L, 1); |
854 | STACK_END( L, 0); | 835 | STACK_END( L, 0); |
855 | return ret; | 836 | return ret; |
837 | } | ||
856 | } | 838 | } |
857 | 839 | ||
858 | 840 | ||
@@ -862,205 +844,190 @@ luaG_IdFunction get_idfunc( lua_State *L, int index ) | |||
862 | * End of life for a proxy object; reduce the deep reference count and clean | 844 | * End of life for a proxy object; reduce the deep reference count and clean |
863 | * it up if reaches 0. | 845 | * it up if reaches 0. |
864 | */ | 846 | */ |
865 | static | 847 | static int deep_userdata_gc( lua_State* L) |
866 | int deep_userdata_gc( lua_State *L ) | ||
867 | { | 848 | { |
868 | DEEP_PRELUDE **proxy= (DEEP_PRELUDE**)lua_touserdata( L, 1 ); | 849 | DEEP_PRELUDE** proxy = (DEEP_PRELUDE**) lua_touserdata( L, 1); |
869 | DEEP_PRELUDE *p= *proxy; | 850 | DEEP_PRELUDE* p = *proxy; |
870 | int v; | 851 | int v; |
871 | 852 | ||
872 | *proxy= 0; // make sure we don't use it any more | 853 | *proxy = 0; // make sure we don't use it any more |
873 | 854 | ||
874 | MUTEX_LOCK( &deep_lock ); | 855 | MUTEX_LOCK( &deep_lock); |
875 | v= --(p->refcount); | 856 | v = -- (p->refcount); |
876 | MUTEX_UNLOCK( &deep_lock ); | 857 | MUTEX_UNLOCK( &deep_lock); |
877 | |||
878 | if (v==0) | ||
879 | { | ||
880 | // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup | ||
881 | // | ||
882 | luaG_IdFunction idfunc = get_idfunc(L,1); | ||
883 | ASSERT_L(idfunc); | ||
884 | |||
885 | lua_settop( L, 0); // clean stack so we can call 'idfunc' directly | ||
886 | 858 | ||
887 | // void= idfunc( "delete", lightuserdata ) | 859 | if( v == 0) |
888 | // | 860 | { |
889 | lua_pushlightuserdata( L, p->deep ); | 861 | // clean stack so we can call 'idfunc' directly |
890 | idfunc( L, "delete"); | 862 | lua_settop( L, 0); |
891 | 863 | // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup | |
892 | // top was set to 0, then userdata was pushed. "delete" might want to pop the userdata (we don't care), but should not push anything! | 864 | lua_pushlightuserdata( L, p->deep); |
893 | if ( lua_gettop( L) > 1) | 865 | ASSERT_L( p->idfunc); |
894 | luaL_error( L, "Bad idfunc on \"delete\": returned something"); | 866 | p->idfunc( L, eDO_delete); |
895 | 867 | DEEP_FREE( (void*) p); | |
896 | DEEP_FREE( (void*)p ); | 868 | |
897 | } | 869 | // top was set to 0, then userdata was pushed. "delete" might want to pop the userdata (we don't care), but should not push anything! |
898 | return 0; | 870 | if ( lua_gettop( L) > 1) |
871 | { | ||
872 | luaL_error( L, "Bad idfunc(eDO_delete): should not push anything"); | ||
873 | } | ||
874 | } | ||
875 | return 0; | ||
899 | } | 876 | } |
900 | 877 | ||
901 | 878 | ||
902 | /* | 879 | /* |
903 | * Push a proxy userdata on the stack. | 880 | * Push a proxy userdata on the stack. |
904 | * | 881 | * returns NULL if ok, else some error string related to bad idfunc behavior or module require problem |
905 | * Initializes necessary structures if it's the first time 'idfunc' is being | 882 | * (error cannot happen with mode_ == eLM_ToKeeper) |
906 | * used in this Lua state (metatable, registring it). Otherwise, increments the | 883 | * |
907 | * reference count. | 884 | * Initializes necessary structures if it's the first time 'idfunc' is being |
908 | */ | 885 | * used in this Lua state (metatable, registring it). Otherwise, increments the |
909 | void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *prelude ) | 886 | * reference count. |
887 | */ | ||
888 | char const* push_deep_proxy( lua_State* L, DEEP_PRELUDE* prelude, enum eLookupMode mode_) | ||
910 | { | 889 | { |
911 | DEEP_PRELUDE **proxy; | 890 | DEEP_PRELUDE** proxy; |
912 | |||
913 | // Check if a proxy already exists | ||
914 | push_registry_subtable_mode(L, DEEP_PROXY_CACHE_KEY, "v"); | ||
915 | lua_pushlightuserdata(L, prelude->deep); | ||
916 | lua_rawget(L, -2); | ||
917 | if (!lua_isnil(L, -1)) | ||
918 | { | ||
919 | lua_remove(L, -2); // deep proxy cache table | ||
920 | return; | ||
921 | } | ||
922 | else | ||
923 | { | ||
924 | lua_pop(L, 2); // Pop the nil and proxy cache table | ||
925 | } | ||
926 | |||
927 | MUTEX_LOCK( &deep_lock ); | ||
928 | ++(prelude->refcount); // one more proxy pointing to this deep data | ||
929 | MUTEX_UNLOCK( &deep_lock ); | ||
930 | |||
931 | STACK_GROW(L,4); | ||
932 | |||
933 | STACK_CHECK( L); | ||
934 | |||
935 | proxy= lua_newuserdata( L, sizeof( DEEP_PRELUDE* ) ); | ||
936 | ASSERT_L(proxy); | ||
937 | *proxy= prelude; | ||
938 | 891 | ||
939 | // Get/create metatable for 'idfunc' (in this state) | 892 | // Check if a proxy already exists |
940 | // | 893 | push_registry_subtable_mode( L, DEEP_PROXY_CACHE_KEY, "v"); // DPC |
941 | lua_pushlightuserdata( L, idfunc ); // key | 894 | lua_pushlightuserdata( L, prelude->deep); // DPC deep |
942 | get_deep_lookup(L); | 895 | lua_rawget( L, -2); // DPC proxy |
943 | // | 896 | if ( !lua_isnil( L, -1)) |
944 | // [-2]: proxy | 897 | { |
945 | // [-1]: metatable / nil | 898 | lua_remove( L, -2); // proxy |
946 | 899 | return NULL; | |
947 | if (lua_isnil(L,-1)) | 900 | } |
948 | { | 901 | else |
949 | // No metatable yet. We have two things to do: | 902 | { |
950 | // 1 - make one and register it | 903 | lua_pop( L, 1); // DPC |
951 | { | 904 | } |
952 | int oldtop; | ||
953 | 905 | ||
954 | lua_pop( L, 1); | 906 | MUTEX_LOCK( &deep_lock); |
907 | ++ (prelude->refcount); // one more proxy pointing to this deep data | ||
908 | MUTEX_UNLOCK( &deep_lock); | ||
955 | 909 | ||
956 | // tbl= idfunc( "metatable" ) | 910 | STACK_GROW( L, 7); |
957 | // | 911 | STACK_CHECK( L); |
958 | oldtop = lua_gettop( L); | ||
959 | idfunc( L, "metatable"); | ||
960 | // | ||
961 | // [-2]: proxy | ||
962 | // [-1]: metatable (returned by 'idfunc') | ||
963 | 912 | ||
964 | if (lua_gettop( L) - oldtop != 1 || !lua_istable(L, -1)) | 913 | proxy = lua_newuserdata( L, sizeof( DEEP_PRELUDE*)); // DPC proxy |
965 | { | 914 | ASSERT_L( proxy); |
966 | luaL_error( L, "Bad idfunc on \"metatable\": did not return one" ); | 915 | *proxy = prelude; |
967 | } | ||
968 | 916 | ||
969 | // Add '__gc' method | 917 | // Get/create metatable for 'idfunc' (in this state) |
970 | // | 918 | lua_pushlightuserdata( L, prelude->idfunc); // DPC proxy idfunc |
971 | lua_pushcfunction( L, deep_userdata_gc ); | 919 | get_deep_lookup( L); // DPC proxy metatable? |
972 | lua_setfield( L, -2, "__gc" ); | ||
973 | 920 | ||
974 | // Memorize for later rounds | 921 | if( lua_isnil( L, -1)) // // No metatable yet. |
975 | // | 922 | { |
976 | lua_pushvalue( L,-1 ); | 923 | char const* modname; |
977 | lua_pushlightuserdata( L, idfunc ); | 924 | int oldtop = lua_gettop( L); // DPC proxy nil |
978 | // | 925 | lua_pop( L, 1); // DPC proxy |
979 | // [-4]: proxy | 926 | // 1 - make one and register it |
980 | // [-3]: metatable (2nd ref) | 927 | if( mode_ != eLM_ToKeeper) |
981 | // [-2]: metatable | 928 | { |
982 | // [-1]: idfunc | 929 | prelude->idfunc( L, eDO_metatable); // DPC proxy metatable |
983 | 930 | if( lua_gettop( L) - oldtop != 0 || !lua_istable( L, -1)) | |
984 | set_deep_lookup(L); | 931 | { |
985 | } | 932 | lua_pop( L, 3); // |
986 | 933 | return "Bad idfunc(eOP_metatable): unexpected pushed value"; | |
987 | // 2 - cause the target state to require the module that exported the idfunc | 934 | } |
988 | // this is needed because we must make sure the shared library is still loaded as long as we hold a pointer on the idfunc | 935 | // make sure the idfunc didn't export __gc, as we will store our own |
989 | STACK_CHECK( L); | 936 | lua_getfield( L, -1, "__gc"); // DPC proxy metatable __gc |
990 | { | 937 | if( !lua_isnil( L, -1)) |
991 | char const * modname; | 938 | { |
992 | // make sure the function pushed a single value on the stack! | 939 | lua_pop( L, 4); // |
993 | { | 940 | return "idfunc-created metatable shouldn't contain __gc"; |
994 | int oldtop = lua_gettop( L); | 941 | } |
995 | idfunc( L, "module"); // ... "module"/nil | 942 | lua_pop( L, 1); // DPC proxy metatable |
996 | if( lua_gettop( L) - oldtop != 1) | 943 | } |
997 | { | 944 | else |
998 | luaL_error( L, "Bad idfunc on \"module\": should return a single value"); | 945 | { |
999 | } | 946 | // keepers need a minimal metatable that only contains __gc |
1000 | } | 947 | lua_newtable( L); // DPC proxy metatable |
1001 | modname = luaL_optstring( L, -1, NULL); // raises an error if not a string or nil | 948 | } |
1002 | if( modname) // we actually got a module name | 949 | // Add our own '__gc' method |
1003 | { | 950 | lua_pushcfunction( L, deep_userdata_gc); // DPC proxy metatable __gc |
1004 | // somehow, L.registry._LOADED can exist without having registered the 'package' library. | 951 | lua_setfield( L, -2, "__gc"); // DPC proxy metatable |
1005 | lua_getglobal( L, "require"); // ... "module" require() | ||
1006 | // check that the module is already loaded (or being loaded, we are happy either way) | ||
1007 | if( lua_isfunction( L, -1)) | ||
1008 | { | ||
1009 | lua_insert( L, -2); // ... require() "module" | ||
1010 | lua_getfield( L, LUA_REGISTRYINDEX, "_LOADED"); // ... require() "module" L.registry._LOADED | ||
1011 | if( lua_istable( L, -1)) | ||
1012 | { | ||
1013 | bool_t alreadyloaded; | ||
1014 | lua_pushvalue( L, -2); // ... require() "module" L.registry._LOADED "module" | ||
1015 | lua_rawget( L, -2); // ... require() "module" L.registry._LOADED module | ||
1016 | alreadyloaded = lua_toboolean( L, -1); | ||
1017 | if( !alreadyloaded) // not loaded | ||
1018 | { | ||
1019 | lua_pop( L, 2); // ... require() "module" | ||
1020 | lua_call( L, 1, 0); // call require "modname" // ... | ||
1021 | } | ||
1022 | else // already loaded, we are happy | ||
1023 | { | ||
1024 | lua_pop( L, 4); // ... | ||
1025 | } | ||
1026 | } | ||
1027 | else // no L.registry._LOADED; can this ever happen? | ||
1028 | { | ||
1029 | luaL_error( L, "unexpected error while requiring a module"); | ||
1030 | lua_pop( L, 3); // ... | ||
1031 | } | ||
1032 | } | ||
1033 | else // a module name, but no require() function :-( | ||
1034 | { | ||
1035 | luaL_error( L, "lanes receiving deep userdata should register the 'package' library"); | ||
1036 | lua_pop( L, 2); // ... | ||
1037 | } | ||
1038 | } | ||
1039 | else // no module name | ||
1040 | { | ||
1041 | lua_pop( L, 1); // ... | ||
1042 | } | ||
1043 | } | ||
1044 | STACK_END( L, 0); | ||
1045 | } | ||
1046 | STACK_MID( L, 2); | ||
1047 | ASSERT_L( lua_isuserdata(L,-2) ); | ||
1048 | ASSERT_L( lua_istable(L,-1) ); | ||
1049 | 952 | ||
1050 | // [-2]: proxy userdata | 953 | // Memorize for later rounds |
1051 | // [-1]: metatable to use | 954 | lua_pushvalue( L, -1); // DPC proxy metatable metatable |
955 | lua_pushlightuserdata( L, prelude->idfunc); // DPC proxy metatable metatable idfunc | ||
956 | set_deep_lookup( L); // DPC proxy metatable | ||
1052 | 957 | ||
1053 | lua_setmetatable( L, -2 ); | 958 | // 2 - cause the target state to require the module that exported the idfunc |
1054 | 959 | // this is needed because we must make sure the shared library is still loaded as long as we hold a pointer on the idfunc | |
1055 | // If we're here, we obviously had to create a new proxy, so cache it. | 960 | { |
1056 | push_registry_subtable_mode(L, DEEP_PROXY_CACHE_KEY, "v"); | 961 | int oldtop = lua_gettop( L); |
1057 | lua_pushlightuserdata(L, (*proxy)->deep); | 962 | modname = (char const*) prelude->idfunc( L, eDO_module); // DPC proxy metatable |
1058 | lua_pushvalue(L, -3); // Copy of the proxy | 963 | // make sure the function pushed nothing on the stack! |
1059 | lua_rawset(L, -3); | 964 | if( lua_gettop( L) - oldtop != 0) |
1060 | lua_pop(L, 1); // Remove the cache proxy table | 965 | { |
1061 | 966 | lua_pop( L, 3); // | |
1062 | STACK_END( L, 1); | 967 | return "Bad idfunc(eOP_module): should not push anything"; |
1063 | // [-1]: proxy userdata | 968 | } |
969 | } | ||
970 | if( modname) // we actually got a module name | ||
971 | { | ||
972 | // somehow, L.registry._LOADED can exist without having registered the 'package' library. | ||
973 | lua_getglobal( L, "require"); // DPC proxy metatable require() | ||
974 | // check that the module is already loaded (or being loaded, we are happy either way) | ||
975 | if( lua_isfunction( L, -1)) | ||
976 | { | ||
977 | lua_pushstring( L, modname); // DPC proxy metatable require() "module" | ||
978 | lua_getfield( L, LUA_REGISTRYINDEX, "_LOADED"); // DPC proxy metatable require() "module" _R._LOADED | ||
979 | if( lua_istable( L, -1)) | ||
980 | { | ||
981 | bool_t alreadyloaded; | ||
982 | lua_pushvalue( L, -2); // DPC proxy metatable require() "module" _R._LOADED "module" | ||
983 | lua_rawget( L, -2); // DPC proxy metatable require() "module" _R._LOADED module | ||
984 | alreadyloaded = lua_toboolean( L, -1); | ||
985 | if( !alreadyloaded) // not loaded | ||
986 | { | ||
987 | int require_result; | ||
988 | lua_pop( L, 2); // DPC proxy metatable require() "module" | ||
989 | // require "modname" | ||
990 | require_result = lua_pcall( L, 1, 0, 0); // DPC proxy metatable error? | ||
991 | if( require_result != LUA_OK) | ||
992 | { | ||
993 | // failed, return the error message | ||
994 | lua_pushfstring( L, "error while requiring '%s' identified by idfunc(eOP_module): ", modname); | ||
995 | lua_insert( L, -2); // DPC proxy metatable prefix error | ||
996 | lua_concat( L, 2); // DPC proxy metatable error | ||
997 | return lua_tostring( L, -1); | ||
998 | } | ||
999 | } | ||
1000 | else // already loaded, we are happy | ||
1001 | { | ||
1002 | lua_pop( L, 4); // DPC proxy metatable | ||
1003 | } | ||
1004 | } | ||
1005 | else // no L.registry._LOADED; can this ever happen? | ||
1006 | { | ||
1007 | lua_pop( L, 6); // | ||
1008 | return "unexpected error while requiring a module identified by idfunc(eOP_module)"; | ||
1009 | } | ||
1010 | } | ||
1011 | else // a module name, but no require() function :-( | ||
1012 | { | ||
1013 | lua_pop( L, 4); // | ||
1014 | return "lanes receiving deep userdata should register the 'package' library"; | ||
1015 | } | ||
1016 | } | ||
1017 | } | ||
1018 | STACK_MID( L, 2); // DPC proxy metatable | ||
1019 | ASSERT_L( lua_isuserdata( L, -2)); | ||
1020 | ASSERT_L( lua_istable( L, -1)); | ||
1021 | lua_setmetatable( L, -2); // DPC proxy | ||
1022 | |||
1023 | // If we're here, we obviously had to create a new proxy, so cache it. | ||
1024 | lua_pushlightuserdata( L, (*proxy)->deep); // DPC proxy deep | ||
1025 | lua_pushvalue( L, -2); // DPC proxy deep proxy | ||
1026 | lua_rawset( L, -4); // DPC proxy | ||
1027 | lua_remove( L, -2); // proxy | ||
1028 | ASSERT_L( lua_isuserdata( L, -1)); | ||
1029 | STACK_END( L, 0); | ||
1030 | return NULL; | ||
1064 | } | 1031 | } |
1065 | 1032 | ||
1066 | 1033 | ||
@@ -1086,39 +1053,34 @@ void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *prelud | |||
1086 | * | 1053 | * |
1087 | * Returns: 'proxy' userdata for accessing the deep data via 'luaG_todeep()' | 1054 | * Returns: 'proxy' userdata for accessing the deep data via 'luaG_todeep()' |
1088 | */ | 1055 | */ |
1089 | int luaG_deep_userdata( lua_State *L, luaG_IdFunction idfunc) | 1056 | int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc) |
1090 | { | 1057 | { |
1091 | int oldtop; | 1058 | char const* errmsg; |
1092 | 1059 | DEEP_PRELUDE* prelude = DEEP_MALLOC( sizeof(DEEP_PRELUDE)); | |
1093 | DEEP_PRELUDE *prelude= DEEP_MALLOC( sizeof(DEEP_PRELUDE) ); | 1060 | ASSERT_L( prelude); |
1094 | ASSERT_L(prelude); | ||
1095 | |||
1096 | prelude->refcount= 0; // 'luaG_push_proxy' will lift it to 1 | ||
1097 | |||
1098 | STACK_GROW(L,1); | ||
1099 | STACK_CHECK( L); | ||
1100 | |||
1101 | // lightuserdata= idfunc( "new" [, ...] ) | ||
1102 | // | ||
1103 | oldtop = lua_gettop( L); | ||
1104 | idfunc(L, "new"); | ||
1105 | |||
1106 | if( lua_gettop( L) - oldtop != 1 || lua_type( L, -1) != LUA_TLIGHTUSERDATA) | ||
1107 | { | ||
1108 | luaL_error( L, "Bad idfunc on \"new\": did not return light userdata"); | ||
1109 | } | ||
1110 | 1061 | ||
1111 | prelude->deep= lua_touserdata(L,-1); | 1062 | prelude->refcount = 0; // 'push_deep_proxy' will lift it to 1 |
1112 | ASSERT_L(prelude->deep); | 1063 | prelude->idfunc = idfunc; |
1113 | 1064 | ||
1114 | lua_pop(L,1); // pop deep data | 1065 | STACK_GROW( L, 1); |
1115 | 1066 | STACK_CHECK( L); | |
1116 | luaG_push_proxy( L, idfunc, prelude ); | 1067 | { |
1117 | // | 1068 | int oldtop = lua_gettop( L); |
1118 | // [-1]: proxy userdata | 1069 | prelude->deep = idfunc( L, eDO_new); |
1070 | ASSERT_L( prelude->deep); | ||
1119 | 1071 | ||
1120 | STACK_END( L, 1); | 1072 | if( lua_gettop( L) - oldtop != 0) |
1121 | return 1; | 1073 | { |
1074 | luaL_error( L, "Bad idfunc(eDO_new): should not push anything on the stack"); | ||
1075 | } | ||
1076 | } | ||
1077 | errmsg = push_deep_proxy( L, prelude, eLM_LaneBody); // proxy | ||
1078 | if( errmsg != NULL) | ||
1079 | { | ||
1080 | luaL_error( L, errmsg); | ||
1081 | } | ||
1082 | STACK_END( L, 1); | ||
1083 | return 1; | ||
1122 | } | 1084 | } |
1123 | 1085 | ||
1124 | 1086 | ||
@@ -1128,52 +1090,51 @@ int luaG_deep_userdata( lua_State *L, luaG_IdFunction idfunc) | |||
1128 | * Reference count is not changed, and access to the deep userdata is not | 1090 | * Reference count is not changed, and access to the deep userdata is not |
1129 | * serialized. It is the module's responsibility to prevent conflicting usage. | 1091 | * serialized. It is the module's responsibility to prevent conflicting usage. |
1130 | */ | 1092 | */ |
1131 | void *luaG_todeep( lua_State *L, luaG_IdFunction idfunc, int index ) | 1093 | void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index) |
1132 | { | 1094 | { |
1133 | DEEP_PRELUDE **proxy; | 1095 | DEEP_PRELUDE** proxy; |
1134 | 1096 | ||
1135 | STACK_CHECK( L); | 1097 | STACK_CHECK( L); |
1136 | if( get_idfunc(L,index) != idfunc) | 1098 | // ensure it is actually a deep userdata |
1137 | return NULL; // no metatable, or wrong kind | 1099 | if( get_idfunc( L, index, eLM_LaneBody) != idfunc) |
1100 | { | ||
1101 | return NULL; // no metatable, or wrong kind | ||
1102 | } | ||
1138 | 1103 | ||
1139 | proxy= (DEEP_PRELUDE**)lua_touserdata( L, index ); | 1104 | proxy = (DEEP_PRELUDE**) lua_touserdata( L, index); |
1140 | STACK_END( L, 0); | 1105 | STACK_END( L, 0); |
1141 | 1106 | ||
1142 | return (*proxy)->deep; | 1107 | return (*proxy)->deep; |
1143 | } | 1108 | } |
1144 | 1109 | ||
1145 | 1110 | ||
1146 | /* | 1111 | /* |
1147 | * Copy deep userdata between two separate Lua states. | 1112 | * Copy deep userdata between two separate Lua states (from L to L2) |
1148 | * | 1113 | * |
1149 | * Returns: | 1114 | * Returns: |
1150 | * the id function of the copied value, or NULL for non-deep userdata | 1115 | * the id function of the copied value, or NULL for non-deep userdata |
1151 | * (not copied) | 1116 | * (not copied) |
1152 | */ | 1117 | */ |
1153 | static | 1118 | static luaG_IdFunction copydeep( lua_State* L, lua_State* L2, int index, enum eLookupMode mode_) |
1154 | luaG_IdFunction luaG_copydeep( lua_State *L, lua_State *L2, int index ) | ||
1155 | { | 1119 | { |
1156 | DEEP_PRELUDE **proxy; | 1120 | char const* errmsg; |
1157 | DEEP_PRELUDE *p; | 1121 | luaG_IdFunction idfunc = get_idfunc( L, index, mode_); |
1158 | 1122 | if( idfunc == NULL) | |
1159 | luaG_IdFunction idfunc = get_idfunc( L, index); | 1123 | { |
1160 | if (!idfunc) | 1124 | return NULL; // not a deep userdata |
1161 | return NULL; // not a deep userdata | 1125 | } |
1162 | |||
1163 | // Increment reference count | ||
1164 | // | ||
1165 | proxy= (DEEP_PRELUDE**)lua_touserdata( L, index ); | ||
1166 | p= *proxy; | ||
1167 | |||
1168 | luaG_push_proxy( L2, idfunc, p ); | ||
1169 | // | ||
1170 | // L2 [-1]: proxy userdata | ||
1171 | 1126 | ||
1172 | return idfunc; | 1127 | errmsg = push_deep_proxy( L2, *(DEEP_PRELUDE**) lua_touserdata( L, index), mode_); |
1128 | if( errmsg != NULL) | ||
1129 | { | ||
1130 | // raise the error in the proper state (not the keeper) | ||
1131 | lua_State* errL = (mode_ == eLM_FromKeeper) ? L2 : L; | ||
1132 | luaL_error( errL, errmsg); | ||
1133 | } | ||
1134 | return idfunc; | ||
1173 | } | 1135 | } |
1174 | 1136 | ||
1175 | 1137 | ||
1176 | |||
1177 | /*---=== Inter-state copying ===---*/ | 1138 | /*---=== Inter-state copying ===---*/ |
1178 | 1139 | ||
1179 | /*-- Metatable copying --*/ | 1140 | /*-- Metatable copying --*/ |
@@ -1190,51 +1151,45 @@ luaG_IdFunction luaG_copydeep( lua_State *L, lua_State *L2, int index ) | |||
1190 | /* | 1151 | /* |
1191 | * Does what the original 'push_registry_subtable' function did, but adds an optional mode argument to it | 1152 | * Does what the original 'push_registry_subtable' function did, but adds an optional mode argument to it |
1192 | */ | 1153 | */ |
1193 | static | 1154 | static void push_registry_subtable_mode( lua_State* L, void* key_, const char* mode_) |
1194 | void push_registry_subtable_mode( lua_State *L, void *token, const char* mode ) { | 1155 | { |
1156 | STACK_GROW( L, 3); | ||
1157 | STACK_CHECK( L); | ||
1195 | 1158 | ||
1196 | STACK_GROW(L,3); | 1159 | lua_pushlightuserdata( L, key_); // key |
1160 | lua_rawget( L, LUA_REGISTRYINDEX); // {}|nil | ||
1197 | 1161 | ||
1198 | STACK_CHECK( L); | 1162 | if( lua_isnil( L, -1)) |
1199 | 1163 | { | |
1200 | lua_pushlightuserdata( L, token ); | 1164 | lua_pop( L, 1); // |
1201 | lua_rawget( L, LUA_REGISTRYINDEX ); | 1165 | lua_newtable( L); // {} |
1202 | // | 1166 | lua_pushlightuserdata( L, key_); // {} key |
1203 | // [-1]: nil/subtable | 1167 | lua_pushvalue( L, -2); // {} key {} |
1204 | 1168 | ||
1205 | if (lua_isnil(L,-1)) { | 1169 | // _R[key_] = {} |
1206 | lua_pop(L,1); | 1170 | lua_rawset( L, LUA_REGISTRYINDEX); // {} |
1207 | lua_newtable(L); // value | ||
1208 | lua_pushlightuserdata( L, token ); // key | ||
1209 | lua_pushvalue(L,-2); | ||
1210 | // | ||
1211 | // [-3]: value (2nd ref) | ||
1212 | // [-2]: key | ||
1213 | // [-1]: value | ||
1214 | |||
1215 | lua_rawset( L, LUA_REGISTRYINDEX ); | ||
1216 | |||
1217 | // Set it's metatable if requested | ||
1218 | if (mode) { | ||
1219 | lua_newtable(L); | ||
1220 | lua_pushliteral(L, "__mode"); | ||
1221 | lua_pushstring(L, mode); | ||
1222 | lua_rawset(L, -3); | ||
1223 | lua_setmetatable(L, -2); | ||
1224 | } | ||
1225 | } | ||
1226 | STACK_END( L, 1); | ||
1227 | 1171 | ||
1228 | ASSERT_L( lua_istable(L,-1) ); | 1172 | // Set its metatable if requested |
1173 | if( mode_) | ||
1174 | { | ||
1175 | lua_newtable( L); // {} mt | ||
1176 | lua_pushliteral( L, "__mode"); // {} mt "__mode" | ||
1177 | lua_pushstring( L, mode_); // {} mt "__mode" mode | ||
1178 | lua_rawset( L, -3); // {} mt | ||
1179 | lua_setmetatable( L, -2); // {} | ||
1180 | } | ||
1181 | } | ||
1182 | STACK_END( L, 1); | ||
1183 | ASSERT_L( lua_istable( L, -1)); | ||
1229 | } | 1184 | } |
1230 | 1185 | ||
1231 | /* | 1186 | /* |
1232 | * Push a registry subtable (keyed by unique 'token') onto the stack. | 1187 | * Push a registry subtable (keyed by unique 'key_') onto the stack. |
1233 | * If the subtable does not exist, it is created and chained. | 1188 | * If the subtable does not exist, it is created and chained. |
1234 | */ | 1189 | */ |
1235 | static | 1190 | static inline void push_registry_subtable( lua_State* L, void* key_) |
1236 | void push_registry_subtable( lua_State *L, void *token ) { | 1191 | { |
1237 | push_registry_subtable_mode(L, token, NULL); | 1192 | push_registry_subtable_mode( L, key_, NULL); |
1238 | } | 1193 | } |
1239 | 1194 | ||
1240 | #define REG_MTID ( (void*) get_mt_id ) | 1195 | #define REG_MTID ( (void*) get_mt_id ) |
@@ -1864,12 +1819,10 @@ static void push_cached_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, ui | |||
1864 | static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum e_vt vt, enum eLookupMode mode_, char const* upName_) | 1819 | static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum e_vt vt, enum eLookupMode mode_, char const* upName_) |
1865 | { | 1820 | { |
1866 | bool_t ret = TRUE; | 1821 | bool_t ret = TRUE; |
1867 | |||
1868 | STACK_GROW( L2, 1); | 1822 | STACK_GROW( L2, 1); |
1869 | |||
1870 | STACK_CHECK( L2); | 1823 | STACK_CHECK( L2); |
1871 | 1824 | ||
1872 | switch ( lua_type( L, i)) | 1825 | switch( lua_type( L, i)) |
1873 | { | 1826 | { |
1874 | /* Basic types allowed both as values, and as table keys */ | 1827 | /* Basic types allowed both as values, and as table keys */ |
1875 | 1828 | ||
@@ -1921,7 +1874,7 @@ static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, u | |||
1921 | /* Allow only deep userdata entities to be copied across | 1874 | /* Allow only deep userdata entities to be copied across |
1922 | */ | 1875 | */ |
1923 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "USERDATA\n" INDENT_END)); | 1876 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "USERDATA\n" INDENT_END)); |
1924 | if( !luaG_copydeep( L, L2, i)) | 1877 | if( !copydeep( L, L2, i, mode_)) |
1925 | { | 1878 | { |
1926 | // Not a deep full userdata | 1879 | // Not a deep full userdata |
1927 | bool_t demote = FALSE; | 1880 | bool_t demote = FALSE; |
@@ -2129,7 +2082,6 @@ static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, u | |||
2129 | } | 2082 | } |
2130 | 2083 | ||
2131 | STACK_END( L2, ret ? 1 : 0); | 2084 | STACK_END( L2, ret ? 1 : 0); |
2132 | |||
2133 | return ret; | 2085 | return ret; |
2134 | } | 2086 | } |
2135 | 2087 | ||
@@ -2225,7 +2177,8 @@ void luaG_inter_copy_package( lua_State* L, lua_State* L2, int _idx, enum eLooku | |||
2225 | // package.loaders is renamed package.searchers in Lua 5.2 | 2177 | // package.loaders is renamed package.searchers in Lua 5.2 |
2226 | // but don't copy it anyway, as the function names change depending on the slot index! | 2178 | // but don't copy it anyway, as the function names change depending on the slot index! |
2227 | // users should provide an on_state_create function to setup custom loaders instead | 2179 | // users should provide an on_state_create function to setup custom loaders instead |
2228 | char const* entries[] = { "path", "cpath", "preload"/*, (LUA_VERSION_NUM == 501) ? "loaders" : "searchers"*/, NULL}; | 2180 | // don't copy package.preload in keeper states (they don't know how to translate functions) |
2181 | char const* entries[] = { "path", "cpath", (mode_ == eLM_LaneBody) ? "preload" : NULL/*, (LUA_VERSION_NUM == 501) ? "loaders" : "searchers"*/, NULL}; | ||
2229 | for( i = 0; entries[i]; ++ i) | 2182 | for( i = 0; entries[i]; ++ i) |
2230 | { | 2183 | { |
2231 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s\n" INDENT_END, entries[i])); | 2184 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s\n" INDENT_END, entries[i])); |
diff --git a/src/tools.h b/src/tools.h index be358db..ebe407b 100644 --- a/src/tools.h +++ b/src/tools.h | |||
@@ -99,11 +99,15 @@ extern int debugspew_indent_depth; | |||
99 | void luaG_dump( lua_State* L ); | 99 | void luaG_dump( lua_State* L ); |
100 | 100 | ||
101 | lua_State* luaG_newstate( lua_State* _from, char const* libs); | 101 | lua_State* luaG_newstate( lua_State* _from, char const* libs); |
102 | void luaG_copy_one_time_settings( lua_State* L, lua_State* L2, char const* name_); | 102 | void luaG_copy_one_time_settings( lua_State* L, lua_State* L2); |
103 | 103 | ||
104 | typedef struct { | 104 | // this is pointed to by full userdata proxies, and allocated with malloc() to survive any lua_State lifetime |
105 | volatile int refcount; | 105 | typedef struct |
106 | void *deep; | 106 | { |
107 | volatile int refcount; | ||
108 | void* deep; | ||
109 | // when stored in a keeper state, the full userdata doesn't have a metatable, so we need direct access to the idfunc | ||
110 | luaG_IdFunction idfunc; | ||
107 | } DEEP_PRELUDE; | 111 | } DEEP_PRELUDE; |
108 | 112 | ||
109 | enum eLookupMode | 113 | enum eLookupMode |
@@ -113,7 +117,7 @@ enum eLookupMode | |||
113 | eLM_FromKeeper // send a function from a keeper state to a lane | 117 | eLM_FromKeeper // send a function from a keeper state to a lane |
114 | }; | 118 | }; |
115 | 119 | ||
116 | void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *deep_userdata); | 120 | char const* push_deep_proxy( lua_State* L, DEEP_PRELUDE* prelude, enum eLookupMode mode_); |
117 | void luaG_inter_copy_package( lua_State* L, lua_State* L2, int _idx, enum eLookupMode mode_); | 121 | void luaG_inter_copy_package( lua_State* L, lua_State* L2, int _idx, enum eLookupMode mode_); |
118 | 122 | ||
119 | int luaG_inter_copy( lua_State *L, lua_State *L2, uint_t n, enum eLookupMode mode_); | 123 | int luaG_inter_copy( lua_State *L, lua_State *L2, uint_t n, enum eLookupMode mode_); |
@@ -130,6 +134,8 @@ extern MUTEX_T mtid_lock; | |||
130 | void populate_func_lookup_table( lua_State* L, int _i, char const* _name); | 134 | void populate_func_lookup_table( lua_State* L, int _i, char const* _name); |
131 | void serialize_require( lua_State *L); | 135 | void serialize_require( lua_State *L); |
132 | int initialize_on_state_create( lua_State *L); | 136 | int initialize_on_state_create( lua_State *L); |
137 | void call_on_state_create( lua_State* L, lua_State* from_, enum eLookupMode mode_); | ||
138 | |||
133 | extern MUTEX_T require_cs; | 139 | extern MUTEX_T require_cs; |
134 | 140 | ||
135 | // for verbose errors | 141 | // for verbose errors |