diff options
| author | Benoit Germain <b n t DOT g e r m a i n AT g m a i l DOT c o m> | 2018-10-29 13:39:49 +0100 |
|---|---|---|
| committer | Benoit Germain <b n t DOT g e r m a i n AT g m a i l DOT c o m> | 2018-10-29 13:39:49 +0100 |
| commit | ea9e8a3af1c2357c454ef18c8136c14a22b8675a (patch) | |
| tree | 0b089ae8b94d7901db8c86051fb001bf5936bc54 | |
| parent | e2908369e92b14e661b16401b6389d6d4a026278 (diff) | |
| parent | debc6b3403077fc5bd1d144d779806fdd22ab55e (diff) | |
| download | lanes-ea9e8a3af1c2357c454ef18c8136c14a22b8675a.tar.gz lanes-ea9e8a3af1c2357c454ef18c8136c14a22b8675a.tar.bz2 lanes-ea9e8a3af1c2357c454ef18c8136c14a22b8675a.zip | |
Merge changes
| -rw-r--r-- | CHANGES | 10 | ||||
| -rw-r--r-- | CMakeLists.txt | 3 | ||||
| -rw-r--r-- | src/deep.c | 38 | ||||
| -rw-r--r-- | src/deep.h | 25 | ||||
| -rw-r--r-- | src/keeper.c | 30 | ||||
| -rw-r--r-- | src/keeper.h | 27 | ||||
| -rw-r--r-- | src/lanes.c | 134 | ||||
| -rw-r--r-- | src/lanes.h | 1 | ||||
| -rw-r--r-- | src/macros_and_utils.h | 1 | ||||
| -rw-r--r-- | src/platform.h | 24 | ||||
| -rw-r--r-- | src/threading.h | 22 | ||||
| -rw-r--r-- | src/tools.c | 153 | ||||
| -rw-r--r-- | src/tools.h | 47 | ||||
| -rw-r--r-- | src/universe.c | 14 | ||||
| -rw-r--r-- | src/universe.h | 24 |
15 files changed, 311 insertions, 242 deletions
| @@ -1,5 +1,15 @@ | |||
| 1 | CHANGES: | 1 | CHANGES: |
| 2 | 2 | ||
| 3 | CHANGE 126: Bge 29-Oct-18 | ||
| 4 | * Add deep user data cloning support | ||
| 5 | |||
| 6 | CHANGE 125: BGe 25-Oct-18 | ||
| 7 | * Fix Lanes build by reorganizing types around a bit | ||
| 8 | |||
| 9 | CHANGE 124: BGe 9-Jul-18 | ||
| 10 | * Fix a stack overflow when copying large tables with verbose_errors option enabled | ||
| 11 | * Support for integer formatting in verbose errors | ||
| 12 | |||
| 3 | CHANGE 123: BGe 2-Aug-17 | 13 | CHANGE 123: BGe 2-Aug-17 |
| 4 | * added support for user-provided __gc in deep userdata | 14 | * added support for user-provided __gc in deep userdata |
| 5 | * more complete deep userdata sample | 15 | * more complete deep userdata sample |
diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ce1bd3..647047c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -13,6 +13,9 @@ FIND_PROGRAM(LUA NAMES lua5.1 lua51 lua) | |||
| 13 | FIND_PROGRAM(LUAC NAMES luac5.1 luac51 luac) | 13 | FIND_PROGRAM(LUAC NAMES luac5.1 luac51 luac) |
| 14 | INCLUDE_DIRECTORIES(${LUA_INCLUDE_DIR}) | 14 | INCLUDE_DIRECTORIES(${LUA_INCLUDE_DIR}) |
| 15 | 15 | ||
| 16 | if(USE_PTHREAD) | ||
| 17 | ADD_DEFINITIONS(-DHAVE_WIN32_PTHREAD) | ||
| 18 | endif(USE_PTHREAD) | ||
| 16 | #2DO - patch threading.c to suppot cygwin. | 19 | #2DO - patch threading.c to suppot cygwin. |
| 17 | # The following values are just a guess. | 20 | # The following values are just a guess. |
| 18 | # WARNING: test segfault under Cygwin | 21 | # WARNING: test segfault under Cygwin |
| @@ -32,11 +32,6 @@ THE SOFTWARE. | |||
| 32 | =============================================================================== | 32 | =============================================================================== |
| 33 | */ | 33 | */ |
| 34 | 34 | ||
| 35 | #include "compat.h" | ||
| 36 | #include "tools.h" | ||
| 37 | #include "universe.h" | ||
| 38 | #include "deep.h" | ||
| 39 | |||
| 40 | #include <stdio.h> | 35 | #include <stdio.h> |
| 41 | #include <string.h> | 36 | #include <string.h> |
| 42 | #include <ctype.h> | 37 | #include <ctype.h> |
| @@ -45,6 +40,11 @@ THE SOFTWARE. | |||
| 45 | #include <malloc.h> | 40 | #include <malloc.h> |
| 46 | #endif | 41 | #endif |
| 47 | 42 | ||
| 43 | #include "compat.h" | ||
| 44 | #include "deep.h" | ||
| 45 | #include "tools.h" | ||
| 46 | #include "universe.h" | ||
| 47 | |||
| 48 | /*-- Metatable copying --*/ | 48 | /*-- Metatable copying --*/ |
| 49 | 49 | ||
| 50 | /* | 50 | /* |
| @@ -174,12 +174,12 @@ static void get_deep_lookup( lua_State* L) | |||
| 174 | * Return the registered ID function for 'index' (deep userdata proxy), | 174 | * Return the registered ID function for 'index' (deep userdata proxy), |
| 175 | * or NULL if 'index' is not a deep userdata proxy. | 175 | * or NULL if 'index' is not a deep userdata proxy. |
| 176 | */ | 176 | */ |
| 177 | static inline luaG_IdFunction get_idfunc( lua_State* L, int index, enum eLookupMode mode_) | 177 | static inline luaG_IdFunction get_idfunc( lua_State* L, int index, LookupMode mode_) |
| 178 | { | 178 | { |
| 179 | // when looking inside a keeper, we are 100% sure the object is a deep userdata | 179 | // when looking inside a keeper, we are 100% sure the object is a deep userdata |
| 180 | if( mode_ == eLM_FromKeeper) | 180 | if( mode_ == eLM_FromKeeper) |
| 181 | { | 181 | { |
| 182 | struct DEEP_PRELUDE** proxy = (struct DEEP_PRELUDE**) lua_touserdata( L, index); | 182 | DeepPrelude** proxy = (DeepPrelude**) lua_touserdata( L, index); |
| 183 | // we can (and must) cast and fetch the internally stored idfunc | 183 | // we can (and must) cast and fetch the internally stored idfunc |
| 184 | return (*proxy)->idfunc; | 184 | return (*proxy)->idfunc; |
| 185 | } | 185 | } |
| @@ -208,7 +208,7 @@ static inline luaG_IdFunction get_idfunc( lua_State* L, int index, enum eLookupM | |||
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | 210 | ||
| 211 | void free_deep_prelude( lua_State* L, struct DEEP_PRELUDE* prelude_) | 211 | void free_deep_prelude( lua_State* L, DeepPrelude* prelude_) |
| 212 | { | 212 | { |
| 213 | // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup | 213 | // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup |
| 214 | lua_pushlightuserdata( L, prelude_->deep); | 214 | lua_pushlightuserdata( L, prelude_->deep); |
| @@ -226,9 +226,9 @@ void free_deep_prelude( lua_State* L, struct DEEP_PRELUDE* prelude_) | |||
| 226 | */ | 226 | */ |
| 227 | static int deep_userdata_gc( lua_State* L) | 227 | static int deep_userdata_gc( lua_State* L) |
| 228 | { | 228 | { |
| 229 | struct DEEP_PRELUDE** proxy = (struct DEEP_PRELUDE**) lua_touserdata( L, 1); | 229 | DeepPrelude** proxy = (DeepPrelude**) lua_touserdata( L, 1); |
| 230 | struct DEEP_PRELUDE* p = *proxy; | 230 | DeepPrelude* p = *proxy; |
| 231 | struct s_Universe* U = universe_get( L); | 231 | Universe* U = universe_get( L); |
| 232 | int v; | 232 | int v; |
| 233 | 233 | ||
| 234 | // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded | 234 | // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded |
| @@ -270,9 +270,9 @@ static int deep_userdata_gc( lua_State* L) | |||
| 270 | * used in this Lua state (metatable, registring it). Otherwise, increments the | 270 | * used in this Lua state (metatable, registring it). Otherwise, increments the |
| 271 | * reference count. | 271 | * reference count. |
| 272 | */ | 272 | */ |
| 273 | char const* push_deep_proxy( struct s_Universe* U, lua_State* L, struct DEEP_PRELUDE* prelude, enum eLookupMode mode_) | 273 | char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, LookupMode mode_) |
| 274 | { | 274 | { |
| 275 | struct DEEP_PRELUDE** proxy; | 275 | DeepPrelude** proxy; |
| 276 | 276 | ||
| 277 | // Check if a proxy already exists | 277 | // Check if a proxy already exists |
| 278 | push_registry_subtable_mode( L, DEEP_PROXY_CACHE_KEY, "v"); // DPC | 278 | push_registry_subtable_mode( L, DEEP_PROXY_CACHE_KEY, "v"); // DPC |
| @@ -297,7 +297,7 @@ char const* push_deep_proxy( struct s_Universe* U, lua_State* L, struct DEEP_PRE | |||
| 297 | STACK_GROW( L, 7); | 297 | STACK_GROW( L, 7); |
| 298 | STACK_CHECK( L); | 298 | STACK_CHECK( L); |
| 299 | 299 | ||
| 300 | proxy = lua_newuserdata( L, sizeof(struct DEEP_PRELUDE*)); // DPC proxy | 300 | proxy = lua_newuserdata( L, sizeof(DeepPrelude*)); // DPC proxy |
| 301 | ASSERT_L( proxy); | 301 | ASSERT_L( proxy); |
| 302 | *proxy = prelude; | 302 | *proxy = prelude; |
| 303 | 303 | ||
| @@ -454,7 +454,7 @@ char const* push_deep_proxy( struct s_Universe* U, lua_State* L, struct DEEP_PRE | |||
| 454 | int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc) | 454 | int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc) |
| 455 | { | 455 | { |
| 456 | char const* errmsg; | 456 | char const* errmsg; |
| 457 | struct DEEP_PRELUDE* prelude = DEEP_MALLOC( sizeof(struct DEEP_PRELUDE)); | 457 | DeepPrelude* prelude = DEEP_MALLOC( sizeof( DeepPrelude)); |
| 458 | if( prelude == NULL) | 458 | if( prelude == NULL) |
| 459 | { | 459 | { |
| 460 | return luaL_error( L, "couldn't not allocate deep prelude: out of memory"); | 460 | return luaL_error( L, "couldn't not allocate deep prelude: out of memory"); |
| @@ -496,7 +496,7 @@ int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc) | |||
| 496 | */ | 496 | */ |
| 497 | void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index) | 497 | void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index) |
| 498 | { | 498 | { |
| 499 | struct DEEP_PRELUDE** proxy; | 499 | DeepPrelude** proxy; |
| 500 | 500 | ||
| 501 | STACK_CHECK( L); | 501 | STACK_CHECK( L); |
| 502 | // ensure it is actually a deep userdata | 502 | // ensure it is actually a deep userdata |
| @@ -505,7 +505,7 @@ void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index) | |||
| 505 | return NULL; // no metatable, or wrong kind | 505 | return NULL; // no metatable, or wrong kind |
| 506 | } | 506 | } |
| 507 | 507 | ||
| 508 | proxy = (struct DEEP_PRELUDE**) lua_touserdata( L, index); | 508 | proxy = (DeepPrelude**) lua_touserdata( L, index); |
| 509 | STACK_END( L, 0); | 509 | STACK_END( L, 0); |
| 510 | 510 | ||
| 511 | return (*proxy)->deep; | 511 | return (*proxy)->deep; |
| @@ -519,7 +519,7 @@ void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index) | |||
| 519 | * the id function of the copied value, or NULL for non-deep userdata | 519 | * the id function of the copied value, or NULL for non-deep userdata |
| 520 | * (not copied) | 520 | * (not copied) |
| 521 | */ | 521 | */ |
| 522 | luaG_IdFunction copydeep( struct s_Universe* U, lua_State* L, lua_State* L2, int index, enum eLookupMode mode_) | 522 | luaG_IdFunction copydeep( Universe* U, lua_State* L, lua_State* L2, int index, LookupMode mode_) |
| 523 | { | 523 | { |
| 524 | char const* errmsg; | 524 | char const* errmsg; |
| 525 | luaG_IdFunction idfunc = get_idfunc( L, index, mode_); | 525 | luaG_IdFunction idfunc = get_idfunc( L, index, mode_); |
| @@ -528,7 +528,7 @@ luaG_IdFunction copydeep( struct s_Universe* U, lua_State* L, lua_State* L2, int | |||
| 528 | return NULL; // not a deep userdata | 528 | return NULL; // not a deep userdata |
| 529 | } | 529 | } |
| 530 | 530 | ||
| 531 | errmsg = push_deep_proxy( U, L2, *(struct DEEP_PRELUDE**) lua_touserdata( L, index), mode_); | 531 | errmsg = push_deep_proxy( U, L2, *(DeepPrelude**) lua_touserdata( L, index), mode_); |
| 532 | if( errmsg != NULL) | 532 | if( errmsg != NULL) |
| 533 | { | 533 | { |
| 534 | // raise the error in the proper state (not the keeper) | 534 | // raise the error in the proper state (not the keeper) |
| @@ -6,14 +6,22 @@ | |||
| 6 | * said modules will have to link against lanes (it is not really possible to separate the 'deep userdata' implementation from the rest of Lanes) | 6 | * said modules will have to link against lanes (it is not really possible to separate the 'deep userdata' implementation from the rest of Lanes) |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | |||
| 10 | #include "lua.h" | 9 | #include "lua.h" |
| 10 | #include "platform.h" | ||
| 11 | |||
| 12 | // forwards | ||
| 13 | struct s_Universe; | ||
| 14 | typedef struct s_Universe Universe; | ||
| 15 | enum eLookupMode; | ||
| 16 | typedef enum eLookupMode LookupMode; | ||
| 11 | 17 | ||
| 18 | #if !defined LANES_API // when deep is compiled standalone outside Lanes | ||
| 12 | #if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) | 19 | #if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) |
| 13 | #define LANES_API __declspec(dllexport) | 20 | #define LANES_API __declspec(dllexport) |
| 14 | #else | 21 | #else |
| 15 | #define LANES_API | 22 | #define LANES_API |
| 16 | #endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) | 23 | #endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) |
| 24 | #endif // LANES_API | ||
| 17 | 25 | ||
| 18 | enum eDeepOp | 26 | enum eDeepOp |
| 19 | { | 27 | { |
| @@ -25,6 +33,21 @@ enum eDeepOp | |||
| 25 | 33 | ||
| 26 | typedef void* (*luaG_IdFunction)( lua_State* L, enum eDeepOp op_); | 34 | typedef void* (*luaG_IdFunction)( lua_State* L, enum eDeepOp op_); |
| 27 | 35 | ||
| 36 | // ################################################################################################ | ||
| 37 | |||
| 38 | // this is pointed to by full userdata proxies, and allocated with malloc() to survive any lua_State lifetime | ||
| 39 | struct s_DeepPrelude | ||
| 40 | { | ||
| 41 | volatile int refcount; | ||
| 42 | void* deep; | ||
| 43 | // when stored in a keeper state, the full userdata doesn't have a metatable, so we need direct access to the idfunc | ||
| 44 | luaG_IdFunction idfunc; | ||
| 45 | }; | ||
| 46 | typedef struct s_DeepPrelude DeepPrelude; | ||
| 47 | |||
| 48 | char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, LookupMode mode_); | ||
| 49 | void free_deep_prelude( lua_State* L, DeepPrelude* prelude_); | ||
| 50 | |||
| 28 | extern LANES_API int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc); | 51 | extern LANES_API int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc); |
| 29 | extern LANES_API void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index); | 52 | extern LANES_API void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index); |
| 30 | extern LANES_API void luaG_pushdeepversion( lua_State* L); | 53 | extern LANES_API void luaG_pushdeepversion( lua_State* L); |
diff --git a/src/keeper.c b/src/keeper.c index dbf083f..907334f 100644 --- a/src/keeper.c +++ b/src/keeper.c | |||
| @@ -42,12 +42,12 @@ | |||
| 42 | #include <stdio.h> | 42 | #include <stdio.h> |
| 43 | #include <stdlib.h> | 43 | #include <stdlib.h> |
| 44 | #include <ctype.h> | 44 | #include <ctype.h> |
| 45 | #include <assert.h> | ||
| 45 | 46 | ||
| 46 | #include "threading.h" | 47 | #include "keeper.h" |
| 47 | #include "compat.h" | 48 | #include "compat.h" |
| 48 | #include "tools.h" | 49 | #include "tools.h" |
| 49 | #include "universe.h" | 50 | #include "universe.h" |
| 50 | #include "keeper.h" | ||
| 51 | 51 | ||
| 52 | //################################################################################### | 52 | //################################################################################### |
| 53 | // Keeper implementation | 53 | // Keeper implementation |
| @@ -184,9 +184,9 @@ static void push_table( lua_State* L, int idx_) | |||
| 184 | STACK_END( L, 1); | 184 | STACK_END( L, 1); |
| 185 | } | 185 | } |
| 186 | 186 | ||
| 187 | int keeper_push_linda_storage( struct s_Universe* U, lua_State* L, void* ptr_, ptrdiff_t magic_) | 187 | int keeper_push_linda_storage( Universe* U, lua_State* L, void* ptr_, ptrdiff_t magic_) |
| 188 | { | 188 | { |
| 189 | struct s_Keeper* const K = keeper_acquire( U->keepers, magic_); | 189 | Keeper* const K = keeper_acquire( U->keepers, magic_); |
| 190 | lua_State* const KL = K ? K->L : NULL; | 190 | lua_State* const KL = K ? K->L : NULL; |
| 191 | if( KL == NULL) return 0; | 191 | if( KL == NULL) return 0; |
| 192 | STACK_GROW( KL, 4); | 192 | STACK_GROW( KL, 4); |
| @@ -576,7 +576,7 @@ int keepercall_count( lua_State* L) | |||
| 576 | */ | 576 | */ |
| 577 | 577 | ||
| 578 | // called as __gc for the keepers array userdata | 578 | // called as __gc for the keepers array userdata |
| 579 | void close_keepers( struct s_Universe* U, lua_State* L) | 579 | void close_keepers( Universe* U, lua_State* L) |
| 580 | { | 580 | { |
| 581 | if( U->keepers != NULL) | 581 | if( U->keepers != NULL) |
| 582 | { | 582 | { |
| @@ -609,7 +609,7 @@ void close_keepers( struct s_Universe* U, lua_State* L) | |||
| 609 | { | 609 | { |
| 610 | void* allocUD; | 610 | void* allocUD; |
| 611 | lua_Alloc allocF = lua_getallocf( L, &allocUD); | 611 | lua_Alloc allocF = lua_getallocf( L, &allocUD); |
| 612 | allocF( allocUD, U->keepers, sizeof( struct s_Keepers) + (nbKeepers - 1) * sizeof(struct s_Keeper), 0); | 612 | allocF( allocUD, U->keepers, sizeof( Keepers) + (nbKeepers - 1) * sizeof( Keeper), 0); |
| 613 | U->keepers = NULL; | 613 | U->keepers = NULL; |
| 614 | } | 614 | } |
| 615 | } | 615 | } |
| @@ -626,7 +626,7 @@ void close_keepers( struct s_Universe* U, lua_State* L) | |||
| 626 | * function never fails. | 626 | * function never fails. |
| 627 | * settings table is at position 1 on the stack | 627 | * settings table is at position 1 on the stack |
| 628 | */ | 628 | */ |
| 629 | void init_keepers( struct s_Universe* U, lua_State* L) | 629 | void init_keepers( Universe* U, lua_State* L) |
| 630 | { | 630 | { |
| 631 | int i; | 631 | int i; |
| 632 | int nb_keepers; | 632 | int nb_keepers; |
| @@ -639,10 +639,10 @@ void init_keepers( struct s_Universe* U, lua_State* L) | |||
| 639 | lua_pop( L, 1); // | 639 | lua_pop( L, 1); // |
| 640 | assert( nb_keepers >= 1); | 640 | assert( nb_keepers >= 1); |
| 641 | 641 | ||
| 642 | // struct s_Keepers contains an array of 1 s_Keeper, adjust for the actual number of keeper states | 642 | // Keepers contains an array of 1 s_Keeper, adjust for the actual number of keeper states |
| 643 | { | 643 | { |
| 644 | size_t const bytes = sizeof( struct s_Keepers) + (nb_keepers - 1) * sizeof(struct s_Keeper); | 644 | size_t const bytes = sizeof( Keepers) + (nb_keepers - 1) * sizeof( Keeper); |
| 645 | U->keepers = (struct s_Keepers*) allocF( allocUD, NULL, 0, bytes); | 645 | U->keepers = (Keepers*) allocF( allocUD, NULL, 0, bytes); |
| 646 | if( U->keepers == NULL) | 646 | if( U->keepers == NULL) |
| 647 | { | 647 | { |
| 648 | (void) luaL_error( L, "init_keepers() failed while creating keeper array; out of memory"); | 648 | (void) luaL_error( L, "init_keepers() failed while creating keeper array; out of memory"); |
| @@ -713,7 +713,7 @@ void init_keepers( struct s_Universe* U, lua_State* L) | |||
| 713 | STACK_END( L, 0); | 713 | STACK_END( L, 0); |
| 714 | } | 714 | } |
| 715 | 715 | ||
| 716 | struct s_Keeper* keeper_acquire( struct s_Keepers* keepers_, ptrdiff_t magic_) | 716 | Keeper* keeper_acquire( Keepers* keepers_, ptrdiff_t magic_) |
| 717 | { | 717 | { |
| 718 | int const nbKeepers = keepers_->nb_keepers; | 718 | int const nbKeepers = keepers_->nb_keepers; |
| 719 | // can be 0 if this happens during main state shutdown (lanes is being GC'ed -> no keepers) | 719 | // can be 0 if this happens during main state shutdown (lanes is being GC'ed -> no keepers) |
| @@ -731,7 +731,7 @@ struct s_Keeper* keeper_acquire( struct s_Keepers* keepers_, ptrdiff_t magic_) | |||
| 731 | * have to cast to unsigned long to avoid compilation warnings about loss of data when converting pointer-to-integer | 731 | * have to cast to unsigned long to avoid compilation warnings about loss of data when converting pointer-to-integer |
| 732 | */ | 732 | */ |
| 733 | unsigned int i = (unsigned int)((magic_ >> KEEPER_MAGIC_SHIFT) % nbKeepers); | 733 | unsigned int i = (unsigned int)((magic_ >> KEEPER_MAGIC_SHIFT) % nbKeepers); |
| 734 | struct s_Keeper* K = &keepers_->keeper_array[i]; | 734 | Keeper* K = &keepers_->keeper_array[i]; |
| 735 | 735 | ||
| 736 | MUTEX_LOCK( &K->keeper_cs); | 736 | MUTEX_LOCK( &K->keeper_cs); |
| 737 | //++ K->count; | 737 | //++ K->count; |
| @@ -739,13 +739,13 @@ struct s_Keeper* keeper_acquire( struct s_Keepers* keepers_, ptrdiff_t magic_) | |||
| 739 | } | 739 | } |
| 740 | } | 740 | } |
| 741 | 741 | ||
| 742 | void keeper_release( struct s_Keeper* K) | 742 | void keeper_release( Keeper* K) |
| 743 | { | 743 | { |
| 744 | //-- K->count; | 744 | //-- K->count; |
| 745 | if( K) MUTEX_UNLOCK( &K->keeper_cs); | 745 | if( K) MUTEX_UNLOCK( &K->keeper_cs); |
| 746 | } | 746 | } |
| 747 | 747 | ||
| 748 | void keeper_toggle_nil_sentinels( lua_State* L, int val_i_, enum eLookupMode mode_) | 748 | void keeper_toggle_nil_sentinels( lua_State* L, int val_i_, LookupMode mode_) |
| 749 | { | 749 | { |
| 750 | int i, n = lua_gettop( L); | 750 | int i, n = lua_gettop( L); |
| 751 | for( i = val_i_; i <= n; ++ i) | 751 | for( i = val_i_; i <= n; ++ i) |
| @@ -778,7 +778,7 @@ void keeper_toggle_nil_sentinels( lua_State* L, int val_i_, enum eLookupMode mod | |||
| 778 | * | 778 | * |
| 779 | * Returns: number of return values (pushed to 'L') or -1 in case of error | 779 | * Returns: number of return values (pushed to 'L') or -1 in case of error |
| 780 | */ | 780 | */ |
| 781 | int keeper_call( struct s_Universe* U, lua_State* K, keeper_api_t func_, lua_State* L, void* linda, uint_t starting_index) | 781 | int keeper_call( Universe* U, lua_State* K, keeper_api_t func_, lua_State* L, void* linda, uint_t starting_index) |
| 782 | { | 782 | { |
| 783 | int const args = starting_index ? (lua_gettop( L) - starting_index + 1) : 0; | 783 | int const args = starting_index ? (lua_gettop( L) - starting_index + 1) : 0; |
| 784 | int const Ktos = lua_gettop( K); | 784 | int const Ktos = lua_gettop( K); |
diff --git a/src/keeper.h b/src/keeper.h index 7dbbc16..06cf3be 100644 --- a/src/keeper.h +++ b/src/keeper.h | |||
| @@ -1,27 +1,38 @@ | |||
| 1 | #if !defined( __keeper_h__) | 1 | #if !defined( __keeper_h__) |
| 2 | #define __keeper_h__ 1 | 2 | #define __keeper_h__ 1 |
| 3 | 3 | ||
| 4 | #include "lua.h" | ||
| 5 | #include "threading.h" | ||
| 6 | |||
| 7 | // forwards | ||
| 8 | struct s_Universe; | ||
| 9 | typedef struct s_Universe Universe; | ||
| 10 | enum eLookupMode; | ||
| 11 | typedef enum eLookupMode LookupMode; | ||
| 12 | |||
| 4 | struct s_Keeper | 13 | struct s_Keeper |
| 5 | { | 14 | { |
| 6 | MUTEX_T keeper_cs; | 15 | MUTEX_T keeper_cs; |
| 7 | lua_State* L; | 16 | lua_State* L; |
| 8 | //int count; | 17 | //int count; |
| 9 | }; | 18 | }; |
| 19 | typedef struct s_Keeper Keeper; | ||
| 10 | 20 | ||
| 11 | struct s_Keepers | 21 | struct s_Keepers |
| 12 | { | 22 | { |
| 13 | int nb_keepers; | 23 | int nb_keepers; |
| 14 | struct s_Keeper keeper_array[1]; | 24 | Keeper keeper_array[1]; |
| 15 | }; | 25 | }; |
| 26 | typedef struct s_Keepers Keepers; | ||
| 16 | 27 | ||
| 17 | void init_keepers( struct s_Universe* U, lua_State* L); | 28 | void init_keepers( Universe* U, lua_State* L); |
| 18 | void close_keepers( struct s_Universe* U, lua_State* L); | 29 | void close_keepers( Universe* U, lua_State* L); |
| 19 | 30 | ||
| 20 | struct s_Keeper* keeper_acquire( struct s_Keepers* keepers_, ptrdiff_t magic_); | 31 | Keeper* keeper_acquire( Keepers* keepers_, ptrdiff_t magic_); |
| 21 | #define KEEPER_MAGIC_SHIFT 3 | 32 | #define KEEPER_MAGIC_SHIFT 3 |
| 22 | void keeper_release( struct s_Keeper* K); | 33 | void keeper_release( Keeper* K); |
| 23 | void keeper_toggle_nil_sentinels( lua_State* L, int val_i_, enum eLookupMode const mode_); | 34 | void keeper_toggle_nil_sentinels( lua_State* L, int val_i_, LookupMode const mode_); |
| 24 | int keeper_push_linda_storage( struct s_Universe* U, lua_State* L, void* ptr_, ptrdiff_t magic_); | 35 | int keeper_push_linda_storage( Universe* U, lua_State* L, void* ptr_, ptrdiff_t magic_); |
| 25 | 36 | ||
| 26 | #define NIL_SENTINEL ((void*)keeper_toggle_nil_sentinels) | 37 | #define NIL_SENTINEL ((void*)keeper_toggle_nil_sentinels) |
| 27 | 38 | ||
| @@ -38,6 +49,6 @@ int keepercall_get( lua_State* L); | |||
| 38 | int keepercall_set( lua_State* L); | 49 | int keepercall_set( lua_State* L); |
| 39 | int keepercall_count( lua_State* L); | 50 | int keepercall_count( lua_State* L); |
| 40 | 51 | ||
| 41 | int keeper_call( struct s_Universe* U, lua_State* K, keeper_api_t _func, lua_State* L, void* linda, uint_t starting_index); | 52 | int keeper_call( Universe* U, lua_State* K, keeper_api_t _func, lua_State* L, void* linda, uint_t starting_index); |
| 42 | 53 | ||
| 43 | #endif // __keeper_h__ \ No newline at end of file | 54 | #endif // __keeper_h__ \ No newline at end of file |
diff --git a/src/lanes.c b/src/lanes.c index 3268c8b..0a04d88 100644 --- a/src/lanes.c +++ b/src/lanes.c | |||
| @@ -85,13 +85,14 @@ THE SOFTWARE. | |||
| 85 | #include <stdio.h> | 85 | #include <stdio.h> |
| 86 | #include <stdlib.h> | 86 | #include <stdlib.h> |
| 87 | #include <ctype.h> | 87 | #include <ctype.h> |
| 88 | #include <assert.h> | ||
| 88 | 89 | ||
| 90 | #include "lanes.h" | ||
| 89 | #include "threading.h" | 91 | #include "threading.h" |
| 90 | #include "compat.h" | 92 | #include "compat.h" |
| 91 | #include "tools.h" | 93 | #include "tools.h" |
| 92 | #include "universe.h" | 94 | #include "universe.h" |
| 93 | #include "keeper.h" | 95 | #include "keeper.h" |
| 94 | #include "lanes.h" | ||
| 95 | 96 | ||
| 96 | #if !(defined( PLATFORM_XBOX) || defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC)) | 97 | #if !(defined( PLATFORM_XBOX) || defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC)) |
| 97 | # include <sys/time.h> | 98 | # include <sys/time.h> |
| @@ -122,7 +123,7 @@ enum e_cancel_request | |||
| 122 | // NOTE: values to be changed by either thread, during execution, without | 123 | // NOTE: values to be changed by either thread, during execution, without |
| 123 | // locking, are marked "volatile" | 124 | // locking, are marked "volatile" |
| 124 | // | 125 | // |
| 125 | struct s_lane | 126 | struct s_Lane |
| 126 | { | 127 | { |
| 127 | THREAD_T thread; | 128 | THREAD_T thread; |
| 128 | // | 129 | // |
| @@ -132,7 +133,7 @@ struct s_lane | |||
| 132 | char const* debug_name; | 133 | char const* debug_name; |
| 133 | 134 | ||
| 134 | lua_State* L; | 135 | lua_State* L; |
| 135 | struct s_Universe* U; | 136 | Universe* U; |
| 136 | // | 137 | // |
| 137 | // M: prepares the state, and reads results | 138 | // M: prepares the state, and reads results |
| 138 | // S: while S is running, M must keep out of modifying the state | 139 | // S: while S is running, M must keep out of modifying the state |
| @@ -172,29 +173,30 @@ struct s_lane | |||
| 172 | // M: sets to NORMAL, if issued a kill changes to KILLED | 173 | // M: sets to NORMAL, if issued a kill changes to KILLED |
| 173 | // S: not used | 174 | // S: not used |
| 174 | 175 | ||
| 175 | struct s_lane* volatile selfdestruct_next; | 176 | struct s_Lane* volatile selfdestruct_next; |
| 176 | // | 177 | // |
| 177 | // M: sets to non-NULL if facing lane handle '__gc' cycle but the lane | 178 | // M: sets to non-NULL if facing lane handle '__gc' cycle but the lane |
| 178 | // is still running | 179 | // is still running |
| 179 | // S: cleans up after itself if non-NULL at lane exit | 180 | // S: cleans up after itself if non-NULL at lane exit |
| 180 | 181 | ||
| 181 | #if HAVE_LANE_TRACKING | 182 | #if HAVE_LANE_TRACKING |
| 182 | struct s_lane* volatile tracking_next; | 183 | struct s_Lane* volatile tracking_next; |
| 183 | #endif // HAVE_LANE_TRACKING | 184 | #endif // HAVE_LANE_TRACKING |
| 184 | // | 185 | // |
| 185 | // For tracking only | 186 | // For tracking only |
| 186 | }; | 187 | }; |
| 188 | typedef struct s_Lane Lane; | ||
| 187 | 189 | ||
| 188 | // To allow free-running threads (longer lifespan than the handle's) | 190 | // To allow free-running threads (longer lifespan than the handle's) |
| 189 | // 'struct s_lane' are malloc/free'd and the handle only carries a pointer. | 191 | // 'Lane' are malloc/free'd and the handle only carries a pointer. |
| 190 | // This is not deep userdata since the handle's not portable among lanes. | 192 | // This is not deep userdata since the handle's not portable among lanes. |
| 191 | // | 193 | // |
| 192 | #define lua_toLane( L, i) (*((struct s_lane**) luaL_checkudata( L, i, "Lane"))) | 194 | #define lua_toLane( L, i) (*((Lane**) luaL_checkudata( L, i, "Lane"))) |
| 193 | 195 | ||
| 194 | #define CANCEL_TEST_KEY ((void*)get_lane_from_registry) // used as registry key | 196 | #define CANCEL_TEST_KEY ((void*)get_lane_from_registry) // used as registry key |
| 195 | static inline struct s_lane* get_lane_from_registry( lua_State* L) | 197 | static inline Lane* get_lane_from_registry( lua_State* L) |
| 196 | { | 198 | { |
| 197 | struct s_lane* s; | 199 | Lane* s; |
| 198 | STACK_GROW( L, 1); | 200 | STACK_GROW( L, 1); |
| 199 | STACK_CHECK( L); | 201 | STACK_CHECK( L); |
| 200 | lua_pushlightuserdata( L, CANCEL_TEST_KEY); | 202 | lua_pushlightuserdata( L, CANCEL_TEST_KEY); |
| @@ -206,7 +208,7 @@ static inline struct s_lane* get_lane_from_registry( lua_State* L) | |||
| 206 | } | 208 | } |
| 207 | 209 | ||
| 208 | // intern the debug name in the specified lua state so that the pointer remains valid when the lane's state is closed | 210 | // intern the debug name in the specified lua state so that the pointer remains valid when the lane's state is closed |
| 209 | static void securize_debug_threadname( lua_State* L, struct s_lane* s) | 211 | static void securize_debug_threadname( lua_State* L, Lane* s) |
| 210 | { | 212 | { |
| 211 | STACK_CHECK( L); | 213 | STACK_CHECK( L); |
| 212 | STACK_GROW( L, 3); | 214 | STACK_GROW( L, 3); |
| @@ -231,7 +233,7 @@ static void securize_debug_threadname( lua_State* L, struct s_lane* s) | |||
| 231 | */ | 233 | */ |
| 232 | static inline enum e_cancel_request cancel_test( lua_State* L) | 234 | static inline enum e_cancel_request cancel_test( lua_State* L) |
| 233 | { | 235 | { |
| 234 | struct s_lane* const s = get_lane_from_registry( L); | 236 | Lane* const s = get_lane_from_registry( L); |
| 235 | // 's' is NULL for the original main state (and no-one can cancel that) | 237 | // 's' is NULL for the original main state (and no-one can cancel that) |
| 236 | return s ? s->cancel_request : CANCEL_NONE; | 238 | return s ? s->cancel_request : CANCEL_NONE; |
| 237 | } | 239 | } |
| @@ -320,15 +322,15 @@ static bool_t push_registry_table( lua_State* L, void* key, bool_t create) | |||
| 320 | 322 | ||
| 321 | #if HAVE_LANE_TRACKING | 323 | #if HAVE_LANE_TRACKING |
| 322 | 324 | ||
| 323 | // The chain is ended by '(struct s_lane*)(-1)', not NULL: | 325 | // The chain is ended by '(Lane*)(-1)', not NULL: |
| 324 | // 'tracking_first -> ... -> ... -> (-1)' | 326 | // 'tracking_first -> ... -> ... -> (-1)' |
| 325 | #define TRACKING_END ((struct s_lane *)(-1)) | 327 | #define TRACKING_END ((Lane *)(-1)) |
| 326 | 328 | ||
| 327 | /* | 329 | /* |
| 328 | * Add the lane to tracking chain; the ones still running at the end of the | 330 | * Add the lane to tracking chain; the ones still running at the end of the |
| 329 | * whole process will be cancelled. | 331 | * whole process will be cancelled. |
| 330 | */ | 332 | */ |
| 331 | static void tracking_add( struct s_lane* s) | 333 | static void tracking_add( Lane* s) |
| 332 | { | 334 | { |
| 333 | 335 | ||
| 334 | MUTEX_LOCK( &s->U->tracking_cs); | 336 | MUTEX_LOCK( &s->U->tracking_cs); |
| @@ -344,7 +346,7 @@ static void tracking_add( struct s_lane* s) | |||
| 344 | /* | 346 | /* |
| 345 | * A free-running lane has ended; remove it from tracking chain | 347 | * A free-running lane has ended; remove it from tracking chain |
| 346 | */ | 348 | */ |
| 347 | static bool_t tracking_remove( struct s_lane* s) | 349 | static bool_t tracking_remove( Lane* s) |
| 348 | { | 350 | { |
| 349 | bool_t found = FALSE; | 351 | bool_t found = FALSE; |
| 350 | MUTEX_LOCK( &s->U->tracking_cs); | 352 | MUTEX_LOCK( &s->U->tracking_cs); |
| @@ -355,7 +357,7 @@ static bool_t tracking_remove( struct s_lane* s) | |||
| 355 | // | 357 | // |
| 356 | if( s->tracking_next != NULL) | 358 | if( s->tracking_next != NULL) |
| 357 | { | 359 | { |
| 358 | struct s_lane** ref = (struct s_lane**) &s->U->tracking_first; | 360 | Lane** ref = (Lane**) &s->U->tracking_first; |
| 359 | 361 | ||
| 360 | while( *ref != TRACKING_END) | 362 | while( *ref != TRACKING_END) |
| 361 | { | 363 | { |
| @@ -366,7 +368,7 @@ static bool_t tracking_remove( struct s_lane* s) | |||
| 366 | found = TRUE; | 368 | found = TRUE; |
| 367 | break; | 369 | break; |
| 368 | } | 370 | } |
| 369 | ref = (struct s_lane**) &((*ref)->tracking_next); | 371 | ref = (Lane**) &((*ref)->tracking_next); |
| 370 | } | 372 | } |
| 371 | assert( found); | 373 | assert( found); |
| 372 | } | 374 | } |
| @@ -380,7 +382,7 @@ static bool_t tracking_remove( struct s_lane* s) | |||
| 380 | //--- | 382 | //--- |
| 381 | // low-level cleanup | 383 | // low-level cleanup |
| 382 | 384 | ||
| 383 | static void lane_cleanup( struct s_lane* s) | 385 | static void lane_cleanup( Lane* s) |
| 384 | { | 386 | { |
| 385 | // Clean up after a (finished) thread | 387 | // Clean up after a (finished) thread |
| 386 | // | 388 | // |
| @@ -414,7 +416,7 @@ struct s_Linda | |||
| 414 | { | 416 | { |
| 415 | SIGNAL_T read_happened; | 417 | SIGNAL_T read_happened; |
| 416 | SIGNAL_T write_happened; | 418 | SIGNAL_T write_happened; |
| 417 | struct s_Universe* U; // the universe this linda belongs to | 419 | Universe* U; // the universe this linda belongs to |
| 418 | ptrdiff_t group; // a group to control keeper allocation between lindas | 420 | ptrdiff_t group; // a group to control keeper allocation between lindas |
| 419 | enum e_cancel_request simulate_cancel; | 421 | enum e_cancel_request simulate_cancel; |
| 420 | char name[1]; | 422 | char name[1]; |
| @@ -504,8 +506,8 @@ LUAG_FUNC( linda_send) | |||
| 504 | 506 | ||
| 505 | { | 507 | { |
| 506 | bool_t try_again = TRUE; | 508 | bool_t try_again = TRUE; |
| 507 | struct s_lane* const s = get_lane_from_registry( L); | 509 | Lane* const s = get_lane_from_registry( L); |
| 508 | struct s_Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); | 510 | Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); |
| 509 | lua_State* KL = K ? K->L : NULL; // need to do this for 'STACK_CHECK' | 511 | lua_State* KL = K ? K->L : NULL; // need to do this for 'STACK_CHECK' |
| 510 | if( KL == NULL) return 0; | 512 | if( KL == NULL) return 0; |
| 511 | STACK_CHECK( KL); | 513 | STACK_CHECK( KL); |
| @@ -666,8 +668,8 @@ LUAG_FUNC( linda_receive) | |||
| 666 | 668 | ||
| 667 | { | 669 | { |
| 668 | bool_t try_again = TRUE; | 670 | bool_t try_again = TRUE; |
| 669 | struct s_lane* const s = get_lane_from_registry( L); | 671 | Lane* const s = get_lane_from_registry( L); |
| 670 | struct s_Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); | 672 | Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); |
| 671 | if( K == NULL) return 0; | 673 | if( K == NULL) return 0; |
| 672 | for( ;;) | 674 | for( ;;) |
| 673 | { | 675 | { |
| @@ -770,7 +772,7 @@ LUAG_FUNC( linda_set) | |||
| 770 | check_key_types( L, 2, 2); | 772 | check_key_types( L, 2, 2); |
| 771 | 773 | ||
| 772 | { | 774 | { |
| 773 | struct s_Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); | 775 | Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); |
| 774 | if( K == NULL) return 0; | 776 | if( K == NULL) return 0; |
| 775 | 777 | ||
| 776 | if( linda->simulate_cancel == CANCEL_NONE) | 778 | if( linda->simulate_cancel == CANCEL_NONE) |
| @@ -826,7 +828,7 @@ LUAG_FUNC( linda_count) | |||
| 826 | check_key_types( L, 2, lua_gettop( L)); | 828 | check_key_types( L, 2, lua_gettop( L)); |
| 827 | 829 | ||
| 828 | { | 830 | { |
| 829 | struct s_Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); | 831 | Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); |
| 830 | if( K == NULL) return 0; | 832 | if( K == NULL) return 0; |
| 831 | pushed = keeper_call( linda->U, K->L, KEEPER_API( count), L, linda, 2); | 833 | pushed = keeper_call( linda->U, K->L, KEEPER_API( count), L, linda, 2); |
| 832 | keeper_release( K); | 834 | keeper_release( K); |
| @@ -855,7 +857,7 @@ LUAG_FUNC( linda_get) | |||
| 855 | // make sure the key is of a valid type (throws an error if not the case) | 857 | // make sure the key is of a valid type (throws an error if not the case) |
| 856 | check_key_types( L, 2, 2); | 858 | check_key_types( L, 2, 2); |
| 857 | { | 859 | { |
| 858 | struct s_Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); | 860 | Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); |
| 859 | if( K == NULL) return 0; | 861 | if( K == NULL) return 0; |
| 860 | 862 | ||
| 861 | if( linda->simulate_cancel == CANCEL_NONE) | 863 | if( linda->simulate_cancel == CANCEL_NONE) |
| @@ -904,7 +906,7 @@ LUAG_FUNC( linda_limit) | |||
| 904 | check_key_types( L, 2, 2); | 906 | check_key_types( L, 2, 2); |
| 905 | 907 | ||
| 906 | { | 908 | { |
| 907 | struct s_Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); | 909 | Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); |
| 908 | if( K == NULL) return 0; | 910 | if( K == NULL) return 0; |
| 909 | 911 | ||
| 910 | if( linda->simulate_cancel == CANCEL_NONE) | 912 | if( linda->simulate_cancel == CANCEL_NONE) |
| @@ -939,7 +941,7 @@ LUAG_FUNC( linda_cancel) | |||
| 939 | { | 941 | { |
| 940 | struct s_Linda* linda = lua_toLinda( L, 1); | 942 | struct s_Linda* linda = lua_toLinda( L, 1); |
| 941 | char const* who = luaL_optstring( L, 2, "both"); | 943 | char const* who = luaL_optstring( L, 2, "both"); |
| 942 | struct s_Keeper* K; | 944 | Keeper* K; |
| 943 | 945 | ||
| 944 | // make sure we got 3 arguments: the linda, a key and a limit | 946 | // make sure we got 3 arguments: the linda, a key and a limit |
| 945 | luaL_argcheck( L, lua_gettop( L) <= 2, 2, "wrong number of arguments"); | 947 | luaL_argcheck( L, lua_gettop( L) <= 2, 2, "wrong number of arguments"); |
| @@ -1171,7 +1173,7 @@ static void* linda_id( lua_State* L, enum eDeepOp op_) | |||
| 1171 | 1173 | ||
| 1172 | case eDO_delete: | 1174 | case eDO_delete: |
| 1173 | { | 1175 | { |
| 1174 | struct s_Keeper* K; | 1176 | Keeper* K; |
| 1175 | struct s_Linda* linda = lua_touserdata( L, 1); | 1177 | struct s_Linda* linda = lua_touserdata( L, 1); |
| 1176 | ASSERT_L( linda); | 1178 | ASSERT_L( linda); |
| 1177 | 1179 | ||
| @@ -1435,7 +1437,7 @@ typedef enum | |||
| 1435 | CR_Killed | 1437 | CR_Killed |
| 1436 | } cancel_result; | 1438 | } cancel_result; |
| 1437 | 1439 | ||
| 1438 | static cancel_result thread_cancel( lua_State* L, struct s_lane* s, double secs, bool_t force, double waitkill_timeout_) | 1440 | static cancel_result thread_cancel( lua_State* L, Lane* s, double secs, bool_t force, double waitkill_timeout_) |
| 1439 | { | 1441 | { |
| 1440 | cancel_result result; | 1442 | cancel_result result; |
| 1441 | 1443 | ||
| @@ -1512,16 +1514,16 @@ static cancel_result thread_cancel( lua_State* L, struct s_lane* s, double secs, | |||
| 1512 | // | 1514 | // |
| 1513 | // Protects modifying the selfdestruct chain | 1515 | // Protects modifying the selfdestruct chain |
| 1514 | 1516 | ||
| 1515 | #define SELFDESTRUCT_END ((struct s_lane*)(-1)) | 1517 | #define SELFDESTRUCT_END ((Lane*)(-1)) |
| 1516 | // | 1518 | // |
| 1517 | // The chain is ended by '(struct s_lane*)(-1)', not NULL: | 1519 | // The chain is ended by '(Lane*)(-1)', not NULL: |
| 1518 | // 'selfdestruct_first -> ... -> ... -> (-1)' | 1520 | // 'selfdestruct_first -> ... -> ... -> (-1)' |
| 1519 | 1521 | ||
| 1520 | /* | 1522 | /* |
| 1521 | * Add the lane to selfdestruct chain; the ones still running at the end of the | 1523 | * Add the lane to selfdestruct chain; the ones still running at the end of the |
| 1522 | * whole process will be cancelled. | 1524 | * whole process will be cancelled. |
| 1523 | */ | 1525 | */ |
| 1524 | static void selfdestruct_add( struct s_lane* s) | 1526 | static void selfdestruct_add( Lane* s) |
| 1525 | { | 1527 | { |
| 1526 | MUTEX_LOCK( &s->U->selfdestruct_cs); | 1528 | MUTEX_LOCK( &s->U->selfdestruct_cs); |
| 1527 | assert( s->selfdestruct_next == NULL); | 1529 | assert( s->selfdestruct_next == NULL); |
| @@ -1534,7 +1536,7 @@ static void selfdestruct_add( struct s_lane* s) | |||
| 1534 | /* | 1536 | /* |
| 1535 | * A free-running lane has ended; remove it from selfdestruct chain | 1537 | * A free-running lane has ended; remove it from selfdestruct chain |
| 1536 | */ | 1538 | */ |
| 1537 | static bool_t selfdestruct_remove( struct s_lane* s) | 1539 | static bool_t selfdestruct_remove( Lane* s) |
| 1538 | { | 1540 | { |
| 1539 | bool_t found = FALSE; | 1541 | bool_t found = FALSE; |
| 1540 | MUTEX_LOCK( &s->U->selfdestruct_cs); | 1542 | MUTEX_LOCK( &s->U->selfdestruct_cs); |
| @@ -1545,7 +1547,7 @@ static bool_t selfdestruct_remove( struct s_lane* s) | |||
| 1545 | // | 1547 | // |
| 1546 | if( s->selfdestruct_next != NULL) | 1548 | if( s->selfdestruct_next != NULL) |
| 1547 | { | 1549 | { |
| 1548 | struct s_lane** ref = (struct s_lane**) &s->U->selfdestruct_first; | 1550 | Lane** ref = (Lane**) &s->U->selfdestruct_first; |
| 1549 | 1551 | ||
| 1550 | while( *ref != SELFDESTRUCT_END ) | 1552 | while( *ref != SELFDESTRUCT_END ) |
| 1551 | { | 1553 | { |
| @@ -1558,7 +1560,7 @@ static bool_t selfdestruct_remove( struct s_lane* s) | |||
| 1558 | found = TRUE; | 1560 | found = TRUE; |
| 1559 | break; | 1561 | break; |
| 1560 | } | 1562 | } |
| 1561 | ref = (struct s_lane**) &((*ref)->selfdestruct_next); | 1563 | ref = (Lane**) &((*ref)->selfdestruct_next); |
| 1562 | } | 1564 | } |
| 1563 | assert( found); | 1565 | assert( found); |
| 1564 | } | 1566 | } |
| @@ -1591,7 +1593,7 @@ void * protected_lua_Alloc( void *ud, void *ptr, size_t osize, size_t nsize) | |||
| 1591 | */ | 1593 | */ |
| 1592 | static int selfdestruct_gc( lua_State* L) | 1594 | static int selfdestruct_gc( lua_State* L) |
| 1593 | { | 1595 | { |
| 1594 | struct s_Universe* U = (struct s_Universe*) lua_touserdata( L, 1); | 1596 | Universe* U = (Universe*) lua_touserdata( L, 1); |
| 1595 | 1597 | ||
| 1596 | while( U->selfdestruct_first != SELFDESTRUCT_END) // true at most once! | 1598 | while( U->selfdestruct_first != SELFDESTRUCT_END) // true at most once! |
| 1597 | { | 1599 | { |
| @@ -1599,7 +1601,7 @@ static int selfdestruct_gc( lua_State* L) | |||
| 1599 | // | 1601 | // |
| 1600 | MUTEX_LOCK( &U->selfdestruct_cs); | 1602 | MUTEX_LOCK( &U->selfdestruct_cs); |
| 1601 | { | 1603 | { |
| 1602 | struct s_lane* s = U->selfdestruct_first; | 1604 | Lane* s = U->selfdestruct_first; |
| 1603 | while( s != SELFDESTRUCT_END) | 1605 | while( s != SELFDESTRUCT_END) |
| 1604 | { | 1606 | { |
| 1605 | // attempt a regular unforced hard cancel with a small timeout | 1607 | // attempt a regular unforced hard cancel with a small timeout |
| @@ -1645,7 +1647,7 @@ static int selfdestruct_gc( lua_State* L) | |||
| 1645 | double t_now = 0.0; | 1647 | double t_now = 0.0; |
| 1646 | MUTEX_LOCK( &U->selfdestruct_cs); | 1648 | MUTEX_LOCK( &U->selfdestruct_cs); |
| 1647 | { | 1649 | { |
| 1648 | struct s_lane* s = U->selfdestruct_first; | 1650 | Lane* s = U->selfdestruct_first; |
| 1649 | while( s != SELFDESTRUCT_END) | 1651 | while( s != SELFDESTRUCT_END) |
| 1650 | { | 1652 | { |
| 1651 | if( s->cancel_request == CANCEL_HARD) | 1653 | if( s->cancel_request == CANCEL_HARD) |
| @@ -1689,10 +1691,10 @@ static int selfdestruct_gc( lua_State* L) | |||
| 1689 | // these are not running, and the state can be closed | 1691 | // these are not running, and the state can be closed |
| 1690 | MUTEX_LOCK( &U->selfdestruct_cs); | 1692 | MUTEX_LOCK( &U->selfdestruct_cs); |
| 1691 | { | 1693 | { |
| 1692 | struct s_lane* s = U->selfdestruct_first; | 1694 | Lane* s = U->selfdestruct_first; |
| 1693 | while( s != SELFDESTRUCT_END) | 1695 | while( s != SELFDESTRUCT_END) |
| 1694 | { | 1696 | { |
| 1695 | struct s_lane* next_s = s->selfdestruct_next; | 1697 | Lane* next_s = s->selfdestruct_next; |
| 1696 | s->selfdestruct_next = NULL; // detach from selfdestruct chain | 1698 | s->selfdestruct_next = NULL; // detach from selfdestruct chain |
| 1697 | if( !THREAD_ISNULL( s->thread)) // can be NULL if previous 'soft' termination succeeded | 1699 | if( !THREAD_ISNULL( s->thread)) // can be NULL if previous 'soft' termination succeeded |
| 1698 | { | 1700 | { |
| @@ -1719,7 +1721,7 @@ static int selfdestruct_gc( lua_State* L) | |||
| 1719 | lua_settop( L, 0); | 1721 | lua_settop( L, 0); |
| 1720 | // no need to mutex-protect this as all threads in the universe are gone at that point | 1722 | // no need to mutex-protect this as all threads in the universe are gone at that point |
| 1721 | -- U->timer_deep->refcount; // should be 0 now | 1723 | -- U->timer_deep->refcount; // should be 0 now |
| 1722 | free_deep_prelude( L, (struct DEEP_PRELUDE*) U->timer_deep); | 1724 | free_deep_prelude( L, (DeepPrelude*) U->timer_deep); |
| 1723 | U->timer_deep = NULL; | 1725 | U->timer_deep = NULL; |
| 1724 | 1726 | ||
| 1725 | close_keepers( U, L); | 1727 | close_keepers( U, L); |
| @@ -1959,7 +1961,7 @@ static void push_stack_trace( lua_State* L, int rc_, int stk_base_) | |||
| 1959 | LUAG_FUNC( set_debug_threadname) | 1961 | LUAG_FUNC( set_debug_threadname) |
| 1960 | { | 1962 | { |
| 1961 | // C s_lane structure is a light userdata upvalue | 1963 | // C s_lane structure is a light userdata upvalue |
| 1962 | struct s_lane* s = lua_touserdata( L, lua_upvalueindex( 1)); | 1964 | Lane* s = lua_touserdata( L, lua_upvalueindex( 1)); |
| 1963 | luaL_checktype( L, -1, LUA_TSTRING); // "name" | 1965 | luaL_checktype( L, -1, LUA_TSTRING); // "name" |
| 1964 | // store a hidden reference in the registry to make sure the string is kept around even if a lane decides to manually change the "decoda_name" global... | 1966 | // store a hidden reference in the registry to make sure the string is kept around even if a lane decides to manually change the "decoda_name" global... |
| 1965 | lua_pushlightuserdata( L, LG_set_debug_threadname); // "name" lud | 1967 | lua_pushlightuserdata( L, LG_set_debug_threadname); // "name" lud |
| @@ -1975,7 +1977,7 @@ LUAG_FUNC( set_debug_threadname) | |||
| 1975 | 1977 | ||
| 1976 | LUAG_FUNC( get_debug_threadname) | 1978 | LUAG_FUNC( get_debug_threadname) |
| 1977 | { | 1979 | { |
| 1978 | struct s_lane* const s = lua_toLane( L, 1); | 1980 | Lane* const s = lua_toLane( L, 1); |
| 1979 | luaL_argcheck( L, lua_gettop( L) == 1, 2, "too many arguments"); | 1981 | luaL_argcheck( L, lua_gettop( L) == 1, 2, "too many arguments"); |
| 1980 | lua_pushstring( L, s->debug_name); | 1982 | lua_pushstring( L, s->debug_name); |
| 1981 | return 1; | 1983 | return 1; |
| @@ -2031,7 +2033,7 @@ static char const* get_errcode_name( int _code) | |||
| 2031 | #if THREADWAIT_METHOD == THREADWAIT_CONDVAR // implies THREADAPI == THREADAPI_PTHREAD | 2033 | #if THREADWAIT_METHOD == THREADWAIT_CONDVAR // implies THREADAPI == THREADAPI_PTHREAD |
| 2032 | static void thread_cleanup_handler( void* opaque) | 2034 | static void thread_cleanup_handler( void* opaque) |
| 2033 | { | 2035 | { |
| 2034 | struct s_lane* s= (struct s_lane*) opaque; | 2036 | Lane* s= (Lane*) opaque; |
| 2035 | MUTEX_LOCK( &s->done_lock); | 2037 | MUTEX_LOCK( &s->done_lock); |
| 2036 | s->status = CANCELLED; | 2038 | s->status = CANCELLED; |
| 2037 | SIGNAL_ONE( &s->done_signal); // wake up master (while 's->done_lock' is on) | 2039 | SIGNAL_ONE( &s->done_signal); // wake up master (while 's->done_lock' is on) |
| @@ -2041,12 +2043,12 @@ static void thread_cleanup_handler( void* opaque) | |||
| 2041 | 2043 | ||
| 2042 | static THREAD_RETURN_T THREAD_CALLCONV lane_main( void* vs) | 2044 | static THREAD_RETURN_T THREAD_CALLCONV lane_main( void* vs) |
| 2043 | { | 2045 | { |
| 2044 | struct s_lane* s = (struct s_lane*) vs; | 2046 | Lane* s = (Lane*) vs; |
| 2045 | int rc, rc2; | 2047 | int rc, rc2; |
| 2046 | lua_State* L = s->L; | 2048 | lua_State* L = s->L; |
| 2047 | // Called with the lane function and arguments on the stack | 2049 | // Called with the lane function and arguments on the stack |
| 2048 | int const nargs = lua_gettop( L) - 1; | 2050 | int const nargs = lua_gettop( L) - 1; |
| 2049 | DEBUGSPEW_CODE( struct s_Universe* U = universe_get( L)); | 2051 | DEBUGSPEW_CODE( Universe* U = universe_get( L)); |
| 2050 | THREAD_MAKE_ASYNCH_CANCELLABLE(); | 2052 | THREAD_MAKE_ASYNCH_CANCELLABLE(); |
| 2051 | THREAD_CLEANUP_PUSH( thread_cleanup_handler, s); | 2053 | THREAD_CLEANUP_PUSH( thread_cleanup_handler, s); |
| 2052 | s->status = RUNNING; // PENDING -> RUNNING | 2054 | s->status = RUNNING; // PENDING -> RUNNING |
| @@ -2144,7 +2146,7 @@ LUAG_FUNC( require) | |||
| 2144 | { | 2146 | { |
| 2145 | char const* name = lua_tostring( L, 1); | 2147 | char const* name = lua_tostring( L, 1); |
| 2146 | int const nargs = lua_gettop( L); | 2148 | int const nargs = lua_gettop( L); |
| 2147 | DEBUGSPEW_CODE( struct s_Universe* U = universe_get( L)); | 2149 | DEBUGSPEW_CODE( Universe* U = universe_get( L)); |
| 2148 | STACK_CHECK( L); | 2150 | STACK_CHECK( L); |
| 2149 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.require %s BEGIN\n" INDENT_END, name)); | 2151 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.require %s BEGIN\n" INDENT_END, name)); |
| 2150 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); | 2152 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); |
| @@ -2170,7 +2172,7 @@ LUAG_FUNC( register) | |||
| 2170 | // ignore extra parameters, just in case | 2172 | // ignore extra parameters, just in case |
| 2171 | lua_settop( L, 2); | 2173 | lua_settop( L, 2); |
| 2172 | luaL_argcheck( L, (mod_type == LUA_TTABLE) || (mod_type == LUA_TFUNCTION), 2, "unexpected module type"); | 2174 | luaL_argcheck( L, (mod_type == LUA_TTABLE) || (mod_type == LUA_TFUNCTION), 2, "unexpected module type"); |
| 2173 | DEBUGSPEW_CODE( struct s_Universe* U = universe_get( L)); | 2175 | DEBUGSPEW_CODE( Universe* U = universe_get( L)); |
| 2174 | STACK_CHECK( L); // "name" mod_table | 2176 | STACK_CHECK( L); // "name" mod_table |
| 2175 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.register %s BEGIN\n" INDENT_END, name)); | 2177 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.register %s BEGIN\n" INDENT_END, name)); |
| 2176 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); | 2178 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); |
| @@ -2200,8 +2202,8 @@ LUAG_FUNC( thread_gc); | |||
| 2200 | LUAG_FUNC( lane_new) | 2202 | LUAG_FUNC( lane_new) |
| 2201 | { | 2203 | { |
| 2202 | lua_State* L2; | 2204 | lua_State* L2; |
| 2203 | struct s_lane* s; | 2205 | Lane* s; |
| 2204 | struct s_lane** ud; | 2206 | Lane** ud; |
| 2205 | 2207 | ||
| 2206 | char const* libs_str = lua_tostring( L, 2); | 2208 | char const* libs_str = lua_tostring( L, 2); |
| 2207 | uint_t cancelstep_idx = luaG_optunsigned( L, 3, 0); | 2209 | uint_t cancelstep_idx = luaG_optunsigned( L, 3, 0); |
| @@ -2213,7 +2215,7 @@ LUAG_FUNC( lane_new) | |||
| 2213 | 2215 | ||
| 2214 | #define FIXED_ARGS 8 | 2216 | #define FIXED_ARGS 8 |
| 2215 | int const nargs = lua_gettop(L) - FIXED_ARGS; | 2217 | int const nargs = lua_gettop(L) - FIXED_ARGS; |
| 2216 | struct s_Universe* U = universe_get( L); | 2218 | Universe* U = universe_get( L); |
| 2217 | ASSERT_L( nargs >= 0); | 2219 | ASSERT_L( nargs >= 0); |
| 2218 | 2220 | ||
| 2219 | // public Lanes API accepts a generic range -3/+3 | 2221 | // public Lanes API accepts a generic range -3/+3 |
| @@ -2386,8 +2388,8 @@ LUAG_FUNC( lane_new) | |||
| 2386 | 2388 | ||
| 2387 | // 's' is allocated from heap, not Lua, since its life span may surpass the handle's (if free running thread) | 2389 | // 's' is allocated from heap, not Lua, since its life span may surpass the handle's (if free running thread) |
| 2388 | // | 2390 | // |
| 2389 | ud = lua_newuserdata( L, sizeof( struct s_lane*)); // func libs cancelstep priority globals package required gc_cb lane | 2391 | ud = lua_newuserdata( L, sizeof( Lane*)); // func libs cancelstep priority globals package required gc_cb lane |
| 2390 | s = *ud = (struct s_lane*) malloc( sizeof( struct s_lane)); | 2392 | s = *ud = (Lane*) malloc( sizeof( Lane)); |
| 2391 | if( s == NULL) | 2393 | if( s == NULL) |
| 2392 | { | 2394 | { |
| 2393 | return luaL_error( L, "could not create lane: out of memory"); | 2395 | return luaL_error( L, "could not create lane: out of memory"); |
| @@ -2470,7 +2472,7 @@ LUAG_FUNC( lane_new) | |||
| 2470 | LUAG_FUNC( thread_gc) | 2472 | LUAG_FUNC( thread_gc) |
| 2471 | { | 2473 | { |
| 2472 | bool_t have_gc_cb = FALSE; | 2474 | bool_t have_gc_cb = FALSE; |
| 2473 | struct s_lane* s = lua_toLane( L, 1); // ud | 2475 | Lane* s = lua_toLane( L, 1); // ud |
| 2474 | 2476 | ||
| 2475 | // if there a gc callback? | 2477 | // if there a gc callback? |
| 2476 | lua_getuservalue( L, 1); // ud uservalue | 2478 | lua_getuservalue( L, 1); // ud uservalue |
| @@ -2547,7 +2549,7 @@ LUAG_FUNC( thread_gc) | |||
| 2547 | // lane_h:cancel( [timeout] [, force [, forcekill_timeout]]) | 2549 | // lane_h:cancel( [timeout] [, force [, forcekill_timeout]]) |
| 2548 | LUAG_FUNC( thread_cancel) | 2550 | LUAG_FUNC( thread_cancel) |
| 2549 | { | 2551 | { |
| 2550 | struct s_lane* s = lua_toLane( L, 1); | 2552 | Lane* s = lua_toLane( L, 1); |
| 2551 | double secs = 0.0; | 2553 | double secs = 0.0; |
| 2552 | int force_i = 2; | 2554 | int force_i = 2; |
| 2553 | int forcekill_timeout_i = 3; | 2555 | int forcekill_timeout_i = 3; |
| @@ -2604,7 +2606,7 @@ LUAG_FUNC( thread_cancel) | |||
| 2604 | // / "error" finished at an error, error value is there | 2606 | // / "error" finished at an error, error value is there |
| 2605 | // / "cancelled" execution cancelled by M (state gone) | 2607 | // / "cancelled" execution cancelled by M (state gone) |
| 2606 | // | 2608 | // |
| 2607 | static char const * thread_status_string( struct s_lane* s) | 2609 | static char const * thread_status_string( Lane* s) |
| 2608 | { | 2610 | { |
| 2609 | enum e_status st = s->status; // read just once (volatile) | 2611 | enum e_status st = s->status; // read just once (volatile) |
| 2610 | char const* str = | 2612 | char const* str = |
| @@ -2618,7 +2620,7 @@ static char const * thread_status_string( struct s_lane* s) | |||
| 2618 | return str; | 2620 | return str; |
| 2619 | } | 2621 | } |
| 2620 | 2622 | ||
| 2621 | static int push_thread_status( lua_State* L, struct s_lane* s) | 2623 | static int push_thread_status( lua_State* L, Lane* s) |
| 2622 | { | 2624 | { |
| 2623 | char const* const str = thread_status_string( s); | 2625 | char const* const str = thread_status_string( s); |
| 2624 | ASSERT_L( str); | 2626 | ASSERT_L( str); |
| @@ -2638,7 +2640,7 @@ static int push_thread_status( lua_State* L, struct s_lane* s) | |||
| 2638 | // | 2640 | // |
| 2639 | LUAG_FUNC( thread_join) | 2641 | LUAG_FUNC( thread_join) |
| 2640 | { | 2642 | { |
| 2641 | struct s_lane* const s = lua_toLane( L, 1); | 2643 | Lane* const s = lua_toLane( L, 1); |
| 2642 | double wait_secs = luaL_optnumber( L, 2, -1.0); | 2644 | double wait_secs = luaL_optnumber( L, 2, -1.0); |
| 2643 | lua_State* L2 = s->L; | 2645 | lua_State* L2 = s->L; |
| 2644 | int ret; | 2646 | int ret; |
| @@ -2661,7 +2663,7 @@ LUAG_FUNC( thread_join) | |||
| 2661 | } | 2663 | } |
| 2662 | else | 2664 | else |
| 2663 | { | 2665 | { |
| 2664 | struct s_Universe* U = universe_get( L); | 2666 | Universe* U = universe_get( L); |
| 2665 | // debug_name is a pointer to string possibly interned in the lane's state, that no longer exists when the state is closed | 2667 | // debug_name is a pointer to string possibly interned in the lane's state, that no longer exists when the state is closed |
| 2666 | // so store it in the userdata uservalue at a key that can't possibly collide | 2668 | // so store it in the userdata uservalue at a key that can't possibly collide |
| 2667 | securize_debug_threadname( L, s); | 2669 | securize_debug_threadname( L, s); |
| @@ -2722,7 +2724,7 @@ LUAG_FUNC( thread_index) | |||
| 2722 | int const UD = 1; | 2724 | int const UD = 1; |
| 2723 | int const KEY = 2; | 2725 | int const KEY = 2; |
| 2724 | int const USR = 3; | 2726 | int const USR = 3; |
| 2725 | struct s_lane* const s = lua_toLane( L, UD); | 2727 | Lane* const s = lua_toLane( L, UD); |
| 2726 | ASSERT_L( lua_gettop( L) == 2); | 2728 | ASSERT_L( lua_gettop( L) == 2); |
| 2727 | 2729 | ||
| 2728 | STACK_GROW( L, 8); // up to 8 positions are needed in case of error propagation | 2730 | STACK_GROW( L, 8); // up to 8 positions are needed in case of error propagation |
| @@ -2873,14 +2875,14 @@ LUAG_FUNC( thread_index) | |||
| 2873 | LUAG_FUNC( threads) | 2875 | LUAG_FUNC( threads) |
| 2874 | { | 2876 | { |
| 2875 | int const top = lua_gettop( L); | 2877 | int const top = lua_gettop( L); |
| 2876 | struct s_Universe* U = universe_get( L); | 2878 | Universe* U = universe_get( L); |
| 2877 | 2879 | ||
| 2878 | // List _all_ still running threads | 2880 | // List _all_ still running threads |
| 2879 | // | 2881 | // |
| 2880 | MUTEX_LOCK( &U->tracking_cs); | 2882 | MUTEX_LOCK( &U->tracking_cs); |
| 2881 | if( U->tracking_first && U->tracking_first != TRACKING_END) | 2883 | if( U->tracking_first && U->tracking_first != TRACKING_END) |
| 2882 | { | 2884 | { |
| 2883 | struct s_lane* s = U->tracking_first; | 2885 | Lane* s = U->tracking_first; |
| 2884 | lua_newtable( L); // {} | 2886 | lua_newtable( L); // {} |
| 2885 | while( s != TRACKING_END) | 2887 | while( s != TRACKING_END) |
| 2886 | { | 2888 | { |
| @@ -3025,7 +3027,7 @@ static volatile long s_initCount = 0; | |||
| 3025 | // param 1: settings table | 3027 | // param 1: settings table |
| 3026 | LUAG_FUNC( configure) | 3028 | LUAG_FUNC( configure) |
| 3027 | { | 3029 | { |
| 3028 | struct s_Universe* U = universe_get( L); | 3030 | Universe* U = universe_get( L); |
| 3029 | bool_t const from_master_state = (U == NULL); | 3031 | bool_t const from_master_state = (U == NULL); |
| 3030 | char const* name = luaL_checkstring( L, lua_upvalueindex( 1)); | 3032 | char const* name = luaL_checkstring( L, lua_upvalueindex( 1)); |
| 3031 | _ASSERT_L( L, lua_type( L, 1) == LUA_TTABLE); | 3033 | _ASSERT_L( L, lua_type( L, 1) == LUA_TTABLE); |
| @@ -3129,7 +3131,7 @@ LUAG_FUNC( configure) | |||
| 3129 | STACK_MID( L, 1); | 3131 | STACK_MID( L, 1); |
| 3130 | 3132 | ||
| 3131 | // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer | 3133 | // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer |
| 3132 | U->timer_deep = *(struct DEEP_PRELUDE**) lua_touserdata( L, -1); | 3134 | U->timer_deep = *(DeepPrelude**) lua_touserdata( L, -1); |
| 3133 | ASSERT_L( U->timer_deep && (U->timer_deep->refcount == 1) && U->timer_deep->deep && U->timer_deep->idfunc == linda_id); | 3135 | ASSERT_L( U->timer_deep && (U->timer_deep->refcount == 1) && U->timer_deep->deep && U->timer_deep->idfunc == linda_id); |
| 3134 | // increment refcount that this linda remains alive as long as the universe is. | 3136 | // increment refcount that this linda remains alive as long as the universe is. |
| 3135 | ++ U->timer_deep->refcount; | 3137 | ++ U->timer_deep->refcount; |
| @@ -3159,7 +3161,7 @@ LUAG_FUNC( configure) | |||
| 3159 | 3161 | ||
| 3160 | { | 3162 | { |
| 3161 | char const* errmsg; | 3163 | char const* errmsg; |
| 3162 | errmsg = push_deep_proxy( U, L, (struct DEEP_PRELUDE*) U->timer_deep, eLM_LaneBody);// settings M timer_deep | 3164 | errmsg = push_deep_proxy( U, L, (DeepPrelude*) U->timer_deep, eLM_LaneBody);// settings M timer_deep |
| 3163 | if( errmsg != NULL) | 3165 | if( errmsg != NULL) |
| 3164 | { | 3166 | { |
| 3165 | return luaL_error( L, errmsg); | 3167 | return luaL_error( L, errmsg); |
diff --git a/src/lanes.h b/src/lanes.h index d07750a..23fa711 100644 --- a/src/lanes.h +++ b/src/lanes.h | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | #define __lanes_h__ 1 | 2 | #define __lanes_h__ 1 |
| 3 | 3 | ||
| 4 | #include "lua.h" | 4 | #include "lua.h" |
| 5 | #include "platform.h" | ||
| 5 | 6 | ||
| 6 | #if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) | 7 | #if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) |
| 7 | #define LANES_API __declspec(dllexport) | 8 | #define LANES_API __declspec(dllexport) |
diff --git a/src/macros_and_utils.h b/src/macros_and_utils.h index d584c2b..2a619b3 100644 --- a/src/macros_and_utils.h +++ b/src/macros_and_utils.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #define MACROS_AND_UTILS_H | 5 | #define MACROS_AND_UTILS_H |
| 6 | 6 | ||
| 7 | #include "lua.h" | 7 | #include "lua.h" |
| 8 | #include "lualib.h" | ||
| 8 | 9 | ||
| 9 | // M$ compiler doesn't support 'inline' keyword in C files... | 10 | // M$ compiler doesn't support 'inline' keyword in C files... |
| 10 | #if defined( _MSC_VER) | 11 | #if defined( _MSC_VER) |
diff --git a/src/platform.h b/src/platform.h new file mode 100644 index 0000000..da5264e --- /dev/null +++ b/src/platform.h | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | #ifndef __LANES_PLATFORM_H__ | ||
| 2 | #define __LANES_PLATFORM_H__ 1 | ||
| 3 | |||
| 4 | #ifdef _WIN32_WCE | ||
| 5 | #define PLATFORM_POCKETPC | ||
| 6 | #elif defined(_XBOX) | ||
| 7 | #define PLATFORM_XBOX | ||
| 8 | #elif (defined _WIN32) | ||
| 9 | #define PLATFORM_WIN32 | ||
| 10 | #elif (defined __linux__) | ||
| 11 | #define PLATFORM_LINUX | ||
| 12 | #elif (defined __APPLE__) && (defined __MACH__) | ||
| 13 | #define PLATFORM_OSX | ||
| 14 | #elif (defined __NetBSD__) || (defined __FreeBSD__) || (defined BSD) | ||
| 15 | #define PLATFORM_BSD | ||
| 16 | #elif (defined __QNX__) | ||
| 17 | #define PLATFORM_QNX | ||
| 18 | #elif (defined __CYGWIN__) | ||
| 19 | #define PLATFORM_CYGWIN | ||
| 20 | #else | ||
| 21 | #error "Unknown platform!" | ||
| 22 | #endif | ||
| 23 | |||
| 24 | #endif // __LANES_PLATFORM_H__ | ||
diff --git a/src/threading.h b/src/threading.h index bfa9ab8..4114dba 100644 --- a/src/threading.h +++ b/src/threading.h | |||
| @@ -4,30 +4,12 @@ | |||
| 4 | #ifndef __threading_h__ | 4 | #ifndef __threading_h__ |
| 5 | #define __threading_h__ 1 | 5 | #define __threading_h__ 1 |
| 6 | 6 | ||
| 7 | /* Platform detection | 7 | /* |
| 8 | * win32-pthread: | 8 | * win32-pthread: |
| 9 | * define HAVE_WIN32_PTHREAD and PTW32_INCLUDE_WINDOWS_H in your project configuration when building for win32-pthread. | 9 | * define HAVE_WIN32_PTHREAD and PTW32_INCLUDE_WINDOWS_H in your project configuration when building for win32-pthread. |
| 10 | * link against pthreadVC2.lib, and of course have pthreadVC2.dll somewhere in your path. | 10 | * link against pthreadVC2.lib, and of course have pthreadVC2.dll somewhere in your path. |
| 11 | */ | 11 | */ |
| 12 | #ifdef _WIN32_WCE | 12 | #include "platform.h" |
| 13 | #define PLATFORM_POCKETPC | ||
| 14 | #elif defined(_XBOX) | ||
| 15 | #define PLATFORM_XBOX | ||
| 16 | #elif (defined _WIN32) | ||
| 17 | #define PLATFORM_WIN32 | ||
| 18 | #elif (defined __linux__) | ||
| 19 | #define PLATFORM_LINUX | ||
| 20 | #elif (defined __APPLE__) && (defined __MACH__) | ||
| 21 | #define PLATFORM_OSX | ||
| 22 | #elif (defined __NetBSD__) || (defined __FreeBSD__) || (defined BSD) | ||
| 23 | #define PLATFORM_BSD | ||
| 24 | #elif (defined __QNX__) | ||
| 25 | #define PLATFORM_QNX | ||
| 26 | #elif (defined __CYGWIN__) | ||
| 27 | #define PLATFORM_CYGWIN | ||
| 28 | #else | ||
| 29 | #error "Unknown platform!" | ||
| 30 | #endif | ||
| 31 | 13 | ||
| 32 | typedef int bool_t; | 14 | typedef int bool_t; |
| 33 | #ifndef FALSE | 15 | #ifndef FALSE |
diff --git a/src/tools.c b/src/tools.c index 13e714d..051e3cc 100644 --- a/src/tools.c +++ b/src/tools.c | |||
| @@ -31,22 +31,22 @@ THE SOFTWARE. | |||
| 31 | =============================================================================== | 31 | =============================================================================== |
| 32 | */ | 32 | */ |
| 33 | 33 | ||
| 34 | #include "compat.h" | ||
| 35 | #include "universe.h" | ||
| 36 | #include "tools.h" | ||
| 37 | #include "keeper.h" | ||
| 38 | #include "lanes.h" | ||
| 39 | |||
| 40 | #include <stdio.h> | 34 | #include <stdio.h> |
| 41 | #include <string.h> | 35 | #include <string.h> |
| 42 | #include <ctype.h> | 36 | #include <ctype.h> |
| 43 | #include <stdlib.h> | 37 | #include <stdlib.h> |
| 44 | #if !defined(__APPLE__) | 38 | #if !defined(__APPLE__) |
| 45 | #include <malloc.h> | 39 | #include <malloc.h> |
| 46 | #endif | 40 | #endif // __APPLE__ |
| 41 | |||
| 42 | #include "tools.h" | ||
| 43 | #include "compat.h" | ||
| 44 | #include "universe.h" | ||
| 45 | #include "keeper.h" | ||
| 46 | #include "lanes.h" | ||
| 47 | 47 | ||
| 48 | // functions implemented in deep.c | 48 | // functions implemented in deep.c |
| 49 | extern luaG_IdFunction copydeep( struct s_Universe* U, lua_State* L, lua_State* L2, int index, enum eLookupMode mode_); | 49 | extern luaG_IdFunction copydeep( Universe* U, lua_State* L, lua_State* L2, int index, LookupMode mode_); |
| 50 | extern void push_registry_subtable( lua_State* L, void* key_); | 50 | extern void push_registry_subtable( lua_State* L, void* key_); |
| 51 | 51 | ||
| 52 | char const* const CONFIG_REGKEY = "ee932492-a654-4506-9da8-f16540bdb5d4"; | 52 | char const* const CONFIG_REGKEY = "ee932492-a654-4506-9da8-f16540bdb5d4"; |
| @@ -105,7 +105,7 @@ void luaG_dump( lua_State* L) | |||
| 105 | fprintf( stderr, "\n"); | 105 | fprintf( stderr, "\n"); |
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | void initialize_on_state_create( struct s_Universe* U, lua_State* L) | 108 | void initialize_on_state_create( Universe* U, lua_State* L) |
| 109 | { | 109 | { |
| 110 | STACK_CHECK( L); | 110 | STACK_CHECK( L); |
| 111 | lua_getfield( L, -1, "on_state_create"); // settings on_state_create|nil | 111 | lua_getfield( L, -1, "on_state_create"); // settings on_state_create|nil |
| @@ -139,7 +139,7 @@ void initialize_on_state_create( struct s_Universe* U, lua_State* L) | |||
| 139 | // ################################################################################################ | 139 | // ################################################################################################ |
| 140 | 140 | ||
| 141 | // just like lua_xmove, args are (from, to) | 141 | // just like lua_xmove, args are (from, to) |
| 142 | void luaG_copy_one_time_settings( struct s_Universe* U, lua_State* L, lua_State* L2) | 142 | void luaG_copy_one_time_settings( Universe* U, lua_State* L, lua_State* L2) |
| 143 | { | 143 | { |
| 144 | STACK_GROW( L, 1); | 144 | STACK_GROW( L, 1); |
| 145 | // copy settings from from source to destination registry | 145 | // copy settings from from source to destination registry |
| @@ -198,7 +198,7 @@ static const luaL_Reg libs[] = | |||
| 198 | { NULL, NULL } | 198 | { NULL, NULL } |
| 199 | }; | 199 | }; |
| 200 | 200 | ||
| 201 | static void open1lib( struct s_Universe* U, lua_State* L, char const* name_, size_t len_, lua_State* from_) | 201 | static void open1lib( Universe* U, lua_State* L, char const* name_, size_t len_, lua_State* from_) |
| 202 | { | 202 | { |
| 203 | int i; | 203 | int i; |
| 204 | for( i = 0; libs[i].name; ++ i) | 204 | for( i = 0; libs[i].name; ++ i) |
| @@ -341,7 +341,7 @@ static void update_lookup_entry( lua_State* L, int _ctx_base, int _depth) | |||
| 341 | size_t prevNameLength, newNameLength; | 341 | size_t prevNameLength, newNameLength; |
| 342 | char const* prevName; | 342 | char const* prevName; |
| 343 | DEBUGSPEW_CODE( char const *newName); | 343 | DEBUGSPEW_CODE( char const *newName); |
| 344 | DEBUGSPEW_CODE( struct s_Universe* U = universe_get( L)); | 344 | DEBUGSPEW_CODE( Universe* U = universe_get( L)); |
| 345 | 345 | ||
| 346 | STACK_CHECK( L); | 346 | STACK_CHECK( L); |
| 347 | // first, raise an error if the function is already known | 347 | // first, raise an error if the function is already known |
| @@ -412,7 +412,7 @@ static void populate_func_lookup_table_recur( lua_State* L, int _ctx_base, int _ | |||
| 412 | int const cache = _ctx_base + 2; | 412 | int const cache = _ctx_base + 2; |
| 413 | // we need to remember subtables to process them after functions encountered at the current depth (breadth-first search) | 413 | // we need to remember subtables to process them after functions encountered at the current depth (breadth-first search) |
| 414 | int const breadth_first_cache = lua_gettop( L) + 1; | 414 | int const breadth_first_cache = lua_gettop( L) + 1; |
| 415 | DEBUGSPEW_CODE( struct s_Universe* U = universe_get( L)); | 415 | DEBUGSPEW_CODE( Universe* U = universe_get( L)); |
| 416 | 416 | ||
| 417 | STACK_GROW( L, 6); | 417 | STACK_GROW( L, 6); |
| 418 | // slot _i contains a table where we search for functions (or a full userdata with a metatable) | 418 | // slot _i contains a table where we search for functions (or a full userdata with a metatable) |
| @@ -530,7 +530,7 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* name_) | |||
| 530 | int const ctx_base = lua_gettop( L) + 1; | 530 | int const ctx_base = lua_gettop( L) + 1; |
| 531 | int const in_base = lua_absindex( L, _i); | 531 | int const in_base = lua_absindex( L, _i); |
| 532 | int start_depth = 0; | 532 | int start_depth = 0; |
| 533 | DEBUGSPEW_CODE( struct s_Universe* U = universe_get( L)); | 533 | DEBUGSPEW_CODE( Universe* U = universe_get( L)); |
| 534 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: populate_func_lookup_table('%s')\n" INDENT_END, L, name_ ? name_ : "NULL")); | 534 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: populate_func_lookup_table('%s')\n" INDENT_END, L, name_ ? name_ : "NULL")); |
| 535 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); | 535 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); |
| 536 | STACK_GROW( L, 3); | 536 | STACK_GROW( L, 3); |
| @@ -585,7 +585,7 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* name_) | |||
| 585 | DEBUGSPEW_CODE( -- U->debugspew_indent_depth); | 585 | DEBUGSPEW_CODE( -- U->debugspew_indent_depth); |
| 586 | } | 586 | } |
| 587 | 587 | ||
| 588 | void call_on_state_create( struct s_Universe* U, lua_State* L, lua_State* from_, enum eLookupMode mode_) | 588 | void call_on_state_create( Universe* U, lua_State* L, lua_State* from_, LookupMode mode_) |
| 589 | { | 589 | { |
| 590 | if( U->on_state_create_func != NULL) | 590 | if( U->on_state_create_func != NULL) |
| 591 | { | 591 | { |
| @@ -630,7 +630,7 @@ void call_on_state_create( struct s_Universe* U, lua_State* L, lua_State* from_, | |||
| 630 | * *NOT* called for keeper states! | 630 | * *NOT* called for keeper states! |
| 631 | * | 631 | * |
| 632 | */ | 632 | */ |
| 633 | lua_State* luaG_newstate( struct s_Universe* U, lua_State* from_, char const* libs_) | 633 | lua_State* luaG_newstate( Universe* U, lua_State* from_, char const* libs_) |
| 634 | { | 634 | { |
| 635 | // re-use alloc function from the originating state | 635 | // re-use alloc function from the originating state |
| 636 | #if PROPAGATE_ALLOCF | 636 | #if PROPAGATE_ALLOCF |
| @@ -761,7 +761,7 @@ lua_State* luaG_newstate( struct s_Universe* U, lua_State* from_, char const* li | |||
| 761 | /* | 761 | /* |
| 762 | * Get a unique ID for metatable at [i]. | 762 | * Get a unique ID for metatable at [i]. |
| 763 | */ | 763 | */ |
| 764 | static uint_t get_mt_id( struct s_Universe* U, lua_State* L, int i) | 764 | static uint_t get_mt_id( Universe* U, lua_State* L, int i) |
| 765 | { | 765 | { |
| 766 | uint_t id; | 766 | uint_t id; |
| 767 | 767 | ||
| @@ -828,9 +828,9 @@ static int table_lookup_sentinel( lua_State* L) | |||
| 828 | /* | 828 | /* |
| 829 | * retrieve the name of a function/table in the lookup database | 829 | * retrieve the name of a function/table in the lookup database |
| 830 | */ | 830 | */ |
| 831 | static char const* find_lookup_name( lua_State* L, uint_t i, enum eLookupMode mode_, char const* upName_, size_t* len_) | 831 | static char const* find_lookup_name( lua_State* L, uint_t i, LookupMode mode_, char const* upName_, size_t* len_) |
| 832 | { | 832 | { |
| 833 | DEBUGSPEW_CODE( struct s_Universe* const U = universe_get( L)); | 833 | DEBUGSPEW_CODE( Universe* const U = universe_get( L)); |
| 834 | char const* fqn; | 834 | char const* fqn; |
| 835 | ASSERT_L( lua_isfunction( L, i) || lua_istable( L, i)); // ... v ... | 835 | ASSERT_L( lua_isfunction( L, i) || lua_istable( L, i)); // ... v ... |
| 836 | STACK_CHECK( L); | 836 | STACK_CHECK( L); |
| @@ -899,7 +899,7 @@ static char const* find_lookup_name( lua_State* L, uint_t i, enum eLookupMode mo | |||
| 899 | /* | 899 | /* |
| 900 | * Push a looked-up table, or nothing if we found nothing | 900 | * Push a looked-up table, or nothing if we found nothing |
| 901 | */ | 901 | */ |
| 902 | static bool_t lookup_table( lua_State* L2, lua_State* L, uint_t i, enum eLookupMode mode_, char const* upName_) | 902 | static bool_t lookup_table( lua_State* L2, lua_State* L, uint_t i, LookupMode mode_, char const* upName_) |
| 903 | { | 903 | { |
| 904 | // get the name of the table we want to send | 904 | // get the name of the table we want to send |
| 905 | size_t len; | 905 | size_t len; |
| @@ -1195,7 +1195,7 @@ int luaG_nameof( lua_State* L) | |||
| 1195 | /* | 1195 | /* |
| 1196 | * Push a looked-up native/LuaJIT function. | 1196 | * Push a looked-up native/LuaJIT function. |
| 1197 | */ | 1197 | */ |
| 1198 | static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i, enum eLookupMode mode_, char const* upName_) | 1198 | static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i, LookupMode mode_, char const* upName_) |
| 1199 | { | 1199 | { |
| 1200 | // get the name of the function we want to send | 1200 | // get the name of the function we want to send |
| 1201 | size_t len; | 1201 | size_t len; |
| @@ -1276,9 +1276,9 @@ enum e_vt | |||
| 1276 | VT_KEY, | 1276 | VT_KEY, |
| 1277 | VT_METATABLE | 1277 | VT_METATABLE |
| 1278 | }; | 1278 | }; |
| 1279 | static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum e_vt value_type, enum eLookupMode mode_, char const* upName_); | 1279 | static bool_t inter_copy_one_( Universe* U, lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum e_vt value_type, LookupMode mode_, char const* upName_); |
| 1280 | 1280 | ||
| 1281 | static void inter_copy_func( struct s_Universe* U, lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum eLookupMode mode_, char const* upName_) | 1281 | static void inter_copy_func( Universe* U, lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, LookupMode mode_, char const* upName_) |
| 1282 | { | 1282 | { |
| 1283 | int n, needToPush; | 1283 | int n, needToPush; |
| 1284 | luaL_Buffer b; | 1284 | luaL_Buffer b; |
| @@ -1427,7 +1427,7 @@ static void inter_copy_func( struct s_Universe* U, lua_State* L2, uint_t L2_cach | |||
| 1427 | * | 1427 | * |
| 1428 | * Always pushes a function to 'L2'. | 1428 | * Always pushes a function to 'L2'. |
| 1429 | */ | 1429 | */ |
| 1430 | static void push_cached_func( struct s_Universe* U, lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum eLookupMode mode_, char const* upName_) | 1430 | static void push_cached_func( Universe* U, lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, LookupMode mode_, char const* upName_) |
| 1431 | { | 1431 | { |
| 1432 | FuncSubType funcSubType; | 1432 | FuncSubType funcSubType; |
| 1433 | /*lua_CFunction cfunc =*/ luaG_tocfunction( L, i, &funcSubType); // NULL for LuaJIT-fast && bytecode functions | 1433 | /*lua_CFunction cfunc =*/ luaG_tocfunction( L, i, &funcSubType); // NULL for LuaJIT-fast && bytecode functions |
| @@ -1480,7 +1480,7 @@ static void push_cached_func( struct s_Universe* U, lua_State* L2, uint_t L2_cac | |||
| 1480 | } | 1480 | } |
| 1481 | } | 1481 | } |
| 1482 | 1482 | ||
| 1483 | static bool_t push_cached_metatable( struct s_Universe* U, lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum eLookupMode mode_, char const* upName_) | 1483 | static bool_t push_cached_metatable( Universe* U, lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum eLookupMode mode_, char const* upName_) |
| 1484 | { | 1484 | { |
| 1485 | if( lua_getmetatable( L, i)) // ... mt | 1485 | if( lua_getmetatable( L, i)) // ... mt |
| 1486 | { | 1486 | { |
| @@ -1526,6 +1526,58 @@ static bool_t push_cached_metatable( struct s_Universe* U, lua_State* L2, uint_t | |||
| 1526 | return FALSE; | 1526 | return FALSE; |
| 1527 | } | 1527 | } |
| 1528 | 1528 | ||
| 1529 | static void inter_copy_keyvaluepair( Universe* U, lua_State* L2, uint_t L2_cache_i, lua_State* L, enum e_vt vt, LookupMode mode_, char const* upName_) | ||
| 1530 | { | ||
| 1531 | uint_t val_i = lua_gettop( L); | ||
| 1532 | uint_t key_i = val_i - 1; | ||
| 1533 | |||
| 1534 | // Only basic key types are copied over; others ignored | ||
| 1535 | if( inter_copy_one_( U, L2, 0 /*key*/, L, key_i, VT_KEY, mode_, upName_)) | ||
| 1536 | { | ||
| 1537 | char* valPath = (char*) upName_; | ||
| 1538 | if( U->verboseErrors) | ||
| 1539 | { | ||
| 1540 | // for debug purposes, let's try to build a useful name | ||
| 1541 | if( lua_type( L, key_i) == LUA_TSTRING) | ||
| 1542 | { | ||
| 1543 | char const* key = lua_tostring( L, key_i); | ||
| 1544 | size_t const keyRawLen = lua_rawlen( L, key_i); | ||
| 1545 | size_t const bufLen = strlen( upName_) + keyRawLen + 2; | ||
| 1546 | valPath = (char*) alloca( bufLen); | ||
| 1547 | sprintf( valPath, "%s.%*s", upName_, (int) keyRawLen, key); | ||
| 1548 | key = NULL; | ||
| 1549 | } | ||
| 1550 | #if defined LUA_LNUM || LUA_VERSION_NUM >= 503 | ||
| 1551 | else if( lua_isinteger( L, key_i)) | ||
| 1552 | { | ||
| 1553 | lua_Integer key = lua_tointeger( L, key_i); | ||
| 1554 | valPath = (char*) alloca( strlen( upName_) + 32 + 3); | ||
| 1555 | sprintf( valPath, "%s[" LUA_INTEGER_FMT "]", upName_, key); | ||
| 1556 | } | ||
| 1557 | #endif // defined LUA_LNUM || LUA_VERSION_NUM >= 503 | ||
| 1558 | else if( lua_type( L, key_i) == LUA_TNUMBER) | ||
| 1559 | { | ||
| 1560 | lua_Number key = lua_tonumber( L, key_i); | ||
| 1561 | valPath = (char*) alloca( strlen( upName_) + 32 + 3); | ||
| 1562 | sprintf( valPath, "%s[" LUA_NUMBER_FMT "]", upName_, key); | ||
| 1563 | } | ||
| 1564 | } | ||
| 1565 | /* | ||
| 1566 | * Contents of metatables are copied with cache checking; | ||
| 1567 | * important to detect loops. | ||
| 1568 | */ | ||
| 1569 | if( inter_copy_one_( U, L2, L2_cache_i, L, val_i, VT_NORMAL, mode_, valPath)) | ||
| 1570 | { | ||
| 1571 | ASSERT_L( lua_istable( L2, -3)); | ||
| 1572 | lua_rawset( L2, -3); // add to table (pops key & val) | ||
| 1573 | } | ||
| 1574 | else | ||
| 1575 | { | ||
| 1576 | luaL_error( L, "Unable to copy over type '%s' (in %s)", luaL_typename( L, val_i), (vt == VT_NORMAL) ? "table" : "metatable"); | ||
| 1577 | } | ||
| 1578 | } | ||
| 1579 | } | ||
| 1580 | |||
| 1529 | /* | 1581 | /* |
| 1530 | * Copies a value from 'L' state (at index 'i') to 'L2' state. Does not remove | 1582 | * Copies a value from 'L' state (at index 'i') to 'L2' state. Does not remove |
| 1531 | * the original value. | 1583 | * the original value. |
| @@ -1536,7 +1588,7 @@ static bool_t push_cached_metatable( struct s_Universe* U, lua_State* L2, uint_t | |||
| 1536 | * | 1588 | * |
| 1537 | * Returns TRUE if value was pushed, FALSE if its type is non-supported. | 1589 | * Returns TRUE if value was pushed, FALSE if its type is non-supported. |
| 1538 | */ | 1590 | */ |
| 1539 | static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum e_vt vt, enum eLookupMode mode_, char const* upName_) | 1591 | static bool_t inter_copy_one_( Universe* U, lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum e_vt vt, LookupMode mode_, char const* upName_) |
| 1540 | { | 1592 | { |
| 1541 | bool_t ret = TRUE; | 1593 | bool_t ret = TRUE; |
| 1542 | bool_t ignore = FALSE; | 1594 | bool_t ignore = FALSE; |
| @@ -1575,7 +1627,7 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca | |||
| 1575 | break; | 1627 | break; |
| 1576 | } | 1628 | } |
| 1577 | else | 1629 | else |
| 1578 | #endif | 1630 | #endif // defined LUA_LNUM || LUA_VERSION_NUM >= 503 |
| 1579 | { | 1631 | { |
| 1580 | lua_Number v = lua_tonumber( L, i); | 1632 | lua_Number v = lua_tonumber( L, i); |
| 1581 | DEBUGSPEW_CODE( if( vt == VT_KEY) fprintf( stderr, INDENT_BEGIN "KEY: " LUA_NUMBER_FMT "\n" INDENT_END, v)); | 1633 | DEBUGSPEW_CODE( if( vt == VT_KEY) fprintf( stderr, INDENT_BEGIN "KEY: " LUA_NUMBER_FMT "\n" INDENT_END, v)); |
| @@ -1735,41 +1787,8 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca | |||
| 1735 | lua_pushnil( L); // start iteration | 1787 | lua_pushnil( L); // start iteration |
| 1736 | while( lua_next( L, i)) | 1788 | while( lua_next( L, i)) |
| 1737 | { | 1789 | { |
| 1738 | uint_t val_i = lua_gettop( L); | 1790 | // need a function to prevent overflowing the stack with verboseErrors-induced alloca() |
| 1739 | uint_t key_i = val_i - 1; | 1791 | inter_copy_keyvaluepair( U, L2, L2_cache_i, L, vt, mode_, upName_); |
| 1740 | |||
| 1741 | // Only basic key types are copied over; others ignored | ||
| 1742 | if( inter_copy_one_( U, L2, 0 /*key*/, L, key_i, VT_KEY, mode_, upName_)) | ||
| 1743 | { | ||
| 1744 | char* valPath = (char*) upName_; | ||
| 1745 | if( U->verboseErrors) | ||
| 1746 | { | ||
| 1747 | // for debug purposes, let's try to build a useful name | ||
| 1748 | if( lua_type( L, key_i) == LUA_TSTRING) | ||
| 1749 | { | ||
| 1750 | valPath = (char*) alloca( strlen( upName_) + strlen( lua_tostring( L, key_i)) + 2); | ||
| 1751 | sprintf( valPath, "%s.%s", upName_, lua_tostring( L, key_i)); | ||
| 1752 | } | ||
| 1753 | else if( lua_type( L, key_i) == LUA_TNUMBER) | ||
| 1754 | { | ||
| 1755 | valPath = (char*) alloca( strlen( upName_) + 32 + 3); | ||
| 1756 | sprintf( valPath, "%s[" LUA_NUMBER_FMT "]", upName_, lua_tonumber( L, key_i)); | ||
| 1757 | } | ||
| 1758 | } | ||
| 1759 | /* | ||
| 1760 | * Contents of metatables are copied with cache checking; | ||
| 1761 | * important to detect loops. | ||
| 1762 | */ | ||
| 1763 | if( inter_copy_one_( U, L2, L2_cache_i, L, val_i, VT_NORMAL, mode_, valPath)) | ||
| 1764 | { | ||
| 1765 | ASSERT_L( lua_istable( L2, -3)); | ||
| 1766 | lua_rawset( L2, -3); // add to table (pops key & val) | ||
| 1767 | } | ||
| 1768 | else | ||
| 1769 | { | ||
| 1770 | (void) luaL_error( L, "Unable to copy over type '%s' (in %s)", luaL_typename( L, val_i), (vt == VT_NORMAL) ? "table" : "metatable"); | ||
| 1771 | } | ||
| 1772 | } | ||
| 1773 | lua_pop( L, 1); // pop value (next round) | 1792 | lua_pop( L, 1); // pop value (next round) |
| 1774 | } | 1793 | } |
| 1775 | STACK_MID( L, 0); | 1794 | STACK_MID( L, 0); |
| @@ -1805,7 +1824,7 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca | |||
| 1805 | * | 1824 | * |
| 1806 | * Note: Parameters are in this order ('L' = from first) to be same as 'lua_xmove'. | 1825 | * Note: Parameters are in this order ('L' = from first) to be same as 'lua_xmove'. |
| 1807 | */ | 1826 | */ |
| 1808 | int luaG_inter_copy( struct s_Universe* U, lua_State* L, lua_State* L2, uint_t n, enum eLookupMode mode_) | 1827 | int luaG_inter_copy( Universe* U, lua_State* L, lua_State* L2, uint_t n, LookupMode mode_) |
| 1809 | { | 1828 | { |
| 1810 | uint_t top_L = lua_gettop( L); | 1829 | uint_t top_L = lua_gettop( L); |
| 1811 | uint_t top_L2 = lua_gettop( L2); | 1830 | uint_t top_L2 = lua_gettop( L2); |
| @@ -1863,14 +1882,14 @@ int luaG_inter_copy( struct s_Universe* U, lua_State* L, lua_State* L2, uint_t n | |||
| 1863 | } | 1882 | } |
| 1864 | 1883 | ||
| 1865 | 1884 | ||
| 1866 | int luaG_inter_move( struct s_Universe* U, lua_State* L, lua_State* L2, uint_t n, enum eLookupMode mode_) | 1885 | int luaG_inter_move( Universe* U, lua_State* L, lua_State* L2, uint_t n, LookupMode mode_) |
| 1867 | { | 1886 | { |
| 1868 | int ret = luaG_inter_copy( U, L, L2, n, mode_); | 1887 | int ret = luaG_inter_copy( U, L, L2, n, mode_); |
| 1869 | lua_pop( L, (int) n); | 1888 | lua_pop( L, (int) n); |
| 1870 | return ret; | 1889 | return ret; |
| 1871 | } | 1890 | } |
| 1872 | 1891 | ||
| 1873 | int luaG_inter_copy_package( struct s_Universe* U, lua_State* L, lua_State* L2, int package_idx_, enum eLookupMode mode_) | 1892 | int luaG_inter_copy_package( Universe* U, lua_State* L, lua_State* L2, int package_idx_, LookupMode mode_) |
| 1874 | { | 1893 | { |
| 1875 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_inter_copy_package()\n" INDENT_END)); | 1894 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_inter_copy_package()\n" INDENT_END)); |
| 1876 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); | 1895 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); |
| @@ -1937,7 +1956,7 @@ int luaG_new_require( lua_State* L) | |||
| 1937 | { | 1956 | { |
| 1938 | int rc, i; | 1957 | int rc, i; |
| 1939 | int args = lua_gettop( L); | 1958 | int args = lua_gettop( L); |
| 1940 | struct s_Universe* U = universe_get( L); | 1959 | Universe* U = universe_get( L); |
| 1941 | //char const* modname = luaL_checkstring( L, 1); | 1960 | //char const* modname = luaL_checkstring( L, 1); |
| 1942 | 1961 | ||
| 1943 | STACK_GROW( L, args + 1); | 1962 | STACK_GROW( L, args + 1); |
| @@ -1970,7 +1989,7 @@ int luaG_new_require( lua_State* L) | |||
| 1970 | /* | 1989 | /* |
| 1971 | * Serialize calls to 'require', if it exists | 1990 | * Serialize calls to 'require', if it exists |
| 1972 | */ | 1991 | */ |
| 1973 | void serialize_require( struct s_Universe* U, lua_State* L) | 1992 | void serialize_require( Universe* U, lua_State* L) |
| 1974 | { | 1993 | { |
| 1975 | STACK_GROW( L, 1); | 1994 | STACK_GROW( L, 1); |
| 1976 | STACK_CHECK( L); | 1995 | STACK_CHECK( L); |
diff --git a/src/tools.h b/src/tools.h index 9155747..df429f7 100644 --- a/src/tools.h +++ b/src/tools.h | |||
| @@ -1,28 +1,15 @@ | |||
| 1 | /* | 1 | #ifndef __LANES_TOOLS_H__ |
| 2 | * TOOLS.H | 2 | #define __LANES_TOOLS_H__ |
| 3 | */ | ||
| 4 | #ifndef TOOLS_H | ||
| 5 | #define TOOLS_H | ||
| 6 | 3 | ||
| 7 | #include "lauxlib.h" | 4 | //#include "lauxlib.h" |
| 8 | #include "threading.h" | 5 | #include "threading.h" |
| 9 | #include "deep.h" | 6 | #include "deep.h" |
| 10 | // MUTEX_T | ||
| 11 | |||
| 12 | #include <assert.h> | ||
| 13 | 7 | ||
| 14 | #include "macros_and_utils.h" | 8 | #include "macros_and_utils.h" |
| 15 | 9 | ||
| 16 | // ################################################################################################ | 10 | // forwards |
| 17 | 11 | struct s_Universe; | |
| 18 | // this is pointed to by full userdata proxies, and allocated with malloc() to survive any lua_State lifetime | 12 | typedef struct s_Universe Universe; |
| 19 | struct DEEP_PRELUDE | ||
| 20 | { | ||
| 21 | volatile int refcount; | ||
| 22 | void* deep; | ||
| 23 | // when stored in a keeper state, the full userdata doesn't have a metatable, so we need direct access to the idfunc | ||
| 24 | luaG_IdFunction idfunc; | ||
| 25 | }; | ||
| 26 | 13 | ||
| 27 | // ################################################################################################ | 14 | // ################################################################################################ |
| 28 | 15 | ||
| @@ -33,8 +20,8 @@ struct DEEP_PRELUDE | |||
| 33 | 20 | ||
| 34 | void luaG_dump( lua_State* L ); | 21 | void luaG_dump( lua_State* L ); |
| 35 | 22 | ||
| 36 | lua_State* luaG_newstate( struct s_Universe* U, lua_State* _from, char const* libs); | 23 | lua_State* luaG_newstate( Universe* U, lua_State* _from, char const* libs); |
| 37 | void luaG_copy_one_time_settings( struct s_Universe* U, lua_State* L, lua_State* L2); | 24 | void luaG_copy_one_time_settings( Universe* U, lua_State* L, lua_State* L2); |
| 38 | 25 | ||
| 39 | // ################################################################################################ | 26 | // ################################################################################################ |
| 40 | 27 | ||
| @@ -44,26 +31,24 @@ enum eLookupMode | |||
| 44 | eLM_ToKeeper, // send a function from a lane to a keeper state | 31 | eLM_ToKeeper, // send a function from a lane to a keeper state |
| 45 | eLM_FromKeeper // send a function from a keeper state to a lane | 32 | eLM_FromKeeper // send a function from a keeper state to a lane |
| 46 | }; | 33 | }; |
| 34 | typedef enum eLookupMode LookupMode; | ||
| 47 | 35 | ||
| 48 | char const* push_deep_proxy( struct s_Universe* U, lua_State* L, struct DEEP_PRELUDE* prelude, enum eLookupMode mode_); | 36 | int luaG_inter_copy_package( Universe* U, lua_State* L, lua_State* L2, int package_idx_, LookupMode mode_); |
| 49 | void free_deep_prelude( lua_State* L, struct DEEP_PRELUDE* prelude_); | ||
| 50 | |||
| 51 | int luaG_inter_copy_package( struct s_Universe* U, lua_State* L, lua_State* L2, int package_idx_, enum eLookupMode mode_); | ||
| 52 | 37 | ||
| 53 | int luaG_inter_copy( struct s_Universe* U, lua_State* L, lua_State* L2, uint_t n, enum eLookupMode mode_); | 38 | int luaG_inter_copy( Universe* U, lua_State* L, lua_State* L2, uint_t n, LookupMode mode_); |
| 54 | int luaG_inter_move( struct s_Universe* U, lua_State* L, lua_State* L2, uint_t n, enum eLookupMode mode_); | 39 | int luaG_inter_move( Universe* U, lua_State* L, lua_State* L2, uint_t n, LookupMode mode_); |
| 55 | 40 | ||
| 56 | int luaG_nameof( lua_State* L); | 41 | int luaG_nameof( lua_State* L); |
| 57 | int luaG_new_require( lua_State* L); | 42 | int luaG_new_require( lua_State* L); |
| 58 | 43 | ||
| 59 | void populate_func_lookup_table( lua_State* L, int _i, char const* _name); | 44 | void populate_func_lookup_table( lua_State* L, int _i, char const* _name); |
| 60 | void serialize_require( struct s_Universe* U, lua_State *L); | 45 | void serialize_require( Universe* U, lua_State *L); |
| 61 | void initialize_on_state_create( struct s_Universe* U, lua_State* L); | 46 | void initialize_on_state_create( Universe* U, lua_State* L); |
| 62 | void call_on_state_create( struct s_Universe* U, lua_State* L, lua_State* from_, enum eLookupMode mode_); | 47 | void call_on_state_create( Universe* U, lua_State* L, lua_State* from_, LookupMode mode_); |
| 63 | 48 | ||
| 64 | // ################################################################################################ | 49 | // ################################################################################################ |
| 65 | 50 | ||
| 66 | extern char const* const CONFIG_REGKEY; | 51 | extern char const* const CONFIG_REGKEY; |
| 67 | extern char const* const LOOKUP_REGKEY; | 52 | extern char const* const LOOKUP_REGKEY; |
| 68 | 53 | ||
| 69 | #endif // TOOLS_H | 54 | #endif // __LANES_TOOLS_H__ |
diff --git a/src/universe.c b/src/universe.c index ba78396..8bcdcfe 100644 --- a/src/universe.c +++ b/src/universe.c | |||
| @@ -28,19 +28,19 @@ THE SOFTWARE. | |||
| 28 | =============================================================================== | 28 | =============================================================================== |
| 29 | */ | 29 | */ |
| 30 | 30 | ||
| 31 | #include "universe.h" | ||
| 31 | #include "compat.h" | 32 | #include "compat.h" |
| 32 | #include "macros_and_utils.h" | 33 | #include "macros_and_utils.h" |
| 33 | #include "universe.h" | ||
| 34 | 34 | ||
| 35 | // crc64/we of string "UNIVERSE_REGKEY" generated at https://www.nitrxgen.net/hashgen/ | 35 | // crc64/we of string "UNIVERSE_REGKEY" generated at https://www.nitrxgen.net/hashgen/ |
| 36 | static void* const UNIVERSE_REGKEY = ((void*)0x9f877b2cf078f17f); | 36 | static void* const UNIVERSE_REGKEY = ((void*)0x9f877b2cf078f17f); |
| 37 | 37 | ||
| 38 | // ################################################################################################ | 38 | // ################################################################################################ |
| 39 | 39 | ||
| 40 | struct s_Universe* universe_create( lua_State* L) | 40 | Universe* universe_create( lua_State* L) |
| 41 | { | 41 | { |
| 42 | struct s_Universe* U = (struct s_Universe*) lua_newuserdata( L, sizeof(struct s_Universe)); // universe | 42 | Universe* U = (Universe*) lua_newuserdata( L, sizeof(Universe)); // universe |
| 43 | memset( U, 0, sizeof( struct s_Universe)); | 43 | memset( U, 0, sizeof( Universe)); |
| 44 | lua_pushlightuserdata( L, UNIVERSE_REGKEY); // universe UNIVERSE_REGKEY | 44 | lua_pushlightuserdata( L, UNIVERSE_REGKEY); // universe UNIVERSE_REGKEY |
| 45 | lua_pushvalue( L, -2); // universe UNIVERSE_REGKEY universe | 45 | lua_pushvalue( L, -2); // universe UNIVERSE_REGKEY universe |
| 46 | lua_rawset( L, LUA_REGISTRYINDEX); // universe | 46 | lua_rawset( L, LUA_REGISTRYINDEX); // universe |
| @@ -49,7 +49,7 @@ struct s_Universe* universe_create( lua_State* L) | |||
| 49 | 49 | ||
| 50 | // ################################################################################################ | 50 | // ################################################################################################ |
| 51 | 51 | ||
| 52 | void universe_store( lua_State* L, struct s_Universe* U) | 52 | void universe_store( lua_State* L, Universe* U) |
| 53 | { | 53 | { |
| 54 | STACK_CHECK( L); | 54 | STACK_CHECK( L); |
| 55 | lua_pushlightuserdata( L, UNIVERSE_REGKEY); | 55 | lua_pushlightuserdata( L, UNIVERSE_REGKEY); |
| @@ -60,9 +60,9 @@ void universe_store( lua_State* L, struct s_Universe* U) | |||
| 60 | 60 | ||
| 61 | // ################################################################################################ | 61 | // ################################################################################################ |
| 62 | 62 | ||
| 63 | struct s_Universe* universe_get( lua_State* L) | 63 | Universe* universe_get( lua_State* L) |
| 64 | { | 64 | { |
| 65 | struct s_Universe* universe; | 65 | Universe* universe; |
| 66 | STACK_GROW( L, 2); | 66 | STACK_GROW( L, 2); |
| 67 | STACK_CHECK( L); | 67 | STACK_CHECK( L); |
| 68 | lua_pushlightuserdata( L, UNIVERSE_REGKEY); | 68 | lua_pushlightuserdata( L, UNIVERSE_REGKEY); |
diff --git a/src/universe.h b/src/universe.h index 0ca5bf7..a75cead 100644 --- a/src/universe.h +++ b/src/universe.h | |||
| @@ -6,7 +6,14 @@ | |||
| 6 | 6 | ||
| 7 | #include "lua.h" | 7 | #include "lua.h" |
| 8 | #include "threading.h" | 8 | #include "threading.h" |
| 9 | // MUTEX_T | 9 | |
| 10 | // forwards | ||
| 11 | struct s_DeepPrelude; | ||
| 12 | typedef struct s_DeepPrelude DeepPrelude; | ||
| 13 | struct s_Keepers; | ||
| 14 | typedef struct s_Keepers Keepers; | ||
| 15 | struct s_Lane; | ||
| 16 | typedef struct s_Lane Lane; | ||
| 10 | 17 | ||
| 11 | // ################################################################################################ | 18 | // ################################################################################################ |
| 12 | 19 | ||
| @@ -27,15 +34,15 @@ struct s_Universe | |||
| 27 | 34 | ||
| 28 | lua_CFunction on_state_create_func; | 35 | lua_CFunction on_state_create_func; |
| 29 | 36 | ||
| 30 | struct s_Keepers* keepers; | 37 | Keepers* keepers; |
| 31 | 38 | ||
| 32 | // Initialized by 'init_once_LOCKED()': the deep userdata Linda object | 39 | // Initialized by 'init_once_LOCKED()': the deep userdata Linda object |
| 33 | // used for timers (each lane will get a proxy to this) | 40 | // used for timers (each lane will get a proxy to this) |
| 34 | volatile struct DEEP_PRELUDE* timer_deep; // = NULL | 41 | volatile DeepPrelude* timer_deep; // = NULL |
| 35 | 42 | ||
| 36 | #if HAVE_LANE_TRACKING | 43 | #if HAVE_LANE_TRACKING |
| 37 | MUTEX_T tracking_cs; | 44 | MUTEX_T tracking_cs; |
| 38 | struct s_lane* volatile tracking_first; // will change to TRACKING_END if we want to activate tracking | 45 | Lane* volatile tracking_first; // will change to TRACKING_END if we want to activate tracking |
| 39 | #endif // HAVE_LANE_TRACKING | 46 | #endif // HAVE_LANE_TRACKING |
| 40 | 47 | ||
| 41 | MUTEX_T selfdestruct_cs; | 48 | MUTEX_T selfdestruct_cs; |
| @@ -53,14 +60,15 @@ struct s_Universe | |||
| 53 | int debugspew_indent_depth; | 60 | int debugspew_indent_depth; |
| 54 | #endif // USE_DEBUG_SPEW | 61 | #endif // USE_DEBUG_SPEW |
| 55 | 62 | ||
| 56 | struct s_lane* volatile selfdestruct_first; | 63 | Lane* volatile selfdestruct_first; |
| 57 | // After a lane has removed itself from the chain, it still performs some processing. | 64 | // After a lane has removed itself from the chain, it still performs some processing. |
| 58 | // The terminal desinit sequence should wait for all such processing to terminate before force-killing threads | 65 | // The terminal desinit sequence should wait for all such processing to terminate before force-killing threads |
| 59 | int volatile selfdestructing_count; | 66 | int volatile selfdestructing_count; |
| 60 | }; | 67 | }; |
| 68 | typedef struct s_Universe Universe; | ||
| 61 | 69 | ||
| 62 | struct s_Universe* universe_get( lua_State* L); | 70 | Universe* universe_get( lua_State* L); |
| 63 | struct s_Universe* universe_create( lua_State* L); | 71 | Universe* universe_create( lua_State* L); |
| 64 | void universe_store( lua_State* L, struct s_Universe* U); | 72 | void universe_store( lua_State* L, Universe* U); |
| 65 | 73 | ||
| 66 | #endif // UNIVERSE_H | 74 | #endif // UNIVERSE_H |
