diff options
-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 | ||