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> | 2017-08-01 09:40:44 +0200 |
|---|---|---|
| committer | Benoit Germain <b n t DOT g e r m a i n AT g m a i l DOT c o m> | 2017-08-01 09:40:44 +0200 |
| commit | e0dbd33c2d4776d6b2213dd82f344166eafde438 (patch) | |
| tree | bab4483f9f5b0d802bdbfc8641fe44ff9649382f | |
| parent | fcd08030b6b6af81a8aa2672082a55f602006f78 (diff) | |
| download | lanes-e0dbd33c2d4776d6b2213dd82f344166eafde438.tar.gz lanes-e0dbd33c2d4776d6b2213dd82f344166eafde438.tar.bz2 lanes-e0dbd33c2d4776d6b2213dd82f344166eafde438.zip | |
Fix for deep-aware modules
Don't crash when using a module that creates Lanes-compatible deep
userdata.
Added a sample deep-aware module.
| -rw-r--r-- | CHANGES | 4 | ||||
| -rw-r--r-- | CMakeLists.txt | 2 | ||||
| -rw-r--r-- | deep_test/deep_test.c | 91 | ||||
| -rw-r--r-- | deep_test/deep_test.lua | 13 | ||||
| -rw-r--r-- | docs/index.html | 6 | ||||
| -rw-r--r-- | src/Makefile | 2 | ||||
| -rw-r--r-- | src/deep.c | 61 | ||||
| -rw-r--r-- | src/keeper.c | 8 | ||||
| -rw-r--r-- | src/lanes.c | 45 | ||||
| -rw-r--r-- | src/macros_and_utils.h | 71 | ||||
| -rw-r--r-- | src/tools.c | 48 | ||||
| -rw-r--r-- | src/tools.h | 118 | ||||
| -rw-r--r-- | src/universe.c | 74 | ||||
| -rw-r--r-- | src/universe.h | 66 |
14 files changed, 396 insertions, 213 deletions
| @@ -1,5 +1,9 @@ | |||
| 1 | CHANGES: | 1 | CHANGES: |
| 2 | 2 | ||
| 3 | CHANGE 122: BGe 1-Aug-17 | ||
| 4 | * fix crash trying to use a deep-aware module while not requiring Lanes | ||
| 5 | * bumped version to 3.12 | ||
| 6 | |||
| 3 | CHANGE 121: BGe 13-Jun-17 | 7 | CHANGE 121: BGe 13-Jun-17 |
| 4 | * no longer internally assert when an error message is not a string | 8 | * no longer internally assert when an error message is not a string |
| 5 | 9 | ||
diff --git a/CMakeLists.txt b/CMakeLists.txt index 37c372b..8ce1bd3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -38,7 +38,7 @@ ENDIF(CYGWIN) | |||
| 38 | 38 | ||
| 39 | # Build | 39 | # Build |
| 40 | INCLUDE_DIRECTORIES(src) | 40 | INCLUDE_DIRECTORIES(src) |
| 41 | ADD_LIBRARY(core MODULE src/lanes.c src/deep.c src/threading.c src/tools.c src/keeper.c src/compat.c) | 41 | ADD_LIBRARY(core MODULE src/lanes.c src/deep.c src/threading.c src/tools.c src/keeper.c src/compat.c src/universe.c) |
| 42 | 42 | ||
| 43 | IF(UNIX AND NOT CYGWIN) | 43 | IF(UNIX AND NOT CYGWIN) |
| 44 | SET(LIBS pthread) | 44 | SET(LIBS pthread) |
diff --git a/deep_test/deep_test.c b/deep_test/deep_test.c new file mode 100644 index 0000000..a48ecb2 --- /dev/null +++ b/deep_test/deep_test.c | |||
| @@ -0,0 +1,91 @@ | |||
| 1 | #include "lua.h" | ||
| 2 | #include "lualib.h" | ||
| 3 | #include "lauxlib.h" | ||
| 4 | |||
| 5 | #include "deep.h" | ||
| 6 | |||
| 7 | #if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) | ||
| 8 | #define LANES_API __declspec(dllexport) | ||
| 9 | #else | ||
| 10 | #define LANES_API | ||
| 11 | #endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) | ||
| 12 | |||
| 13 | // ################################################################################################ | ||
| 14 | |||
| 15 | static int deep_tostring(lua_State* L) | ||
| 16 | { | ||
| 17 | lua_pushliteral( L, "I am a deep_test"); | ||
| 18 | return 1; | ||
| 19 | } | ||
| 20 | |||
| 21 | // ################################################################################################ | ||
| 22 | |||
| 23 | static luaL_Reg const deep_mt[] = | ||
| 24 | { | ||
| 25 | { "__tostring", deep_tostring}, | ||
| 26 | { NULL, NULL } | ||
| 27 | }; | ||
| 28 | |||
| 29 | // ################################################################################################ | ||
| 30 | |||
| 31 | static void* deep_test_id( lua_State* L, enum eDeepOp op_) | ||
| 32 | { | ||
| 33 | switch( op_) | ||
| 34 | { | ||
| 35 | case eDO_new: | ||
| 36 | { | ||
| 37 | void* allocUD; | ||
| 38 | lua_Alloc allocF = lua_getallocf( L, &allocUD); | ||
| 39 | void* deep_test = allocF( allocUD, NULL, 0, sizeof(void*)); | ||
| 40 | return deep_test; | ||
| 41 | } | ||
| 42 | |||
| 43 | case eDO_delete: | ||
| 44 | { | ||
| 45 | void* allocUD; | ||
| 46 | lua_Alloc allocF = lua_getallocf( L, &allocUD); | ||
| 47 | void* deep_test = lua_touserdata( L, 1); | ||
| 48 | allocF( allocUD, deep_test, sizeof(void*), 0); | ||
| 49 | return NULL; | ||
| 50 | } | ||
| 51 | |||
| 52 | case eDO_metatable: | ||
| 53 | { | ||
| 54 | lua_newtable( L); | ||
| 55 | luaL_setfuncs( L, deep_mt, 0); | ||
| 56 | luaG_pushdeepversion( L); | ||
| 57 | return NULL; | ||
| 58 | } | ||
| 59 | |||
| 60 | case eDO_module: | ||
| 61 | return "deep_test"; | ||
| 62 | |||
| 63 | default: | ||
| 64 | { | ||
| 65 | return NULL; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | // ################################################################################################ | ||
| 71 | |||
| 72 | int luaD_new_deep(lua_State* L) | ||
| 73 | { | ||
| 74 | return luaG_newdeepuserdata( L, deep_test_id); | ||
| 75 | } | ||
| 76 | |||
| 77 | // ################################################################################################ | ||
| 78 | |||
| 79 | static luaL_Reg const deep_module[] = | ||
| 80 | { | ||
| 81 | { "new_deep", luaD_new_deep}, | ||
| 82 | { NULL, NULL} | ||
| 83 | }; | ||
| 84 | |||
| 85 | // ################################################################################################ | ||
| 86 | |||
| 87 | extern int __declspec(dllexport) luaopen_deep_test(lua_State* L) | ||
| 88 | { | ||
| 89 | luaL_newlib( L, deep_module); | ||
| 90 | return 1; | ||
| 91 | } | ||
diff --git a/deep_test/deep_test.lua b/deep_test/deep_test.lua new file mode 100644 index 0000000..034c07d --- /dev/null +++ b/deep_test/deep_test.lua | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | -- create a deep-aware full userdata while Lanes isn't loaded | ||
| 2 | local dt = require "deep_test" | ||
| 3 | local deep = dt.new_deep() | ||
| 4 | print( deep) | ||
| 5 | |||
| 6 | -- now load Lanes and see if that userdata is transferable | ||
| 7 | |||
| 8 | local lanes = require("lanes").configure() | ||
| 9 | |||
| 10 | local l = lanes.linda "my linda" | ||
| 11 | l.put( "key", deep) | ||
| 12 | local out = l.get( "key") | ||
| 13 | print( out) \ No newline at end of file | ||
diff --git a/docs/index.html b/docs/index.html index feee273..703fa69 100644 --- a/docs/index.html +++ b/docs/index.html | |||
| @@ -70,7 +70,7 @@ | |||
| 70 | </p> | 70 | </p> |
| 71 | 71 | ||
| 72 | <p> | 72 | <p> |
| 73 | This document was revised on 5-Jun-17, and applies to version <tt>3.11</tt>. | 73 | This document was revised on 1-Aug-17, and applies to version <tt>3.12</tt>. |
| 74 | </p> | 74 | </p> |
| 75 | </font> | 75 | </font> |
| 76 | </center> | 76 | </center> |
| @@ -1527,9 +1527,9 @@ events to a common Linda, but... :).</font> | |||
| 1527 | <li><tt>eDO_metatable</tt>: should build a metatable for the object. Don't cache the metatable yourself, Lanes takes care of it (<tt>eDO_metatable</tt> should only be invoked once per state). Push the metatable on the stack, then call <tt>luaG_pushdeepversion()</tt> before returning (new in version 3.9.5).</li> | 1527 | <li><tt>eDO_metatable</tt>: should build a metatable for the object. Don't cache the metatable yourself, Lanes takes care of it (<tt>eDO_metatable</tt> should only be invoked once per state). Push the metatable on the stack, then call <tt>luaG_pushdeepversion()</tt> before returning (new in version 3.9.5).</li> |
| 1528 | <li><tt>eDO_module</tt>: requests the name of the module that exports the idfunc, to be returned. It is necessary so that Lanes can require it in any lane state that receives a userdata. This is to prevent crashes in situations where the module could be unloaded while the idfunc pointer is still held.</li> | 1528 | <li><tt>eDO_module</tt>: requests the name of the module that exports the idfunc, to be returned. It is necessary so that Lanes can require it in any lane state that receives a userdata. This is to prevent crashes in situations where the module could be unloaded while the idfunc pointer is still held.</li> |
| 1529 | </ul> | 1529 | </ul> |
| 1530 | Take a look at <tt>linda_id</tt> in <tt>lanes.c</tt>. | 1530 | Take a look at <tt>linda_id</tt> in <tt>lanes.c</tt> or <tt>deep_test_id</tt> in <tt>deep_test.c</tt>. |
| 1531 | </li> | 1531 | </li> |
| 1532 | <li>Include <tt>"deep.h"</tt> and either link against Lanes or statically compile deep.c into your module if you want to avoid a runtime dependency for users that will use your module without Lanes. | 1532 | <li>Include <tt>"deep.h"</tt> and either link against Lanes or statically compile <tt>deep.c</tt> and <tt>universe.c</tt> into your module if you want to avoid a runtime dependency for users that will use your module without Lanes. |
| 1533 | <li>Instanciate your userdata using <tt>luaG_newdeepuserdata()</tt>, instead of the regular <tt>lua_newuserdata()</tt>. Given an <tt>idfunc</tt>, it sets up the support structures and returns a state-specific proxy userdata for accessing your data. This proxy can also be copied over to other lanes.</li> | 1533 | <li>Instanciate your userdata using <tt>luaG_newdeepuserdata()</tt>, instead of the regular <tt>lua_newuserdata()</tt>. Given an <tt>idfunc</tt>, it sets up the support structures and returns a state-specific proxy userdata for accessing your data. This proxy can also be copied over to other lanes.</li> |
| 1534 | <li>Accessing the deep userdata from your C code, use <tt>luaG_todeep()</tt> instead of the regular <tt>lua_touserdata()</tt>.</li> | 1534 | <li>Accessing the deep userdata from your C code, use <tt>luaG_todeep()</tt> instead of the regular <tt>lua_touserdata()</tt>.</li> |
| 1535 | </ol> | 1535 | </ol> |
diff --git a/src/Makefile b/src/Makefile index 7e45d2a..37b5a37 100644 --- a/src/Makefile +++ b/src/Makefile | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | 7 | ||
| 8 | MODULE=lanes | 8 | MODULE=lanes |
| 9 | 9 | ||
| 10 | SRC=lanes.c compat.c threading.c tools.c deep.c keeper.c | 10 | SRC=lanes.c compat.c threading.c tools.c deep.c keeper.c universe.c |
| 11 | 11 | ||
| 12 | OBJ=$(SRC:.c=.o) | 12 | OBJ=$(SRC:.c=.o) |
| 13 | 13 | ||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * DEEP.C Copyright (c) 2014, Benoit Germain | 2 | * DEEP.C Copyright (c) 2017, Benoit Germain |
| 3 | * | 3 | * |
| 4 | * Depp userdata support, separate in its own source file to help integration | 4 | * Deep userdata support, separate in its own source file to help integration |
| 5 | * without enforcing a Lanes dependency | 5 | * without enforcing a Lanes dependency |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| @@ -9,7 +9,7 @@ | |||
| 9 | =============================================================================== | 9 | =============================================================================== |
| 10 | 10 | ||
| 11 | Copyright (C) 2002-10 Asko Kauppi <akauppi@gmail.com> | 11 | Copyright (C) 2002-10 Asko Kauppi <akauppi@gmail.com> |
| 12 | 2011-14 Benoit Germain <bnt.germain@gmail.com> | 12 | 2011-17 Benoit Germain <bnt.germain@gmail.com> |
| 13 | 13 | ||
| 14 | Permission is hereby granted, free of charge, to any person obtaining a copy | 14 | Permission is hereby granted, free of charge, to any person obtaining a copy |
| 15 | of this software and associated documentation files (the "Software"), to deal | 15 | of this software and associated documentation files (the "Software"), to deal |
| @@ -34,6 +34,7 @@ THE SOFTWARE. | |||
| 34 | 34 | ||
| 35 | #include "compat.h" | 35 | #include "compat.h" |
| 36 | #include "tools.h" | 36 | #include "tools.h" |
| 37 | #include "universe.h" | ||
| 37 | #include "deep.h" | 38 | #include "deep.h" |
| 38 | 39 | ||
| 39 | #include <stdio.h> | 40 | #include <stdio.h> |
| @@ -120,14 +121,15 @@ void luaG_pushdeepversion( lua_State* L) { (void) lua_pushliteral( L, "f248e77a- | |||
| 120 | * metatable -> idfunc | 121 | * metatable -> idfunc |
| 121 | * idfunc -> metatable | 122 | * idfunc -> metatable |
| 122 | */ | 123 | */ |
| 123 | #define DEEP_LOOKUP_KEY ((void*)set_deep_lookup) | 124 | // crc64/we of string "DEEP_LOOKUP_KEY" generated at https://www.nitrxgen.net/hashgen/ |
| 124 | // any unique light userdata | 125 | #define DEEP_LOOKUP_KEY ((void*)0x9fb9b4f3f633d83d) |
| 125 | 126 | ||
| 126 | 127 | ||
| 127 | /* | 128 | /* |
| 128 | * The deep proxy cache is a weak valued table listing all deep UD proxies indexed by the deep UD that they are proxying | 129 | * The deep proxy cache is a weak valued table listing all deep UD proxies indexed by the deep UD that they are proxying |
| 130 | * crc64/we of string "DEEP_PROXY_CACHE_KEY" generated at https://www.nitrxgen.net/hashgen/ | ||
| 129 | */ | 131 | */ |
| 130 | #define DEEP_PROXY_CACHE_KEY ((void*)push_deep_proxy) | 132 | #define DEEP_PROXY_CACHE_KEY ((void*)0x05773d6fc26be106) |
| 131 | 133 | ||
| 132 | /* | 134 | /* |
| 133 | * Sets up [-1]<->[-2] two-way lookups, and ensures the lookup table exists. | 135 | * Sets up [-1]<->[-2] two-way lookups, and ensures the lookup table exists. |
| @@ -163,7 +165,7 @@ static void get_deep_lookup( lua_State* L) | |||
| 163 | { | 165 | { |
| 164 | lua_insert( L, -2); // {} a | 166 | lua_insert( L, -2); // {} a |
| 165 | lua_rawget( L, -2); // {} b | 167 | lua_rawget( L, -2); // {} b |
| 166 | } | 168 | } |
| 167 | lua_remove( L, -2); // a|b | 169 | lua_remove( L, -2); // a|b |
| 168 | STACK_END( L, 0); | 170 | STACK_END( L, 0); |
| 169 | } | 171 | } |
| @@ -177,7 +179,7 @@ static inline luaG_IdFunction get_idfunc( lua_State* L, int index, enum eLookupM | |||
| 177 | // 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 |
| 178 | if( mode_ == eLM_FromKeeper) | 180 | if( mode_ == eLM_FromKeeper) |
| 179 | { | 181 | { |
| 180 | DEEP_PRELUDE** proxy = (DEEP_PRELUDE**) lua_touserdata( L, index); | 182 | struct DEEP_PRELUDE** proxy = (struct DEEP_PRELUDE**) lua_touserdata( L, index); |
| 181 | // we can (and must) cast and fetch the internally stored idfunc | 183 | // we can (and must) cast and fetch the internally stored idfunc |
| 182 | return (*proxy)->idfunc; | 184 | return (*proxy)->idfunc; |
| 183 | } | 185 | } |
| @@ -206,7 +208,7 @@ static inline luaG_IdFunction get_idfunc( lua_State* L, int index, enum eLookupM | |||
| 206 | } | 208 | } |
| 207 | 209 | ||
| 208 | 210 | ||
| 209 | void free_deep_prelude( lua_State* L, DEEP_PRELUDE* prelude_) | 211 | void free_deep_prelude( lua_State* L, struct DEEP_PRELUDE* prelude_) |
| 210 | { | 212 | { |
| 211 | // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup | 213 | // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup |
| 212 | lua_pushlightuserdata( L, prelude_->deep); | 214 | lua_pushlightuserdata( L, prelude_->deep); |
| @@ -224,16 +226,18 @@ void free_deep_prelude( lua_State* L, DEEP_PRELUDE* prelude_) | |||
| 224 | */ | 226 | */ |
| 225 | static int deep_userdata_gc( lua_State* L) | 227 | static int deep_userdata_gc( lua_State* L) |
| 226 | { | 228 | { |
| 227 | DEEP_PRELUDE** proxy = (DEEP_PRELUDE**) lua_touserdata( L, 1); | 229 | struct DEEP_PRELUDE** proxy = (struct DEEP_PRELUDE**) lua_touserdata( L, 1); |
| 228 | DEEP_PRELUDE* p = *proxy; | 230 | struct DEEP_PRELUDE* p = *proxy; |
| 229 | struct s_Universe* U = get_universe( L); | 231 | struct s_Universe* U = universe_get( L); |
| 230 | int v; | 232 | int v; |
| 231 | 233 | ||
| 232 | *proxy = 0; // make sure we don't use it any more | 234 | *proxy = 0; // make sure we don't use it any more |
| 233 | 235 | ||
| 234 | MUTEX_LOCK( &U->deep_lock); | 236 | // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded |
| 237 | // in that case, we are not multithreaded and locking isn't necessary anyway | ||
| 238 | if( U) MUTEX_LOCK( &U->deep_lock); | ||
| 235 | v = -- (p->refcount); | 239 | v = -- (p->refcount); |
| 236 | MUTEX_UNLOCK( &U->deep_lock); | 240 | if (U) MUTEX_UNLOCK( &U->deep_lock); |
| 237 | 241 | ||
| 238 | if( v == 0) | 242 | if( v == 0) |
| 239 | { | 243 | { |
| @@ -260,9 +264,9 @@ static int deep_userdata_gc( lua_State* L) | |||
| 260 | * used in this Lua state (metatable, registring it). Otherwise, increments the | 264 | * used in this Lua state (metatable, registring it). Otherwise, increments the |
| 261 | * reference count. | 265 | * reference count. |
| 262 | */ | 266 | */ |
| 263 | char const* push_deep_proxy( struct s_Universe* U, lua_State* L, DEEP_PRELUDE* prelude, enum eLookupMode mode_) | 267 | char const* push_deep_proxy( struct s_Universe* U, lua_State* L, struct DEEP_PRELUDE* prelude, enum eLookupMode mode_) |
| 264 | { | 268 | { |
| 265 | DEEP_PRELUDE** proxy; | 269 | struct DEEP_PRELUDE** proxy; |
| 266 | 270 | ||
| 267 | // Check if a proxy already exists | 271 | // Check if a proxy already exists |
| 268 | push_registry_subtable_mode( L, DEEP_PROXY_CACHE_KEY, "v"); // DPC | 272 | push_registry_subtable_mode( L, DEEP_PROXY_CACHE_KEY, "v"); // DPC |
| @@ -278,14 +282,16 @@ char const* push_deep_proxy( struct s_Universe* U, lua_State* L, DEEP_PRELUDE* p | |||
| 278 | lua_pop( L, 1); // DPC | 282 | lua_pop( L, 1); // DPC |
| 279 | } | 283 | } |
| 280 | 284 | ||
| 281 | MUTEX_LOCK( &U->deep_lock); | 285 | // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded |
| 286 | // in that case, we are not multithreaded and locking isn't necessary anyway | ||
| 287 | if( U) MUTEX_LOCK( &U->deep_lock); | ||
| 282 | ++ (prelude->refcount); // one more proxy pointing to this deep data | 288 | ++ (prelude->refcount); // one more proxy pointing to this deep data |
| 283 | MUTEX_UNLOCK( &U->deep_lock); | 289 | if( U) MUTEX_UNLOCK( &U->deep_lock); |
| 284 | 290 | ||
| 285 | STACK_GROW( L, 7); | 291 | STACK_GROW( L, 7); |
| 286 | STACK_CHECK( L); | 292 | STACK_CHECK( L); |
| 287 | 293 | ||
| 288 | proxy = lua_newuserdata( L, sizeof( DEEP_PRELUDE*)); // DPC proxy | 294 | proxy = lua_newuserdata( L, sizeof(struct DEEP_PRELUDE*)); // DPC proxy |
| 289 | ASSERT_L( proxy); | 295 | ASSERT_L( proxy); |
| 290 | *proxy = prelude; | 296 | *proxy = prelude; |
| 291 | 297 | ||
| @@ -301,7 +307,7 @@ char const* push_deep_proxy( struct s_Universe* U, lua_State* L, DEEP_PRELUDE* p | |||
| 301 | // 1 - make one and register it | 307 | // 1 - make one and register it |
| 302 | if( mode_ != eLM_ToKeeper) | 308 | if( mode_ != eLM_ToKeeper) |
| 303 | { | 309 | { |
| 304 | prelude->idfunc( L, eDO_metatable); // DPC proxy metatable deepversion | 310 | (void) prelude->idfunc( L, eDO_metatable); // DPC proxy metatable deepversion |
| 305 | if( lua_gettop( L) - oldtop != 1 || !lua_istable( L, -2) || !lua_isstring( L, -1)) | 311 | if( lua_gettop( L) - oldtop != 1 || !lua_istable( L, -2) || !lua_isstring( L, -1)) |
| 306 | { | 312 | { |
| 307 | lua_settop( L, oldtop); // DPC proxy X | 313 | lua_settop( L, oldtop); // DPC proxy X |
| @@ -350,7 +356,7 @@ char const* push_deep_proxy( struct s_Universe* U, lua_State* L, DEEP_PRELUDE* p | |||
| 350 | return "Bad idfunc(eOP_module): should not push anything"; | 356 | return "Bad idfunc(eOP_module): should not push anything"; |
| 351 | } | 357 | } |
| 352 | } | 358 | } |
| 353 | if( modname) // we actually got a module name | 359 | if( NULL != modname) // we actually got a module name |
| 354 | { | 360 | { |
| 355 | // somehow, L.registry._LOADED can exist without having registered the 'package' library. | 361 | // somehow, L.registry._LOADED can exist without having registered the 'package' library. |
| 356 | lua_getglobal( L, "require"); // DPC proxy metatable require() | 362 | lua_getglobal( L, "require"); // DPC proxy metatable require() |
| @@ -413,7 +419,6 @@ char const* push_deep_proxy( struct s_Universe* U, lua_State* L, DEEP_PRELUDE* p | |||
| 413 | return NULL; | 419 | return NULL; |
| 414 | } | 420 | } |
| 415 | 421 | ||
| 416 | |||
| 417 | /* | 422 | /* |
| 418 | * Create a deep userdata | 423 | * Create a deep userdata |
| 419 | * | 424 | * |
| @@ -439,7 +444,7 @@ char const* push_deep_proxy( struct s_Universe* U, lua_State* L, DEEP_PRELUDE* p | |||
| 439 | int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc) | 444 | int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc) |
| 440 | { | 445 | { |
| 441 | char const* errmsg; | 446 | char const* errmsg; |
| 442 | DEEP_PRELUDE* prelude = DEEP_MALLOC( sizeof(DEEP_PRELUDE)); | 447 | struct DEEP_PRELUDE* prelude = DEEP_MALLOC( sizeof(struct DEEP_PRELUDE)); |
| 443 | if( prelude == NULL) | 448 | if( prelude == NULL) |
| 444 | { | 449 | { |
| 445 | return luaL_error( L, "couldn't not allocate deep prelude: out of memory"); | 450 | return luaL_error( L, "couldn't not allocate deep prelude: out of memory"); |
| @@ -463,7 +468,7 @@ int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc) | |||
| 463 | luaL_error( L, "Bad idfunc(eDO_new): should not push anything on the stack"); | 468 | luaL_error( L, "Bad idfunc(eDO_new): should not push anything on the stack"); |
| 464 | } | 469 | } |
| 465 | } | 470 | } |
| 466 | errmsg = push_deep_proxy( get_universe( L), L, prelude, eLM_LaneBody); // proxy | 471 | errmsg = push_deep_proxy( universe_get( L), L, prelude, eLM_LaneBody); // proxy |
| 467 | if( errmsg != NULL) | 472 | if( errmsg != NULL) |
| 468 | { | 473 | { |
| 469 | luaL_error( L, errmsg); | 474 | luaL_error( L, errmsg); |
| @@ -481,7 +486,7 @@ int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc) | |||
| 481 | */ | 486 | */ |
| 482 | void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index) | 487 | void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index) |
| 483 | { | 488 | { |
| 484 | DEEP_PRELUDE** proxy; | 489 | struct DEEP_PRELUDE** proxy; |
| 485 | 490 | ||
| 486 | STACK_CHECK( L); | 491 | STACK_CHECK( L); |
| 487 | // ensure it is actually a deep userdata | 492 | // ensure it is actually a deep userdata |
| @@ -490,7 +495,7 @@ void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index) | |||
| 490 | return NULL; // no metatable, or wrong kind | 495 | return NULL; // no metatable, or wrong kind |
| 491 | } | 496 | } |
| 492 | 497 | ||
| 493 | proxy = (DEEP_PRELUDE**) lua_touserdata( L, index); | 498 | proxy = (struct DEEP_PRELUDE**) lua_touserdata( L, index); |
| 494 | STACK_END( L, 0); | 499 | STACK_END( L, 0); |
| 495 | 500 | ||
| 496 | return (*proxy)->deep; | 501 | return (*proxy)->deep; |
| @@ -513,7 +518,7 @@ luaG_IdFunction copydeep( struct s_Universe* U, lua_State* L, lua_State* L2, int | |||
| 513 | return NULL; // not a deep userdata | 518 | return NULL; // not a deep userdata |
| 514 | } | 519 | } |
| 515 | 520 | ||
| 516 | errmsg = push_deep_proxy( U, L2, *(DEEP_PRELUDE**) lua_touserdata( L, index), mode_); | 521 | errmsg = push_deep_proxy( U, L2, *(struct DEEP_PRELUDE**) lua_touserdata( L, index), mode_); |
| 517 | if( errmsg != NULL) | 522 | if( errmsg != NULL) |
| 518 | { | 523 | { |
| 519 | // raise the error in the proper state (not the keeper) | 524 | // raise the error in the proper state (not the keeper) |
diff --git a/src/keeper.c b/src/keeper.c index 9a7c804..dbf083f 100644 --- a/src/keeper.c +++ b/src/keeper.c | |||
| @@ -46,6 +46,7 @@ | |||
| 46 | #include "threading.h" | 46 | #include "threading.h" |
| 47 | #include "compat.h" | 47 | #include "compat.h" |
| 48 | #include "tools.h" | 48 | #include "tools.h" |
| 49 | #include "universe.h" | ||
| 49 | #include "keeper.h" | 50 | #include "keeper.h" |
| 50 | 51 | ||
| 51 | //################################################################################### | 52 | //################################################################################### |
| @@ -664,14 +665,11 @@ void init_keepers( struct s_Universe* U, lua_State* L) | |||
| 664 | // from there, GC can collect a linda, which would acquire the keeper again, and deadlock the thread. | 665 | // from there, GC can collect a linda, which would acquire the keeper again, and deadlock the thread. |
| 665 | // therefore, we need a recursive mutex. | 666 | // therefore, we need a recursive mutex. |
| 666 | MUTEX_RECURSIVE_INIT( &U->keepers->keeper_array[i].keeper_cs); | 667 | MUTEX_RECURSIVE_INIT( &U->keepers->keeper_array[i].keeper_cs); |
| 667 | STACK_CHECK( K); | ||
| 668 | 668 | ||
| 669 | // copy the universe pointer in the keeper itself | 669 | // copy the universe pointer in the keeper itself |
| 670 | lua_pushlightuserdata( K, UNIVERSE_REGKEY); | 670 | universe_store( K, U); |
| 671 | lua_pushlightuserdata( K, U); | ||
| 672 | lua_rawset( K, LUA_REGISTRYINDEX); | ||
| 673 | STACK_MID( K, 0); | ||
| 674 | 671 | ||
| 672 | STACK_CHECK( K); | ||
| 675 | // make sure 'package' is initialized in keeper states, so that we have require() | 673 | // make sure 'package' is initialized in keeper states, so that we have require() |
| 676 | // this because this is needed when transferring deep userdata object | 674 | // this because this is needed when transferring deep userdata object |
| 677 | luaL_requiref( K, "package", luaopen_package, 1); // package | 675 | luaL_requiref( K, "package", luaopen_package, 1); // package |
diff --git a/src/lanes.c b/src/lanes.c index 78fece8..3268c8b 100644 --- a/src/lanes.c +++ b/src/lanes.c | |||
| @@ -52,7 +52,7 @@ | |||
| 52 | * ... | 52 | * ... |
| 53 | */ | 53 | */ |
| 54 | 54 | ||
| 55 | char const* VERSION = "3.11"; | 55 | char const* VERSION = "3.12"; |
| 56 | 56 | ||
| 57 | /* | 57 | /* |
| 58 | =============================================================================== | 58 | =============================================================================== |
| @@ -89,6 +89,7 @@ THE SOFTWARE. | |||
| 89 | #include "threading.h" | 89 | #include "threading.h" |
| 90 | #include "compat.h" | 90 | #include "compat.h" |
| 91 | #include "tools.h" | 91 | #include "tools.h" |
| 92 | #include "universe.h" | ||
| 92 | #include "keeper.h" | 93 | #include "keeper.h" |
| 93 | #include "lanes.h" | 94 | #include "lanes.h" |
| 94 | 95 | ||
| @@ -1070,7 +1071,7 @@ LUAG_FUNC( linda_concat) | |||
| 1070 | LUAG_FUNC( linda_dump) | 1071 | LUAG_FUNC( linda_dump) |
| 1071 | { | 1072 | { |
| 1072 | struct s_Linda* linda = lua_toLinda( L, 1); | 1073 | struct s_Linda* linda = lua_toLinda( L, 1); |
| 1073 | ASSERT_L( linda->U == get_universe( L)); | 1074 | ASSERT_L( linda->U == universe_get( L)); |
| 1074 | return keeper_push_linda_storage( linda->U, L, linda, LINDA_KEEPER_HASHSEED( linda)); | 1075 | return keeper_push_linda_storage( linda->U, L, linda, LINDA_KEEPER_HASHSEED( linda)); |
| 1075 | } | 1076 | } |
| 1076 | 1077 | ||
| @@ -1082,7 +1083,7 @@ LUAG_FUNC( linda_towatch) | |||
| 1082 | { | 1083 | { |
| 1083 | struct s_Linda* linda = lua_toLinda( L, 1); | 1084 | struct s_Linda* linda = lua_toLinda( L, 1); |
| 1084 | int pushed; | 1085 | int pushed; |
| 1085 | ASSERT_L( linda->U == get_universe( L)); | 1086 | ASSERT_L( linda->U == universe_get( L)); |
| 1086 | pushed = keeper_push_linda_storage( linda->U, L, linda, LINDA_KEEPER_HASHSEED( linda)); | 1087 | pushed = keeper_push_linda_storage( linda->U, L, linda, LINDA_KEEPER_HASHSEED( linda)); |
| 1087 | if( pushed == 0) | 1088 | if( pushed == 0) |
| 1088 | { | 1089 | { |
| @@ -1159,7 +1160,7 @@ static void* linda_id( lua_State* L, enum eDeepOp op_) | |||
| 1159 | { | 1160 | { |
| 1160 | SIGNAL_INIT( &s->read_happened); | 1161 | SIGNAL_INIT( &s->read_happened); |
| 1161 | SIGNAL_INIT( &s->write_happened); | 1162 | SIGNAL_INIT( &s->write_happened); |
| 1162 | s->U = get_universe( L); | 1163 | s->U = universe_get( L); |
| 1163 | s->simulate_cancel = CANCEL_NONE; | 1164 | s->simulate_cancel = CANCEL_NONE; |
| 1164 | s->group = linda_group << KEEPER_MAGIC_SHIFT; | 1165 | s->group = linda_group << KEEPER_MAGIC_SHIFT; |
| 1165 | s->name[0] = 0; | 1166 | s->name[0] = 0; |
| @@ -1718,7 +1719,7 @@ static int selfdestruct_gc( lua_State* L) | |||
| 1718 | lua_settop( L, 0); | 1719 | lua_settop( L, 0); |
| 1719 | // no need to mutex-protect this as all threads in the universe are gone at that point | 1720 | // no need to mutex-protect this as all threads in the universe are gone at that point |
| 1720 | -- U->timer_deep->refcount; // should be 0 now | 1721 | -- U->timer_deep->refcount; // should be 0 now |
| 1721 | free_deep_prelude( L, (DEEP_PRELUDE*) U->timer_deep); | 1722 | free_deep_prelude( L, (struct DEEP_PRELUDE*) U->timer_deep); |
| 1722 | U->timer_deep = NULL; | 1723 | U->timer_deep = NULL; |
| 1723 | 1724 | ||
| 1724 | close_keepers( U, L); | 1725 | close_keepers( U, L); |
| @@ -2045,7 +2046,7 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void* vs) | |||
| 2045 | lua_State* L = s->L; | 2046 | lua_State* L = s->L; |
| 2046 | // Called with the lane function and arguments on the stack | 2047 | // Called with the lane function and arguments on the stack |
| 2047 | int const nargs = lua_gettop( L) - 1; | 2048 | int const nargs = lua_gettop( L) - 1; |
| 2048 | DEBUGSPEW_CODE( struct s_Universe* U = get_universe( L)); | 2049 | DEBUGSPEW_CODE( struct s_Universe* U = universe_get( L)); |
| 2049 | THREAD_MAKE_ASYNCH_CANCELLABLE(); | 2050 | THREAD_MAKE_ASYNCH_CANCELLABLE(); |
| 2050 | THREAD_CLEANUP_PUSH( thread_cleanup_handler, s); | 2051 | THREAD_CLEANUP_PUSH( thread_cleanup_handler, s); |
| 2051 | s->status = RUNNING; // PENDING -> RUNNING | 2052 | s->status = RUNNING; // PENDING -> RUNNING |
| @@ -2143,7 +2144,7 @@ LUAG_FUNC( require) | |||
| 2143 | { | 2144 | { |
| 2144 | char const* name = lua_tostring( L, 1); | 2145 | char const* name = lua_tostring( L, 1); |
| 2145 | int const nargs = lua_gettop( L); | 2146 | int const nargs = lua_gettop( L); |
| 2146 | DEBUGSPEW_CODE( struct s_Universe* U = get_universe( L)); | 2147 | DEBUGSPEW_CODE( struct s_Universe* U = universe_get( L)); |
| 2147 | STACK_CHECK( L); | 2148 | STACK_CHECK( L); |
| 2148 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.require %s BEGIN\n" INDENT_END, name)); | 2149 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.require %s BEGIN\n" INDENT_END, name)); |
| 2149 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); | 2150 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); |
| @@ -2169,7 +2170,7 @@ LUAG_FUNC( register) | |||
| 2169 | // ignore extra parameters, just in case | 2170 | // ignore extra parameters, just in case |
| 2170 | lua_settop( L, 2); | 2171 | lua_settop( L, 2); |
| 2171 | luaL_argcheck( L, (mod_type == LUA_TTABLE) || (mod_type == LUA_TFUNCTION), 2, "unexpected module type"); | 2172 | luaL_argcheck( L, (mod_type == LUA_TTABLE) || (mod_type == LUA_TFUNCTION), 2, "unexpected module type"); |
| 2172 | DEBUGSPEW_CODE( struct s_Universe* U = get_universe( L)); | 2173 | DEBUGSPEW_CODE( struct s_Universe* U = universe_get( L)); |
| 2173 | STACK_CHECK( L); // "name" mod_table | 2174 | STACK_CHECK( L); // "name" mod_table |
| 2174 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.register %s BEGIN\n" INDENT_END, name)); | 2175 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.register %s BEGIN\n" INDENT_END, name)); |
| 2175 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); | 2176 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); |
| @@ -2212,7 +2213,7 @@ LUAG_FUNC( lane_new) | |||
| 2212 | 2213 | ||
| 2213 | #define FIXED_ARGS 8 | 2214 | #define FIXED_ARGS 8 |
| 2214 | int const nargs = lua_gettop(L) - FIXED_ARGS; | 2215 | int const nargs = lua_gettop(L) - FIXED_ARGS; |
| 2215 | struct s_Universe* U = get_universe( L); | 2216 | struct s_Universe* U = universe_get( L); |
| 2216 | ASSERT_L( nargs >= 0); | 2217 | ASSERT_L( nargs >= 0); |
| 2217 | 2218 | ||
| 2218 | // public Lanes API accepts a generic range -3/+3 | 2219 | // public Lanes API accepts a generic range -3/+3 |
| @@ -2660,7 +2661,7 @@ LUAG_FUNC( thread_join) | |||
| 2660 | } | 2661 | } |
| 2661 | else | 2662 | else |
| 2662 | { | 2663 | { |
| 2663 | struct s_Universe* U = get_universe( L); | 2664 | struct s_Universe* U = universe_get( L); |
| 2664 | // debug_name is a pointer to string possibly interned in the lane's state, that no longer exists when the state is closed | 2665 | // debug_name is a pointer to string possibly interned in the lane's state, that no longer exists when the state is closed |
| 2665 | // so store it in the userdata uservalue at a key that can't possibly collide | 2666 | // so store it in the userdata uservalue at a key that can't possibly collide |
| 2666 | securize_debug_threadname( L, s); | 2667 | securize_debug_threadname( L, s); |
| @@ -2872,7 +2873,7 @@ LUAG_FUNC( thread_index) | |||
| 2872 | LUAG_FUNC( threads) | 2873 | LUAG_FUNC( threads) |
| 2873 | { | 2874 | { |
| 2874 | int const top = lua_gettop( L); | 2875 | int const top = lua_gettop( L); |
| 2875 | struct s_Universe* U = get_universe( L); | 2876 | struct s_Universe* U = universe_get( L); |
| 2876 | 2877 | ||
| 2877 | // List _all_ still running threads | 2878 | // List _all_ still running threads |
| 2878 | // | 2879 | // |
| @@ -3024,7 +3025,7 @@ static volatile long s_initCount = 0; | |||
| 3024 | // param 1: settings table | 3025 | // param 1: settings table |
| 3025 | LUAG_FUNC( configure) | 3026 | LUAG_FUNC( configure) |
| 3026 | { | 3027 | { |
| 3027 | struct s_Universe* U = get_universe( L); | 3028 | struct s_Universe* U = universe_get( L); |
| 3028 | bool_t const from_master_state = (U == NULL); | 3029 | bool_t const from_master_state = (U == NULL); |
| 3029 | char const* name = luaL_checkstring( L, lua_upvalueindex( 1)); | 3030 | char const* name = luaL_checkstring( L, lua_upvalueindex( 1)); |
| 3030 | _ASSERT_L( L, lua_type( L, 1) == LUA_TTABLE); | 3031 | _ASSERT_L( L, lua_type( L, 1) == LUA_TTABLE); |
| @@ -3093,16 +3094,14 @@ LUAG_FUNC( configure) | |||
| 3093 | // grab or create the universe | 3094 | // grab or create the universe |
| 3094 | if( U == NULL) | 3095 | if( U == NULL) |
| 3095 | { | 3096 | { |
| 3096 | lua_pushlightuserdata( L, UNIVERSE_REGKEY); // settings UNIVERSE_REGKEY | 3097 | U = universe_create( L); // settings universe |
| 3097 | U = (struct s_Universe*) lua_newuserdata( L, sizeof( struct s_Universe)); // settings UNIVERSE_REGKEY universe | ||
| 3098 | memset( U, 0, sizeof( struct s_Universe)); | ||
| 3099 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); | 3098 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); |
| 3100 | lua_newtable( L); // settings UNIVERSE_REGKEY universe mt | 3099 | lua_newtable( L); // settings universe mt |
| 3101 | lua_getfield( L, 1, "shutdown_timeout"); // settings UNIVERSE_REGKEY universe mt shutdown_timeout | 3100 | lua_getfield( L, 1, "shutdown_timeout"); // settings universe mt shutdown_timeout |
| 3102 | lua_pushcclosure( L, selfdestruct_gc, 1); // settings UNIVERSE_REGKEY universe mt selfdestruct_gc | 3101 | lua_pushcclosure( L, selfdestruct_gc, 1); // settings universe mt selfdestruct_gc |
| 3103 | lua_setfield( L, -2, "__gc"); // settings UNIVERSE_REGKEY universe mt | 3102 | lua_setfield( L, -2, "__gc"); // settings universe mt |
| 3104 | lua_setmetatable( L, -2); // settings UNIVERSE_REGKEY universe | 3103 | lua_setmetatable( L, -2); // settings universe |
| 3105 | lua_rawset( L, LUA_REGISTRYINDEX); // settings | 3104 | lua_pop( L, 1); // settings |
| 3106 | lua_getfield( L, 1, "verbose_errors"); // settings verbose_errors | 3105 | lua_getfield( L, 1, "verbose_errors"); // settings verbose_errors |
| 3107 | U->verboseErrors = lua_toboolean( L, -1); | 3106 | U->verboseErrors = lua_toboolean( L, -1); |
| 3108 | lua_pop( L, 1); // settings | 3107 | lua_pop( L, 1); // settings |
| @@ -3130,7 +3129,7 @@ LUAG_FUNC( configure) | |||
| 3130 | STACK_MID( L, 1); | 3129 | STACK_MID( L, 1); |
| 3131 | 3130 | ||
| 3132 | // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer | 3131 | // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer |
| 3133 | U->timer_deep = * (DEEP_PRELUDE**) lua_touserdata( L, -1); | 3132 | U->timer_deep = *(struct DEEP_PRELUDE**) lua_touserdata( L, -1); |
| 3134 | ASSERT_L( U->timer_deep && (U->timer_deep->refcount == 1) && U->timer_deep->deep && U->timer_deep->idfunc == linda_id); | 3133 | ASSERT_L( U->timer_deep && (U->timer_deep->refcount == 1) && U->timer_deep->deep && U->timer_deep->idfunc == linda_id); |
| 3135 | // increment refcount that this linda remains alive as long as the universe is. | 3134 | // increment refcount that this linda remains alive as long as the universe is. |
| 3136 | ++ U->timer_deep->refcount; | 3135 | ++ U->timer_deep->refcount; |
| @@ -3160,7 +3159,7 @@ LUAG_FUNC( configure) | |||
| 3160 | 3159 | ||
| 3161 | { | 3160 | { |
| 3162 | char const* errmsg; | 3161 | char const* errmsg; |
| 3163 | errmsg = push_deep_proxy( U, L, (DEEP_PRELUDE*) U->timer_deep, eLM_LaneBody); // settings M timer_deep | 3162 | errmsg = push_deep_proxy( U, L, (struct DEEP_PRELUDE*) U->timer_deep, eLM_LaneBody);// settings M timer_deep |
| 3164 | if( errmsg != NULL) | 3163 | if( errmsg != NULL) |
| 3165 | { | 3164 | { |
| 3166 | return luaL_error( L, errmsg); | 3165 | return luaL_error( L, errmsg); |
diff --git a/src/macros_and_utils.h b/src/macros_and_utils.h new file mode 100644 index 0000000..d584c2b --- /dev/null +++ b/src/macros_and_utils.h | |||
| @@ -0,0 +1,71 @@ | |||
| 1 | /* | ||
| 2 | * MACROS_AND_UTILS.H | ||
| 3 | */ | ||
| 4 | #ifndef MACROS_AND_UTILS_H | ||
| 5 | #define MACROS_AND_UTILS_H | ||
| 6 | |||
| 7 | #include "lua.h" | ||
| 8 | |||
| 9 | // M$ compiler doesn't support 'inline' keyword in C files... | ||
| 10 | #if defined( _MSC_VER) | ||
| 11 | #define inline __inline | ||
| 12 | #endif | ||
| 13 | |||
| 14 | // For some reason, LuaJIT 64bits doesn't support lua_newstate() | ||
| 15 | #if defined(LUA_JITLIBNAME) && (defined(__x86_64__) || defined(_M_X64)) | ||
| 16 | //#pragma message( "LuaJIT 64 bits detected: don't propagate allocf") | ||
| 17 | #define PROPAGATE_ALLOCF 0 | ||
| 18 | #else // LuaJIT x64 | ||
| 19 | //#pragma message( "PUC-Lua detected: propagate allocf") | ||
| 20 | #define PROPAGATE_ALLOCF 1 | ||
| 21 | #endif // LuaJIT x64 | ||
| 22 | #if PROPAGATE_ALLOCF | ||
| 23 | #define PROPAGATE_ALLOCF_PREP( L) void* allocUD; lua_Alloc allocF = lua_getallocf( L, &allocUD) | ||
| 24 | #define PROPAGATE_ALLOCF_ALLOC() lua_newstate( allocF, allocUD) | ||
| 25 | #else // PROPAGATE_ALLOCF | ||
| 26 | #define PROPAGATE_ALLOCF_PREP( L) | ||
| 27 | #define PROPAGATE_ALLOCF_ALLOC() luaL_newstate() | ||
| 28 | #endif // PROPAGATE_ALLOCF | ||
| 29 | |||
| 30 | #define USE_DEBUG_SPEW 0 | ||
| 31 | #if USE_DEBUG_SPEW | ||
| 32 | extern char const* debugspew_indent; | ||
| 33 | #define INDENT_BEGIN "%.*s " | ||
| 34 | #define INDENT_END , (U ? U->debugspew_indent_depth : 0), debugspew_indent | ||
| 35 | #define DEBUGSPEW_CODE(_code) _code | ||
| 36 | #else // USE_DEBUG_SPEW | ||
| 37 | #define DEBUGSPEW_CODE(_code) | ||
| 38 | #endif // USE_DEBUG_SPEW | ||
| 39 | |||
| 40 | #ifdef NDEBUG | ||
| 41 | |||
| 42 | #define _ASSERT_L(lua,c) /*nothing*/ | ||
| 43 | #define STACK_CHECK(L) /*nothing*/ | ||
| 44 | #define STACK_MID(L,c) /*nothing*/ | ||
| 45 | #define STACK_END(L,c) /*nothing*/ | ||
| 46 | #define STACK_DUMP(L) /*nothing*/ | ||
| 47 | |||
| 48 | #else // NDEBUG | ||
| 49 | |||
| 50 | #define _ASSERT_L( L, cond_) if( (cond_) == 0) { (void) luaL_error( L, "ASSERT failed: %s:%d '%s'", __FILE__, __LINE__, #cond_);} | ||
| 51 | |||
| 52 | #define STACK_CHECK(L) { int const _oldtop_##L = lua_gettop( L) | ||
| 53 | #define STACK_MID(L,change) \ | ||
| 54 | do \ | ||
| 55 | { \ | ||
| 56 | int a = lua_gettop( L) - _oldtop_##L; \ | ||
| 57 | int b = (change); \ | ||
| 58 | if( a != b) \ | ||
| 59 | luaL_error( L, "STACK ASSERT failed (%d not %d): %s:%d", a, b, __FILE__, __LINE__ ); \ | ||
| 60 | } while( 0) | ||
| 61 | #define STACK_END(L,change) STACK_MID(L,change); } | ||
| 62 | |||
| 63 | #define STACK_DUMP( L) luaG_dump( L) | ||
| 64 | |||
| 65 | #endif // NDEBUG | ||
| 66 | |||
| 67 | #define ASSERT_L(c) _ASSERT_L(L,c) | ||
| 68 | |||
| 69 | #define STACK_GROW( L, n) do { if (!lua_checkstack(L,(int)(n))) luaL_error( L, "Cannot grow stack!" ); } while( 0) | ||
| 70 | |||
| 71 | #endif // MACROS_AND_UTILS_H | ||
diff --git a/src/tools.c b/src/tools.c index c2491ba..f935c26 100644 --- a/src/tools.c +++ b/src/tools.c | |||
| @@ -32,6 +32,7 @@ THE SOFTWARE. | |||
| 32 | */ | 32 | */ |
| 33 | 33 | ||
| 34 | #include "compat.h" | 34 | #include "compat.h" |
| 35 | #include "universe.h" | ||
| 35 | #include "tools.h" | 36 | #include "tools.h" |
| 36 | #include "keeper.h" | 37 | #include "keeper.h" |
| 37 | #include "lanes.h" | 38 | #include "lanes.h" |
| @@ -48,21 +49,6 @@ THE SOFTWARE. | |||
| 48 | extern luaG_IdFunction copydeep( struct s_Universe* U, lua_State* L, lua_State* L2, int index, enum eLookupMode mode_); | 49 | extern luaG_IdFunction copydeep( struct s_Universe* U, lua_State* L, lua_State* L2, int index, enum eLookupMode mode_); |
| 49 | extern void push_registry_subtable( lua_State* L, void* key_); | 50 | extern void push_registry_subtable( lua_State* L, void* key_); |
| 50 | 51 | ||
| 51 | void* const UNIVERSE_REGKEY = (void*) luaopen_lanes_core; | ||
| 52 | |||
| 53 | /* | ||
| 54 | * ############################################################################################### | ||
| 55 | * ########################################### ASSERT ############################################ | ||
| 56 | * ############################################################################################### | ||
| 57 | */ | ||
| 58 | void ASSERT_IMPL( lua_State* L, bool_t cond_, char const* file_, int const line_, char const* text_) | ||
| 59 | { | ||
| 60 | if ( !cond_) | ||
| 61 | { | ||
| 62 | (void) luaL_error( L, "ASSERT failed: %s:%d '%s'", file_, line_, text_); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | char const* const CONFIG_REGKEY = "ee932492-a654-4506-9da8-f16540bdb5d4"; | 52 | char const* const CONFIG_REGKEY = "ee932492-a654-4506-9da8-f16540bdb5d4"; |
| 67 | char const* const LOOKUP_REGKEY = "ddea37aa-50c7-4d3f-8e0b-fb7a9d62bac5"; | 53 | char const* const LOOKUP_REGKEY = "ddea37aa-50c7-4d3f-8e0b-fb7a9d62bac5"; |
| 68 | 54 | ||
| @@ -150,19 +136,7 @@ void initialize_on_state_create( struct s_Universe* U, lua_State* L) | |||
| 150 | STACK_END( L, 0); | 136 | STACK_END( L, 0); |
| 151 | } | 137 | } |
| 152 | 138 | ||
| 153 | 139 | // ################################################################################################ | |
| 154 | struct s_Universe* get_universe( lua_State* L) | ||
| 155 | { | ||
| 156 | struct s_Universe* universe; | ||
| 157 | STACK_GROW( L, 2); | ||
| 158 | STACK_CHECK( L); | ||
| 159 | lua_pushlightuserdata( L, UNIVERSE_REGKEY); | ||
| 160 | lua_rawget( L, LUA_REGISTRYINDEX); | ||
| 161 | universe = lua_touserdata( L, -1); // NULL if nil | ||
| 162 | lua_pop( L, 1); | ||
| 163 | STACK_END( L, 0); | ||
| 164 | return universe; | ||
| 165 | } | ||
| 166 | 140 | ||
| 167 | // just like lua_xmove, args are (from, to) | 141 | // just like lua_xmove, args are (from, to) |
| 168 | void luaG_copy_one_time_settings( struct s_Universe* U, lua_State* L, lua_State* L2) | 142 | void luaG_copy_one_time_settings( struct s_Universe* U, lua_State* L, lua_State* L2) |
| @@ -367,7 +341,7 @@ static void update_lookup_entry( lua_State* L, int _ctx_base, int _depth) | |||
| 367 | size_t prevNameLength, newNameLength; | 341 | size_t prevNameLength, newNameLength; |
| 368 | char const* prevName; | 342 | char const* prevName; |
| 369 | DEBUGSPEW_CODE( char const *newName); | 343 | DEBUGSPEW_CODE( char const *newName); |
| 370 | DEBUGSPEW_CODE( struct s_Universe* U = get_universe( L)); | 344 | DEBUGSPEW_CODE( struct s_Universe* U = universe_get( L)); |
| 371 | 345 | ||
| 372 | STACK_CHECK( L); | 346 | STACK_CHECK( L); |
| 373 | // first, raise an error if the function is already known | 347 | // first, raise an error if the function is already known |
| @@ -438,7 +412,7 @@ static void populate_func_lookup_table_recur( lua_State* L, int _ctx_base, int _ | |||
| 438 | int const cache = _ctx_base + 2; | 412 | int const cache = _ctx_base + 2; |
| 439 | // 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) |
| 440 | int const breadth_first_cache = lua_gettop( L) + 1; | 414 | int const breadth_first_cache = lua_gettop( L) + 1; |
| 441 | DEBUGSPEW_CODE( struct s_Universe* U = get_universe( L)); | 415 | DEBUGSPEW_CODE( struct s_Universe* U = universe_get( L)); |
| 442 | 416 | ||
| 443 | STACK_GROW( L, 6); | 417 | STACK_GROW( L, 6); |
| 444 | // 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) |
| @@ -556,7 +530,7 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* name_) | |||
| 556 | int const ctx_base = lua_gettop( L) + 1; | 530 | int const ctx_base = lua_gettop( L) + 1; |
| 557 | int const in_base = lua_absindex( L, _i); | 531 | int const in_base = lua_absindex( L, _i); |
| 558 | int start_depth = 0; | 532 | int start_depth = 0; |
| 559 | DEBUGSPEW_CODE( struct s_Universe* U = get_universe( L)); | 533 | DEBUGSPEW_CODE( struct s_Universe* U = universe_get( L)); |
| 560 | 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")); |
| 561 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); | 535 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); |
| 562 | STACK_GROW( L, 3); | 536 | STACK_GROW( L, 3); |
| @@ -670,14 +644,12 @@ lua_State* luaG_newstate( struct s_Universe* U, lua_State* from_, char const* li | |||
| 670 | } | 644 | } |
| 671 | 645 | ||
| 672 | STACK_GROW( L, 2); | 646 | STACK_GROW( L, 2); |
| 673 | STACK_CHECK( L); | ||
| 674 | 647 | ||
| 675 | // copy the universe as a light userdata (only the master state holds the full userdata) | 648 | // copy the universe as a light userdata (only the master state holds the full userdata) |
| 676 | // that way, if Lanes is required in this new state, we'll know we are part of this universe | 649 | // that way, if Lanes is required in this new state, we'll know we are part of this universe |
| 677 | lua_pushlightuserdata( L, UNIVERSE_REGKEY); | 650 | universe_store( L, U); |
| 678 | lua_pushlightuserdata( L, U); | 651 | |
| 679 | lua_rawset( L, LUA_REGISTRYINDEX); | 652 | STACK_CHECK( L); |
| 680 | STACK_MID( L, 0); | ||
| 681 | 653 | ||
| 682 | // we'll need this every time we transfer some C function from/to this state | 654 | // we'll need this every time we transfer some C function from/to this state |
| 683 | lua_newtable( L); | 655 | lua_newtable( L); |
| @@ -858,7 +830,7 @@ static int table_lookup_sentinel( lua_State* L) | |||
| 858 | */ | 830 | */ |
| 859 | 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, enum eLookupMode mode_, char const* upName_, size_t* len_) |
| 860 | { | 832 | { |
| 861 | DEBUGSPEW_CODE( struct s_Universe* const U = get_universe( L)); | 833 | DEBUGSPEW_CODE( struct s_Universe* const U = universe_get( L)); |
| 862 | char const* fqn; | 834 | char const* fqn; |
| 863 | ASSERT_L( lua_isfunction( L, i) || lua_istable( L, i)); // ... v ... | 835 | ASSERT_L( lua_isfunction( L, i) || lua_istable( L, i)); // ... v ... |
| 864 | STACK_CHECK( L); | 836 | STACK_CHECK( L); |
| @@ -1950,7 +1922,7 @@ int luaG_new_require( lua_State* L) | |||
| 1950 | { | 1922 | { |
| 1951 | int rc, i; | 1923 | int rc, i; |
| 1952 | int args = lua_gettop( L); | 1924 | int args = lua_gettop( L); |
| 1953 | struct s_Universe* U = get_universe( L); | 1925 | struct s_Universe* U = universe_get( L); |
| 1954 | //char const* modname = luaL_checkstring( L, 1); | 1926 | //char const* modname = luaL_checkstring( L, 1); |
| 1955 | 1927 | ||
| 1956 | STACK_GROW( L, args + 1); | 1928 | STACK_GROW( L, args + 1); |
diff --git a/src/tools.h b/src/tools.h index b869a16..9155747 100644 --- a/src/tools.h +++ b/src/tools.h | |||
| @@ -11,131 +11,21 @@ | |||
| 11 | 11 | ||
| 12 | #include <assert.h> | 12 | #include <assert.h> |
| 13 | 13 | ||
| 14 | // M$ compiler doesn't support 'inline' keyword in C files... | 14 | #include "macros_and_utils.h" |
| 15 | #if defined( _MSC_VER) | ||
| 16 | #define inline __inline | ||
| 17 | #endif | ||
| 18 | |||
| 19 | // For some reason, LuaJIT 64bits doesn't support lua_newstate() | ||
| 20 | #if defined(LUA_JITLIBNAME) && (defined(__x86_64__) || defined(_M_X64)) | ||
| 21 | //#pragma message( "LuaJIT 64 bits detected: don't propagate allocf") | ||
| 22 | #define PROPAGATE_ALLOCF 0 | ||
| 23 | #else // LuaJIT x64 | ||
| 24 | //#pragma message( "PUC-Lua detected: propagate allocf") | ||
| 25 | #define PROPAGATE_ALLOCF 1 | ||
| 26 | #endif // LuaJIT x64 | ||
| 27 | #if PROPAGATE_ALLOCF | ||
| 28 | #define PROPAGATE_ALLOCF_PREP( L) void* allocUD; lua_Alloc allocF = lua_getallocf( L, &allocUD) | ||
| 29 | #define PROPAGATE_ALLOCF_ALLOC() lua_newstate( allocF, allocUD) | ||
| 30 | #else // PROPAGATE_ALLOCF | ||
| 31 | #define PROPAGATE_ALLOCF_PREP( L) | ||
| 32 | #define PROPAGATE_ALLOCF_ALLOC() luaL_newstate() | ||
| 33 | #endif // PROPAGATE_ALLOCF | ||
| 34 | |||
| 35 | #define USE_DEBUG_SPEW 0 | ||
| 36 | #if USE_DEBUG_SPEW | ||
| 37 | extern char const* debugspew_indent; | ||
| 38 | #define INDENT_BEGIN "%.*s " | ||
| 39 | #define INDENT_END , (U ? U->debugspew_indent_depth : 0), debugspew_indent | ||
| 40 | #define DEBUGSPEW_CODE(_code) _code | ||
| 41 | #else // USE_DEBUG_SPEW | ||
| 42 | #define DEBUGSPEW_CODE(_code) | ||
| 43 | #endif // USE_DEBUG_SPEW | ||
| 44 | |||
| 45 | // ################################################################################################ | ||
| 46 | |||
| 47 | /* | ||
| 48 | * Do we want to activate full lane tracking feature? (EXPERIMENTAL) | ||
| 49 | */ | ||
| 50 | #define HAVE_LANE_TRACKING 1 | ||
| 51 | 15 | ||
| 52 | // ################################################################################################ | 16 | // ################################################################################################ |
| 53 | 17 | ||
| 54 | // this is pointed to by full userdata proxies, and allocated with malloc() to survive any lua_State lifetime | 18 | // this is pointed to by full userdata proxies, and allocated with malloc() to survive any lua_State lifetime |
| 55 | typedef struct | 19 | struct DEEP_PRELUDE |
| 56 | { | 20 | { |
| 57 | volatile int refcount; | 21 | volatile int refcount; |
| 58 | void* deep; | 22 | void* deep; |
| 59 | // when stored in a keeper state, the full userdata doesn't have a metatable, so we need direct access to the idfunc | 23 | // when stored in a keeper state, the full userdata doesn't have a metatable, so we need direct access to the idfunc |
| 60 | luaG_IdFunction idfunc; | 24 | luaG_IdFunction idfunc; |
| 61 | } DEEP_PRELUDE; | ||
| 62 | |||
| 63 | // ################################################################################################ | ||
| 64 | |||
| 65 | // everything regarding the a Lanes universe is stored in that global structure | ||
| 66 | // held as a full userdata in the master Lua state that required it for the first time | ||
| 67 | // don't forget to initialize all members in LG_configure() | ||
| 68 | struct s_Universe | ||
| 69 | { | ||
| 70 | // for verbose errors | ||
| 71 | bool_t verboseErrors; | ||
| 72 | |||
| 73 | lua_CFunction on_state_create_func; | ||
| 74 | |||
| 75 | struct s_Keepers* keepers; | ||
| 76 | |||
| 77 | // Initialized by 'init_once_LOCKED()': the deep userdata Linda object | ||
| 78 | // used for timers (each lane will get a proxy to this) | ||
| 79 | volatile DEEP_PRELUDE* timer_deep; // = NULL | ||
| 80 | |||
| 81 | #if HAVE_LANE_TRACKING | ||
| 82 | MUTEX_T tracking_cs; | ||
| 83 | struct s_lane* volatile tracking_first; // will change to TRACKING_END if we want to activate tracking | ||
| 84 | #endif // HAVE_LANE_TRACKING | ||
| 85 | |||
| 86 | MUTEX_T selfdestruct_cs; | ||
| 87 | |||
| 88 | // require() serialization | ||
| 89 | MUTEX_T require_cs; | ||
| 90 | |||
| 91 | // Lock for reference counter inc/dec locks (to be initialized by outside code) TODO: get rid of this and use atomics instead! | ||
| 92 | MUTEX_T deep_lock; | ||
| 93 | MUTEX_T mtid_lock; | ||
| 94 | |||
| 95 | int last_mt_id; | ||
| 96 | |||
| 97 | #if USE_DEBUG_SPEW | ||
| 98 | int debugspew_indent_depth; | ||
| 99 | #endif // USE_DEBUG_SPEW | ||
| 100 | |||
| 101 | struct s_lane* volatile selfdestruct_first; | ||
| 102 | // After a lane has removed itself from the chain, it still performs some processing. | ||
| 103 | // The terminal desinit sequence should wait for all such processing to terminate before force-killing threads | ||
| 104 | int volatile selfdestructing_count; | ||
| 105 | }; | 25 | }; |
| 106 | 26 | ||
| 107 | struct s_Universe* get_universe( lua_State* L); | ||
| 108 | extern void* const UNIVERSE_REGKEY; | ||
| 109 | |||
| 110 | // ################################################################################################ | 27 | // ################################################################################################ |
| 111 | 28 | ||
| 112 | #ifdef NDEBUG | ||
| 113 | #define _ASSERT_L(lua,c) /*nothing*/ | ||
| 114 | #define STACK_CHECK(L) /*nothing*/ | ||
| 115 | #define STACK_MID(L,c) /*nothing*/ | ||
| 116 | #define STACK_END(L,c) /*nothing*/ | ||
| 117 | #define STACK_DUMP(L) /*nothing*/ | ||
| 118 | #else | ||
| 119 | void ASSERT_IMPL( lua_State* L, bool_t cond_, char const* file_, int const line_, char const* text_); | ||
| 120 | #define _ASSERT_L(lua,c) ASSERT_IMPL( lua, (c) != 0, __FILE__, __LINE__, #c) | ||
| 121 | // | ||
| 122 | #define STACK_CHECK(L) { int const _oldtop_##L = lua_gettop( L) | ||
| 123 | #define STACK_MID(L,change) \ | ||
| 124 | do \ | ||
| 125 | { \ | ||
| 126 | int a = lua_gettop( L) - _oldtop_##L; \ | ||
| 127 | int b = (change); \ | ||
| 128 | if( a != b) \ | ||
| 129 | luaL_error( L, "STACK ASSERT failed (%d not %d): %s:%d", a, b, __FILE__, __LINE__ ); \ | ||
| 130 | } while( 0) | ||
| 131 | #define STACK_END(L,change) STACK_MID(L,change); } | ||
| 132 | |||
| 133 | #define STACK_DUMP( L) luaG_dump( L) | ||
| 134 | #endif | ||
| 135 | #define ASSERT_L(c) _ASSERT_L(L,c) | ||
| 136 | |||
| 137 | #define STACK_GROW( L, n) do { if (!lua_checkstack(L,(int)(n))) luaL_error( L, "Cannot grow stack!" ); } while( 0) | ||
| 138 | |||
| 139 | #define LUAG_FUNC( func_name ) static int LG_##func_name( lua_State* L) | 29 | #define LUAG_FUNC( func_name ) static int LG_##func_name( lua_State* L) |
| 140 | 30 | ||
| 141 | #define luaG_optunsigned(L,i,d) ((uint_t) luaL_optinteger(L,i,d)) | 31 | #define luaG_optunsigned(L,i,d) ((uint_t) luaL_optinteger(L,i,d)) |
| @@ -155,8 +45,8 @@ enum eLookupMode | |||
| 155 | eLM_FromKeeper // send a function from a keeper state to a lane | 45 | eLM_FromKeeper // send a function from a keeper state to a lane |
| 156 | }; | 46 | }; |
| 157 | 47 | ||
| 158 | char const* push_deep_proxy( struct s_Universe* U, lua_State* L, DEEP_PRELUDE* prelude, enum eLookupMode mode_); | 48 | char const* push_deep_proxy( struct s_Universe* U, lua_State* L, struct DEEP_PRELUDE* prelude, enum eLookupMode mode_); |
| 159 | void free_deep_prelude( lua_State* L, DEEP_PRELUDE* prelude_); | 49 | void free_deep_prelude( lua_State* L, struct DEEP_PRELUDE* prelude_); |
| 160 | 50 | ||
| 161 | int luaG_inter_copy_package( struct s_Universe* U, lua_State* L, lua_State* L2, int package_idx_, enum eLookupMode mode_); | 51 | int luaG_inter_copy_package( struct s_Universe* U, lua_State* L, lua_State* L2, int package_idx_, enum eLookupMode mode_); |
| 162 | 52 | ||
diff --git a/src/universe.c b/src/universe.c new file mode 100644 index 0000000..ba78396 --- /dev/null +++ b/src/universe.c | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | /* | ||
| 2 | * UNIVERSE.C Copyright (c) 2017, Benoit Germain | ||
| 3 | */ | ||
| 4 | |||
| 5 | /* | ||
| 6 | =============================================================================== | ||
| 7 | |||
| 8 | Copyright (C) 2017 Benoit Germain <bnt.germain@gmail.com> | ||
| 9 | |||
| 10 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 11 | of this software and associated documentation files (the "Software"), to deal | ||
| 12 | in the Software without restriction, including without limitation the rights | ||
| 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 14 | copies of the Software, and to permit persons to whom the Software is | ||
| 15 | furnished to do so, subject to the following conditions: | ||
| 16 | |||
| 17 | The above copyright notice and this permission notice shall be included in | ||
| 18 | all copies or substantial portions of the Software. | ||
| 19 | |||
| 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 26 | THE SOFTWARE. | ||
| 27 | |||
| 28 | =============================================================================== | ||
| 29 | */ | ||
| 30 | |||
| 31 | #include "compat.h" | ||
| 32 | #include "macros_and_utils.h" | ||
| 33 | #include "universe.h" | ||
| 34 | |||
| 35 | // crc64/we of string "UNIVERSE_REGKEY" generated at https://www.nitrxgen.net/hashgen/ | ||
| 36 | static void* const UNIVERSE_REGKEY = ((void*)0x9f877b2cf078f17f); | ||
| 37 | |||
| 38 | // ################################################################################################ | ||
| 39 | |||
| 40 | struct s_Universe* universe_create( lua_State* L) | ||
| 41 | { | ||
| 42 | struct s_Universe* U = (struct s_Universe*) lua_newuserdata( L, sizeof(struct s_Universe)); // universe | ||
| 43 | memset( U, 0, sizeof( struct s_Universe)); | ||
| 44 | lua_pushlightuserdata( L, UNIVERSE_REGKEY); // universe UNIVERSE_REGKEY | ||
| 45 | lua_pushvalue( L, -2); // universe UNIVERSE_REGKEY universe | ||
| 46 | lua_rawset( L, LUA_REGISTRYINDEX); // universe | ||
| 47 | return U; | ||
| 48 | } | ||
| 49 | |||
| 50 | // ################################################################################################ | ||
| 51 | |||
| 52 | void universe_store( lua_State* L, struct s_Universe* U) | ||
| 53 | { | ||
| 54 | STACK_CHECK( L); | ||
| 55 | lua_pushlightuserdata( L, UNIVERSE_REGKEY); | ||
| 56 | lua_pushlightuserdata( L, U); | ||
| 57 | lua_rawset( L, LUA_REGISTRYINDEX); | ||
| 58 | STACK_END( L, 0); | ||
| 59 | } | ||
| 60 | |||
| 61 | // ################################################################################################ | ||
| 62 | |||
| 63 | struct s_Universe* universe_get( lua_State* L) | ||
| 64 | { | ||
| 65 | struct s_Universe* universe; | ||
| 66 | STACK_GROW( L, 2); | ||
| 67 | STACK_CHECK( L); | ||
| 68 | lua_pushlightuserdata( L, UNIVERSE_REGKEY); | ||
| 69 | lua_rawget( L, LUA_REGISTRYINDEX); | ||
| 70 | universe = lua_touserdata( L, -1); // NULL if nil | ||
| 71 | lua_pop( L, 1); | ||
| 72 | STACK_END( L, 0); | ||
| 73 | return universe; | ||
| 74 | } | ||
diff --git a/src/universe.h b/src/universe.h new file mode 100644 index 0000000..0ca5bf7 --- /dev/null +++ b/src/universe.h | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | /* | ||
| 2 | * UNIVERSE.H | ||
| 3 | */ | ||
| 4 | #ifndef UNIVERSE_H | ||
| 5 | #define UNIVERSE_H | ||
| 6 | |||
| 7 | #include "lua.h" | ||
| 8 | #include "threading.h" | ||
| 9 | // MUTEX_T | ||
| 10 | |||
| 11 | // ################################################################################################ | ||
| 12 | |||
| 13 | /* | ||
| 14 | * Do we want to activate full lane tracking feature? (EXPERIMENTAL) | ||
| 15 | */ | ||
| 16 | #define HAVE_LANE_TRACKING 1 | ||
| 17 | |||
| 18 | // ################################################################################################ | ||
| 19 | |||
| 20 | // everything regarding the a Lanes universe is stored in that global structure | ||
| 21 | // held as a full userdata in the master Lua state that required it for the first time | ||
| 22 | // don't forget to initialize all members in LG_configure() | ||
| 23 | struct s_Universe | ||
| 24 | { | ||
| 25 | // for verbose errors | ||
| 26 | bool_t verboseErrors; | ||
| 27 | |||
| 28 | lua_CFunction on_state_create_func; | ||
| 29 | |||
| 30 | struct s_Keepers* keepers; | ||
| 31 | |||
| 32 | // Initialized by 'init_once_LOCKED()': the deep userdata Linda object | ||
| 33 | // used for timers (each lane will get a proxy to this) | ||
| 34 | volatile struct DEEP_PRELUDE* timer_deep; // = NULL | ||
| 35 | |||
| 36 | #if HAVE_LANE_TRACKING | ||
| 37 | MUTEX_T tracking_cs; | ||
| 38 | struct s_lane* volatile tracking_first; // will change to TRACKING_END if we want to activate tracking | ||
| 39 | #endif // HAVE_LANE_TRACKING | ||
| 40 | |||
| 41 | MUTEX_T selfdestruct_cs; | ||
| 42 | |||
| 43 | // require() serialization | ||
| 44 | MUTEX_T require_cs; | ||
| 45 | |||
| 46 | // Lock for reference counter inc/dec locks (to be initialized by outside code) TODO: get rid of this and use atomics instead! | ||
| 47 | MUTEX_T deep_lock; | ||
| 48 | MUTEX_T mtid_lock; | ||
| 49 | |||
| 50 | int last_mt_id; | ||
| 51 | |||
| 52 | #if USE_DEBUG_SPEW | ||
| 53 | int debugspew_indent_depth; | ||
| 54 | #endif // USE_DEBUG_SPEW | ||
| 55 | |||
| 56 | struct s_lane* volatile selfdestruct_first; | ||
| 57 | // 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 | ||
| 59 | int volatile selfdestructing_count; | ||
| 60 | }; | ||
| 61 | |||
| 62 | struct s_Universe* universe_get( lua_State* L); | ||
| 63 | struct s_Universe* universe_create( lua_State* L); | ||
| 64 | void universe_store( lua_State* L, struct s_Universe* U); | ||
| 65 | |||
| 66 | #endif // UNIVERSE_H | ||
