aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES4
-rw-r--r--CMakeLists.txt2
-rw-r--r--deep_test/deep_test.c91
-rw-r--r--deep_test/deep_test.lua13
-rw-r--r--docs/index.html6
-rw-r--r--src/Makefile2
-rw-r--r--src/deep.c61
-rw-r--r--src/keeper.c8
-rw-r--r--src/lanes.c45
-rw-r--r--src/macros_and_utils.h71
-rw-r--r--src/tools.c48
-rw-r--r--src/tools.h118
-rw-r--r--src/universe.c74
-rw-r--r--src/universe.h66
14 files changed, 396 insertions, 213 deletions
diff --git a/CHANGES b/CHANGES
index 156be08..338c48f 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,9 @@
1CHANGES: 1CHANGES:
2 2
3CHANGE 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
3CHANGE 121: BGe 13-Jun-17 7CHANGE 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
40INCLUDE_DIRECTORIES(src) 40INCLUDE_DIRECTORIES(src)
41ADD_LIBRARY(core MODULE src/lanes.c src/deep.c src/threading.c src/tools.c src/keeper.c src/compat.c) 41ADD_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
43IF(UNIX AND NOT CYGWIN) 43IF(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
15static int deep_tostring(lua_State* L)
16{
17 lua_pushliteral( L, "I am a deep_test");
18 return 1;
19}
20
21// ################################################################################################
22
23static luaL_Reg const deep_mt[] =
24{
25 { "__tostring", deep_tostring},
26 { NULL, NULL }
27};
28
29// ################################################################################################
30
31static 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
72int luaD_new_deep(lua_State* L)
73{
74 return luaG_newdeepuserdata( L, deep_test_id);
75}
76
77// ################################################################################################
78
79static luaL_Reg const deep_module[] =
80{
81 { "new_deep", luaD_new_deep},
82 { NULL, NULL}
83};
84
85// ################################################################################################
86
87extern 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
2local dt = require "deep_test"
3local deep = dt.new_deep()
4print( deep)
5
6-- now load Lanes and see if that userdata is transferable
7
8local lanes = require("lanes").configure()
9
10local l = lanes.linda "my linda"
11l.put( "key", deep)
12local out = l.get( "key")
13print( 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
8MODULE=lanes 8MODULE=lanes
9 9
10SRC=lanes.c compat.c threading.c tools.c deep.c keeper.c 10SRC=lanes.c compat.c threading.c tools.c deep.c keeper.c universe.c
11 11
12OBJ=$(SRC:.c=.o) 12OBJ=$(SRC:.c=.o)
13 13
diff --git a/src/deep.c b/src/deep.c
index b5d6aee..71a798c 100644
--- a/src/deep.c
+++ b/src/deep.c
@@ -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
11Copyright (C) 2002-10 Asko Kauppi <akauppi@gmail.com> 11Copyright (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
14Permission is hereby granted, free of charge, to any person obtaining a copy 14Permission is hereby granted, free of charge, to any person obtaining a copy
15of this software and associated documentation files (the "Software"), to deal 15of 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
209void free_deep_prelude( lua_State* L, DEEP_PRELUDE* prelude_) 211void 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*/
225static int deep_userdata_gc( lua_State* L) 227static 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 */
263char const* push_deep_proxy( struct s_Universe* U, lua_State* L, DEEP_PRELUDE* prelude, enum eLookupMode mode_) 267char 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
439int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc) 444int 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*/
482void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index) 487void* 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
55char const* VERSION = "3.11"; 55char 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)
1070LUAG_FUNC( linda_dump) 1071LUAG_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)
2872LUAG_FUNC( threads) 2873LUAG_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
3025LUAG_FUNC( configure) 3026LUAG_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
32extern 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.
48extern luaG_IdFunction copydeep( struct s_Universe* U, lua_State* L, lua_State* L2, int index, enum eLookupMode mode_); 49extern luaG_IdFunction copydeep( struct s_Universe* U, lua_State* L, lua_State* L2, int index, enum eLookupMode mode_);
49extern void push_registry_subtable( lua_State* L, void* key_); 50extern void push_registry_subtable( lua_State* L, void* key_);
50 51
51void* const UNIVERSE_REGKEY = (void*) luaopen_lanes_core;
52
53/*
54 * ###############################################################################################
55 * ########################################### ASSERT ############################################
56 * ###############################################################################################
57 */
58void 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
66char const* const CONFIG_REGKEY = "ee932492-a654-4506-9da8-f16540bdb5d4"; 52char const* const CONFIG_REGKEY = "ee932492-a654-4506-9da8-f16540bdb5d4";
67char const* const LOOKUP_REGKEY = "ddea37aa-50c7-4d3f-8e0b-fb7a9d62bac5"; 53char 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// ################################################################################################
154struct 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)
168void luaG_copy_one_time_settings( struct s_Universe* U, lua_State* L, lua_State* L2) 142void 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 */
859static char const* find_lookup_name( lua_State* L, uint_t i, enum eLookupMode mode_, char const* upName_, size_t* len_) 831static 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
37extern 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
55typedef struct 19struct 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()
68struct 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
107struct s_Universe* get_universe( lua_State* L);
108extern 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
158char const* push_deep_proxy( struct s_Universe* U, lua_State* L, DEEP_PRELUDE* prelude, enum eLookupMode mode_); 48char const* push_deep_proxy( struct s_Universe* U, lua_State* L, struct DEEP_PRELUDE* prelude, enum eLookupMode mode_);
159void free_deep_prelude( lua_State* L, DEEP_PRELUDE* prelude_); 49void free_deep_prelude( lua_State* L, struct DEEP_PRELUDE* prelude_);
160 50
161int luaG_inter_copy_package( struct s_Universe* U, lua_State* L, lua_State* L2, int package_idx_, enum eLookupMode mode_); 51int 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
8Copyright (C) 2017 Benoit Germain <bnt.germain@gmail.com>
9
10Permission is hereby granted, free of charge, to any person obtaining a copy
11of this software and associated documentation files (the "Software"), to deal
12in the Software without restriction, including without limitation the rights
13to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14copies of the Software, and to permit persons to whom the Software is
15furnished to do so, subject to the following conditions:
16
17The above copyright notice and this permission notice shall be included in
18all copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26THE 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/
36static void* const UNIVERSE_REGKEY = ((void*)0x9f877b2cf078f17f);
37
38// ################################################################################################
39
40struct 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
52void 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
63struct 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()
23struct 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
62struct s_Universe* universe_get( lua_State* L);
63struct s_Universe* universe_create( lua_State* L);
64void universe_store( lua_State* L, struct s_Universe* U);
65
66#endif // UNIVERSE_H