aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/deep.cpp14
-rw-r--r--src/keeper.cpp32
-rw-r--r--src/lanes.cpp6
-rw-r--r--src/lanes_private.h2
-rw-r--r--src/linda.cpp2
-rw-r--r--src/macros_and_utils.h7
-rw-r--r--src/state.cpp2
-rw-r--r--src/universe.cpp2
-rw-r--r--src/universe.h2
-rw-r--r--tests/keeper.lua39
10 files changed, 76 insertions, 32 deletions
diff --git a/src/deep.cpp b/src/deep.cpp
index dd682e4..f091d4d 100644
--- a/src/deep.cpp
+++ b/src/deep.cpp
@@ -113,7 +113,7 @@ static inline luaG_IdFunction* get_idfunc( lua_State* L, int index, LookupMode m
113 // when looking inside a keeper, we are 100% sure the object is a deep userdata 113 // when looking inside a keeper, we are 100% sure the object is a deep userdata
114 if( mode_ == eLM_FromKeeper) 114 if( mode_ == eLM_FromKeeper)
115 { 115 {
116 DeepPrelude** proxy = (DeepPrelude**) lua_touserdata( L, index); 116 DeepPrelude** const proxy{ lua_touserdata<DeepPrelude*>(L, index) };
117 // we can (and must) cast and fetch the internally stored idfunc 117 // we can (and must) cast and fetch the internally stored idfunc
118 return (*proxy)->idfunc; 118 return (*proxy)->idfunc;
119 } 119 }
@@ -133,7 +133,7 @@ static inline luaG_IdFunction* get_idfunc( lua_State* L, int index, LookupMode m
133 // replace metatable with the idfunc pointer, if it is actually a deep userdata 133 // replace metatable with the idfunc pointer, if it is actually a deep userdata
134 get_deep_lookup( L); // deep ... idfunc|nil 134 get_deep_lookup( L); // deep ... idfunc|nil
135 135
136 luaG_IdFunction* const ret{ static_cast<luaG_IdFunction*>(lua_touserdata(L, -1)) }; // nullptr if not a userdata 136 luaG_IdFunction* const ret{ lua_touserdata<luaG_IdFunction>(L, -1) }; // nullptr if not a userdata
137 lua_pop( L, 1); 137 lua_pop( L, 1);
138 STACK_CHECK( L, 0); 138 STACK_CHECK( L, 0);
139 return ret; 139 return ret;
@@ -161,7 +161,7 @@ void free_deep_prelude( lua_State* L, DeepPrelude* prelude_)
161 */ 161 */
162static int deep_userdata_gc( lua_State* L) 162static int deep_userdata_gc( lua_State* L)
163{ 163{
164 DeepPrelude** proxy = (DeepPrelude**) lua_touserdata( L, 1); 164 DeepPrelude** const proxy{ lua_touserdata<DeepPrelude*>(L, 1) };
165 DeepPrelude* p = *proxy; 165 DeepPrelude* p = *proxy;
166 166
167 // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded 167 // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded
@@ -418,17 +418,15 @@ int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction* idfunc, int nuv_)
418*/ 418*/
419void* luaG_todeep( lua_State* L, luaG_IdFunction* idfunc, int index) 419void* luaG_todeep( lua_State* L, luaG_IdFunction* idfunc, int index)
420{ 420{
421 DeepPrelude** proxy;
422
423 STACK_CHECK_START_REL(L, 0); 421 STACK_CHECK_START_REL(L, 0);
424 // ensure it is actually a deep userdata 422 // ensure it is actually a deep userdata
425 if( get_idfunc( L, index, eLM_LaneBody) != idfunc) 423 if( get_idfunc( L, index, eLM_LaneBody) != idfunc)
426 { 424 {
427 return nullptr; // no metatable, or wrong kind 425 return nullptr; // no metatable, or wrong kind
428 } 426 }
427 STACK_CHECK(L, 0);
429 428
430 proxy = (DeepPrelude**) lua_touserdata( L, index); 429 DeepPrelude** const proxy{ lua_touserdata<DeepPrelude*>(L, index) };
431 STACK_CHECK( L, 0);
432 430
433 return *proxy; 431 return *proxy;
434} 432}
@@ -464,7 +462,7 @@ bool copydeep(Universe* U, lua_State* L2, int L2_cache_i, lua_State* L, int i, L
464 lua_pop( L, 1); // ... u [uv]* 462 lua_pop( L, 1); // ... u [uv]*
465 STACK_CHECK( L, nuv); 463 STACK_CHECK( L, nuv);
466 464
467 errmsg = push_deep_proxy(L2, *(DeepPrelude**) lua_touserdata( L, i), nuv, mode_); // u 465 errmsg = push_deep_proxy(L2, *lua_touserdata<DeepPrelude*>(L, i), nuv, mode_); // u
468 466
469 // transfer all uservalues of the source in the destination 467 // transfer all uservalues of the source in the destination
470 { 468 {
diff --git a/src/keeper.cpp b/src/keeper.cpp
index 88bd4ff..35b5ea8 100644
--- a/src/keeper.cpp
+++ b/src/keeper.cpp
@@ -52,11 +52,18 @@
52// Keeper implementation 52// Keeper implementation
53// ################################################################################### 53// ###################################################################################
54 54
55struct keeper_fifo 55class keeper_fifo
56{ 56{
57 public:
58
57 int first{ 1 }; 59 int first{ 1 };
58 int count{ 0 }; 60 int count{ 0 };
59 int limit{ -1 }; 61 int limit{ -1 };
62
63 static void* operator new(size_t size_, lua_State* L) noexcept { return lua_newuserdatauv(L, size_, 1); }
64 // always embedded somewhere else or "in-place constructed" as a full userdata
65 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception
66 static void operator delete(void* p_, lua_State* L){ ASSERT_L(!"should never be called") };
60}; 67};
61 68
62static constexpr int CONTENTS_TABLE{ 1 }; 69static constexpr int CONTENTS_TABLE{ 1 };
@@ -66,7 +73,7 @@ static constexpr int CONTENTS_TABLE{ 1 };
66// replaces the fifo ud by its uservalue on the stack 73// replaces the fifo ud by its uservalue on the stack
67static keeper_fifo* prepare_fifo_access(lua_State* L, int idx_) 74static keeper_fifo* prepare_fifo_access(lua_State* L, int idx_)
68{ 75{
69 keeper_fifo* const fifo{ static_cast<keeper_fifo*>(lua_touserdata(L, idx_)) }; 76 keeper_fifo* const fifo{ lua_touserdata<keeper_fifo>(L, idx_) };
70 if (fifo != nullptr) 77 if (fifo != nullptr)
71 { 78 {
72 idx_ = lua_absindex(L, idx_); 79 idx_ = lua_absindex(L, idx_);
@@ -84,13 +91,14 @@ static keeper_fifo* prepare_fifo_access(lua_State* L, int idx_)
84// out: { first = 1, count = 0, limit = -1} 91// out: { first = 1, count = 0, limit = -1}
85static void fifo_new(lua_State* L) 92static void fifo_new(lua_State* L)
86{ 93{
87 keeper_fifo* fifo;
88 STACK_GROW(L, 2); 94 STACK_GROW(L, 2);
95 STACK_CHECK_START_REL(L, 0);
89 // a fifo full userdata has one uservalue, the table that holds the actual fifo contents 96 // a fifo full userdata has one uservalue, the table that holds the actual fifo contents
90 fifo = (keeper_fifo*) lua_newuserdatauv(L, sizeof(keeper_fifo), 1); 97 [[maybe_unused]] keeper_fifo* const fifo{ new (L) keeper_fifo{} };
91 fifo->keeper_fifo::keeper_fifo(); 98 STACK_CHECK(L, 1);
92 lua_newtable(L); 99 lua_newtable(L);
93 lua_setiuservalue(L, -2, CONTENTS_TABLE); 100 lua_setiuservalue(L, -2, CONTENTS_TABLE);
101 STACK_CHECK(L, 1);
94} 102}
95 103
96// ################################################################################################## 104// ##################################################################################################
@@ -163,13 +171,13 @@ static void fifo_pop( lua_State* L, keeper_fifo* fifo_, int count_)
163 171
164// ################################################################################################## 172// ##################################################################################################
165 173
166// in: linda_ud expected at *absolute* stack slot idx 174// in: linda_ud expected at stack slot idx
167// out: fifos[ud] 175// out: fifos[ud]
168// crc64/we of string "FIFOS_KEY" generated at http://www.nitrxgen.net/hashgen/ 176// crc64/we of string "FIFOS_KEY" generated at http://www.nitrxgen.net/hashgen/
169static constexpr UniqueKey FIFOS_KEY{ 0xdce50bbc351cd465ull }; 177static constexpr UniqueKey FIFOS_KEY{ 0xdce50bbc351cd465ull };
170static void push_table(lua_State* L, int idx_) 178static void push_table(lua_State* L, int idx_)
171{ 179{
172 STACK_GROW(L, 4); 180 STACK_GROW(L, 5);
173 STACK_CHECK_START_REL(L, 0); 181 STACK_CHECK_START_REL(L, 0);
174 idx_ = lua_absindex(L, idx_); 182 idx_ = lua_absindex(L, idx_);
175 FIFOS_KEY.query_registry(L); // ud fifos 183 FIFOS_KEY.query_registry(L); // ud fifos
@@ -276,7 +284,7 @@ int keepercall_send(lua_State* L)
276 lua_rawset(L, -4); // ud key ... fifos fifo 284 lua_rawset(L, -4); // ud key ... fifos fifo
277 } 285 }
278 lua_remove(L, -2); // ud key ... fifo 286 lua_remove(L, -2); // ud key ... fifo
279 keeper_fifo* fifo{ static_cast<keeper_fifo*>(lua_touserdata(L, -1)) }; 287 keeper_fifo* fifo{ lua_touserdata<keeper_fifo>(L, -1) };
280 if( fifo->limit >= 0 && fifo->count + n > fifo->limit) 288 if( fifo->limit >= 0 && fifo->count + n > fifo->limit)
281 { 289 {
282 lua_settop(L, 0); // 290 lua_settop(L, 0); //
@@ -374,12 +382,12 @@ int keepercall_limit(lua_State* L)
374 lua_pop(L, 1); // fifos key 382 lua_pop(L, 1); // fifos key
375 lua_pushvalue(L, -1); // fifos key key 383 lua_pushvalue(L, -1); // fifos key key
376 lua_rawget(L, -3); // fifos key fifo|nil 384 lua_rawget(L, -3); // fifos key fifo|nil
377 keeper_fifo* fifo{ static_cast<keeper_fifo*>(lua_touserdata(L, -1)) }; 385 keeper_fifo* fifo{ lua_touserdata<keeper_fifo>(L, -1) };
378 if (fifo == nullptr) 386 if (fifo == nullptr)
379 { // fifos key nil 387 { // fifos key nil
380 lua_pop(L, 1); // fifos key 388 lua_pop(L, 1); // fifos key
381 fifo_new(L); // fifos key fifo 389 fifo_new(L); // fifos key fifo
382 fifo = static_cast<keeper_fifo*>(lua_touserdata(L, -1)); 390 fifo = lua_touserdata<keeper_fifo>(L, -1);
383 lua_rawset(L, -3); // fifos 391 lua_rawset(L, -3); // fifos
384 } 392 }
385 // remove any clutter on the stack 393 // remove any clutter on the stack
@@ -418,7 +426,7 @@ int keepercall_set(lua_State* L)
418 lua_pushvalue(L, -1); // fifos key key 426 lua_pushvalue(L, -1); // fifos key key
419 lua_rawget(L, 1); // fifos key fifo|nil 427 lua_rawget(L, 1); // fifos key fifo|nil
420 // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! 428 // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged!
421 keeper_fifo* const fifo{ static_cast<keeper_fifo*>(lua_touserdata(L, -1)) }; 429 keeper_fifo* const fifo{ lua_touserdata<keeper_fifo>(L, -1) };
422 if (fifo != nullptr) // might be nullptr if we set a nonexistent key to nil 430 if (fifo != nullptr) // might be nullptr if we set a nonexistent key to nil
423 { // fifos key fifo 431 { // fifos key fifo
424 if (fifo->limit < 0) // fifo limit value is the default (unlimited): we can totally remove it 432 if (fifo->limit < 0) // fifo limit value is the default (unlimited): we can totally remove it
@@ -444,7 +452,7 @@ int keepercall_set(lua_State* L)
444 int const count{ lua_gettop(L) - 2 }; // number of items we want to store 452 int const count{ lua_gettop(L) - 2 }; // number of items we want to store
445 lua_pushvalue(L, 2); // fifos key [val [, ...]] key 453 lua_pushvalue(L, 2); // fifos key [val [, ...]] key
446 lua_rawget(L, 1); // fifos key [val [, ...]] fifo|nil 454 lua_rawget(L, 1); // fifos key [val [, ...]] fifo|nil
447 keeper_fifo* fifo = static_cast<keeper_fifo*>(lua_touserdata( L, -1)); 455 keeper_fifo* fifo{ lua_touserdata<keeper_fifo>(L, -1) };
448 if( fifo == nullptr) // can be nullptr if we store a value at a new key 456 if( fifo == nullptr) // can be nullptr if we store a value at a new key
449 { // fifos key [val [, ...]] nil 457 { // fifos key [val [, ...]] nil
450 // no need to wake writers in that case, because a writer can't wait on an inexistent key 458 // no need to wake writers in that case, because a writer can't wait on an inexistent key
diff --git a/src/lanes.cpp b/src/lanes.cpp
index 5945a1a..6b3542b 100644
--- a/src/lanes.cpp
+++ b/src/lanes.cpp
@@ -442,7 +442,7 @@ static bool selfdestruct_remove( Lane* s)
442*/ 442*/
443static int selfdestruct_gc( lua_State* L) 443static int selfdestruct_gc( lua_State* L)
444{ 444{
445 Universe* U = (Universe*) lua_touserdata( L, 1); 445 Universe* const U{ lua_touserdata<Universe>(L, 1) };
446 446
447 while( U->selfdestruct_first != SELFDESTRUCT_END) // true at most once! 447 while( U->selfdestruct_first != SELFDESTRUCT_END) // true at most once!
448 { 448 {
@@ -781,7 +781,7 @@ LUAG_FUNC( set_debug_threadname)
781 // fnv164 of string "debug_threadname" generated at https://www.pelock.com/products/hash-calculator 781 // fnv164 of string "debug_threadname" generated at https://www.pelock.com/products/hash-calculator
782 constexpr UniqueKey hidden_regkey{ 0x79C0669AAAE04440ull }; 782 constexpr UniqueKey hidden_regkey{ 0x79C0669AAAE04440ull };
783 // C s_lane structure is a light userdata upvalue 783 // C s_lane structure is a light userdata upvalue
784 Lane* s = (Lane*) lua_touserdata( L, lua_upvalueindex( 1)); 784 Lane* const s{ lua_touserdata<Lane>(L, lua_upvalueindex(1)) };
785 luaL_checktype( L, -1, LUA_TSTRING); // "name" 785 luaL_checktype( L, -1, LUA_TSTRING); // "name"
786 lua_settop( L, 1); 786 lua_settop( L, 1);
787 STACK_CHECK_START_ABS( L, 1); 787 STACK_CHECK_START_ABS( L, 1);
@@ -1887,7 +1887,7 @@ LUAG_FUNC( configure)
1887 STACK_CHECK( L, 2); 1887 STACK_CHECK( L, 2);
1888 1888
1889 // Proxy userdata contents is only a 'DeepPrelude*' pointer 1889 // Proxy userdata contents is only a 'DeepPrelude*' pointer
1890 U->timer_deep = *(DeepPrelude**) lua_touserdata( L, -1); 1890 U->timer_deep = *lua_touserdata<DeepPrelude*>(L, -1);
1891 // increment refcount so that this linda remains alive as long as the universe exists. 1891 // increment refcount so that this linda remains alive as long as the universe exists.
1892 U->timer_deep->m_refcount.fetch_add(1, std::memory_order_relaxed); 1892 U->timer_deep->m_refcount.fetch_add(1, std::memory_order_relaxed);
1893 lua_pop( L, 1); // settings 1893 lua_pop( L, 1); // settings
diff --git a/src/lanes_private.h b/src/lanes_private.h
index b8d26d3..839a51f 100644
--- a/src/lanes_private.h
+++ b/src/lanes_private.h
@@ -83,7 +83,7 @@ static inline Lane* get_lane_from_registry( lua_State* L)
83 STACK_GROW( L, 1); 83 STACK_GROW( L, 1);
84 STACK_CHECK_START_REL(L, 0); 84 STACK_CHECK_START_REL(L, 0);
85 CANCEL_TEST_KEY.query_registry(L); 85 CANCEL_TEST_KEY.query_registry(L);
86 Lane* const s = static_cast<Lane*>(lua_touserdata(L, -1)); // lightuserdata (true 's_lane' pointer) / nil 86 Lane* const s{ lua_touserdata<Lane>(L, -1) }; // lightuserdata (true 's_lane' pointer) / nil
87 lua_pop( L, 1); 87 lua_pop( L, 1);
88 STACK_CHECK( L, 0); 88 STACK_CHECK( L, 0);
89 return s; 89 return s;
diff --git a/src/linda.cpp b/src/linda.cpp
index eb2349e..7e346d8 100644
--- a/src/linda.cpp
+++ b/src/linda.cpp
@@ -808,7 +808,7 @@ static void* linda_id( lua_State* L, DeepOp op_)
808 808
809 case eDO_delete: 809 case eDO_delete:
810 { 810 {
811 struct s_Linda* linda = (struct s_Linda*) lua_touserdata( L, 1); 811 struct s_Linda* const linda{ lua_touserdata<struct s_Linda>(L, 1) };
812 ASSERT_L( linda); 812 ASSERT_L( linda);
813 813
814 // Clean associated structures in the keeper state. 814 // Clean associated structures in the keeper state.
diff --git a/src/macros_and_utils.h b/src/macros_and_utils.h
index c549d72..370cbed 100644
--- a/src/macros_and_utils.h
+++ b/src/macros_and_utils.h
@@ -124,3 +124,10 @@ inline void STACK_GROW(lua_State* L, int n_)
124} 124}
125 125
126#define LUAG_FUNC( func_name) int LG_##func_name( lua_State* L) 126#define LUAG_FUNC( func_name) int LG_##func_name( lua_State* L)
127
128// a small helper to extract a userdata pointer from the stack
129template<typename T>
130T* lua_touserdata(lua_State* L, int index_)
131{
132 return static_cast<T*>(lua_touserdata(L, index_));
133}
diff --git a/src/state.cpp b/src/state.cpp
index 7bdaec9..b46a145 100644
--- a/src/state.cpp
+++ b/src/state.cpp
@@ -259,7 +259,7 @@ lua_State* create_state( Universe* U, lua_State* from_)
259 lua_pushcclosure( from_, U->provide_allocator, 0); 259 lua_pushcclosure( from_, U->provide_allocator, 0);
260 lua_call( from_, 0, 1); 260 lua_call( from_, 0, 1);
261 { 261 {
262 AllocatorDefinition* const def = (AllocatorDefinition*) lua_touserdata( from_, -1); 262 AllocatorDefinition* const def{ lua_touserdata<AllocatorDefinition>(from_, -1) };
263 L = lua_newstate( def->m_allocF, def->m_allocUD); 263 L = lua_newstate( def->m_allocF, def->m_allocUD);
264 } 264 }
265 lua_pop( from_, 1); 265 lua_pop( from_, 1);
diff --git a/src/universe.cpp b/src/universe.cpp
index 4dd956d..095f000 100644
--- a/src/universe.cpp
+++ b/src/universe.cpp
@@ -67,7 +67,7 @@ Universe* universe_get(lua_State* L)
67 STACK_GROW(L, 2); 67 STACK_GROW(L, 2);
68 STACK_CHECK_START_REL(L, 0); 68 STACK_CHECK_START_REL(L, 0);
69 UNIVERSE_REGKEY.query_registry(L); 69 UNIVERSE_REGKEY.query_registry(L);
70 Universe* const universe = static_cast<Universe*>(lua_touserdata(L, -1)); // nullptr if nil 70 Universe* const universe{ lua_touserdata<Universe>(L, -1) }; // nullptr if nil
71 lua_pop(L, 1); 71 lua_pop(L, 1);
72 STACK_CHECK(L, 0); 72 STACK_CHECK(L, 0);
73 return universe; 73 return universe;
diff --git a/src/universe.h b/src/universe.h
index bb3ebdd..04c92ca 100644
--- a/src/universe.h
+++ b/src/universe.h
@@ -142,7 +142,7 @@ struct Universe
142 142
143 // Initialized by 'init_once_LOCKED()': the deep userdata Linda object 143 // Initialized by 'init_once_LOCKED()': the deep userdata Linda object
144 // used for timers (each lane will get a proxy to this) 144 // used for timers (each lane will get a proxy to this)
145 volatile DeepPrelude* timer_deep{ nullptr }; // = nullptr 145 DeepPrelude* timer_deep{ nullptr };
146 146
147#if HAVE_LANE_TRACKING() 147#if HAVE_LANE_TRACKING()
148 std::mutex tracking_cs; 148 std::mutex tracking_cs;
diff --git a/tests/keeper.lua b/tests/keeper.lua
index f8c915d..11bbe17 100644
--- a/tests/keeper.lua
+++ b/tests/keeper.lua
@@ -6,6 +6,12 @@
6 6
7local lanes = require "lanes".configure{ with_timers = false, nb_keepers = 200} 7local lanes = require "lanes".configure{ with_timers = false, nb_keepers = 200}
8 8
9local print_id = 0
10local PRINT = function(...)
11 print_id = print_id + 1
12 print("main", print_id .. ".", ...)
13end
14
9local function keeper(linda) 15local function keeper(linda)
10 local mt= { 16 local mt= {
11 __index= function( _, key ) 17 __index= function( _, key )
@@ -25,23 +31,48 @@ local A= keeper( lindaA )
25local lindaB= lanes.linda( "B", 2) 31local lindaB= lanes.linda( "B", 2)
26local B= keeper( lindaB ) 32local B= keeper( lindaB )
27 33
34local lindaC= lanes.linda( "C", 3)
35local C= keeper( lindaC )
36
28A.some= 1 37A.some= 1
29print( A.some ) 38PRINT("A.some == " .. A.some )
30assert( A.some==1 ) 39assert( A.some==1 )
31 40
32B.some= "hoo" 41B.some= "hoo"
42PRINT("B.some == " .. B.some )
33assert( B.some=="hoo" ) 43assert( B.some=="hoo" )
34assert( A.some==1 ) 44assert( A.some==1 )
45assert( C.some==nil )
35 46
36function lane() 47function lane()
48 local print_id = 0
49 local PRINT = function(...)
50 print_id = print_id + 1
51 print("lane", print_id .. ".", ...)
52 end
53
37 local a= keeper(lindaA) 54 local a= keeper(lindaA)
38 print( a.some ) 55 PRINT("a.some == " .. a.some )
39 assert( a.some==1 ) 56 assert( a.some==1 )
40 a.some= 2 57 a.some= 2
58 assert( a.some==2 )
59 PRINT("a.some == " .. a.some )
60
61 local c = keeper(lindaC)
62 assert( c.some==nil )
63 PRINT("c.some == " .. tostring(c.some))
64 c.some= 3
65 assert( c.some==3 )
66 PRINT("c.some == " .. c.some)
41end 67end
42 68
69PRINT("lane started")
43local h= lanes.gen( "io", lane )() 70local h= lanes.gen( "io", lane )()
44h:join() 71PRINT("lane joined:", h:join())
45 72
46print( A.some ) -- 2 73PRINT("A.some = " .. A.some )
47assert( A.some==2 ) 74assert( A.some==2 )
75PRINT("C.some = " .. C.some )
76assert( C.some==3 )
77lindaC:set("some")
78assert( C.some==nil )