diff options
-rw-r--r-- | src/lanes.cpp | 4 | ||||
-rw-r--r-- | src/lanes_private.h | 2 | ||||
-rw-r--r-- | src/linda.cpp | 226 | ||||
-rw-r--r-- | tests/fifo.lua | 2 | ||||
-rw-r--r-- | tests/keeper.lua | 9 |
5 files changed, 168 insertions, 75 deletions
diff --git a/src/lanes.cpp b/src/lanes.cpp index 72652ef..a378a88 100644 --- a/src/lanes.cpp +++ b/src/lanes.cpp | |||
@@ -142,8 +142,6 @@ static constexpr UniqueKey STACKTRACE_REGKEY{ 0x534af7d3226a429full }; | |||
142 | // crc64/we of string "FINALIZER_REGKEY" generated at http://www.nitrxgen.net/hashgen/ | 142 | // crc64/we of string "FINALIZER_REGKEY" generated at http://www.nitrxgen.net/hashgen/ |
143 | static constexpr UniqueKey FINALIZER_REGKEY{ 0x188fccb8bf348e09ull }; | 143 | static constexpr UniqueKey FINALIZER_REGKEY{ 0x188fccb8bf348e09ull }; |
144 | 144 | ||
145 | struct s_Linda; | ||
146 | |||
147 | /* | 145 | /* |
148 | * Push a table stored in registry onto Lua stack. | 146 | * Push a table stored in registry onto Lua stack. |
149 | * | 147 | * |
@@ -892,7 +890,7 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void* vs) | |||
892 | lua_setglobal( L, "set_finalizer"); | 890 | lua_setglobal( L, "set_finalizer"); |
893 | 891 | ||
894 | // Tie "set_debug_threadname()" to the state | 892 | // Tie "set_debug_threadname()" to the state |
895 | // But don't register it in the lookup database because of the s_lane pointer upvalue | 893 | // But don't register it in the lookup database because of the Lane pointer upvalue |
896 | lua_pushlightuserdata( L, s); | 894 | lua_pushlightuserdata( L, s); |
897 | lua_pushcclosure( L, LG_set_debug_threadname, 1); | 895 | lua_pushcclosure( L, LG_set_debug_threadname, 1); |
898 | lua_setglobal( L, "set_debug_threadname"); | 896 | lua_setglobal( L, "set_debug_threadname"); |
diff --git a/src/lanes_private.h b/src/lanes_private.h index 5d6d25c..85b3c52 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{ lua_tolightuserdata<Lane>(L, -1) }; // lightuserdata (true 's_lane' pointer) / nil | 86 | Lane* const s{ lua_tolightuserdata<Lane>(L, -1) }; // lightuserdata (true '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 b28a126..2830593 100644 --- a/src/linda.cpp +++ b/src/linda.cpp | |||
@@ -42,32 +42,120 @@ THE SOFTWARE. | |||
42 | #include "deep.h" | 42 | #include "deep.h" |
43 | #include "lanes_private.h" | 43 | #include "lanes_private.h" |
44 | 44 | ||
45 | #include <array> | ||
46 | #include <bit> | ||
47 | #include <variant> | ||
48 | |||
45 | /* | 49 | /* |
46 | * Actual data is kept within a keeper state, which is hashed by the 's_Linda' | 50 | * Actual data is kept within a keeper state, which is hashed by the 'Linda' |
47 | * pointer (which is same to all userdatas pointing to it). | 51 | * pointer (which is same to all userdatas pointing to it). |
48 | */ | 52 | */ |
49 | struct s_Linda | 53 | struct Linda : public DeepPrelude // Deep userdata MUST start with this header |
50 | { | 54 | { |
51 | DeepPrelude prelude; // Deep userdata MUST start with this header | 55 | private: |
56 | |||
57 | static constexpr size_t kEmbeddedNameLength = 24; | ||
58 | using EmbeddedName = std::array<char, kEmbeddedNameLength>; | ||
59 | struct AllocatedName | ||
60 | { | ||
61 | size_t len{ 0 }; | ||
62 | char* name{ nullptr }; | ||
63 | }; | ||
64 | |||
65 | public: | ||
66 | |||
52 | SIGNAL_T read_happened; | 67 | SIGNAL_T read_happened; |
53 | SIGNAL_T write_happened; | 68 | SIGNAL_T write_happened; |
54 | Universe* U; // the universe this linda belongs to | 69 | Universe* const U; // the universe this linda belongs to |
55 | ptrdiff_t group; // a group to control keeper allocation between lindas | 70 | ptrdiff_t const group; // a group to control keeper allocation between lindas |
56 | CancelRequest simulate_cancel; | 71 | CancelRequest simulate_cancel{ CancelRequest::None }; |
57 | char name[1]; | 72 | std::variant<AllocatedName, EmbeddedName> m_name; |
58 | }; | ||
59 | #define LINDA_KEEPER_HASHSEED( linda) (linda->group ? linda->group : (ptrdiff_t)linda) | ||
60 | 73 | ||
74 | public: | ||
75 | |||
76 | Linda(Universe* U_, ptrdiff_t group_, char const* name_, size_t len_) | ||
77 | : U{ U_ } | ||
78 | , group{ group_ << KEEPER_MAGIC_SHIFT } | ||
79 | { | ||
80 | SIGNAL_INIT(&read_happened); | ||
81 | SIGNAL_INIT(&write_happened); | ||
82 | |||
83 | setName(name_, len_); | ||
84 | } | ||
85 | |||
86 | ~Linda() | ||
87 | { | ||
88 | // There aren't any lanes waiting on these lindas, since all proxies have been gc'ed. Right? | ||
89 | SIGNAL_FREE(&read_happened); | ||
90 | SIGNAL_FREE(&write_happened); | ||
91 | if (std::holds_alternative<AllocatedName>(m_name)) | ||
92 | { | ||
93 | AllocatedName& name = std::get<AllocatedName>(m_name); | ||
94 | U->internal_allocator.free(name.name, name.len); | ||
95 | } | ||
96 | } | ||
97 | |||
98 | private: | ||
99 | |||
100 | void setName(char const* name_, size_t len_) | ||
101 | { | ||
102 | // keep default | ||
103 | if (!name_ || len_ == 0) | ||
104 | { | ||
105 | return; | ||
106 | } | ||
107 | ++len_; // don't forget terminating 0 | ||
108 | if (len_ < kEmbeddedNameLength) | ||
109 | { | ||
110 | m_name.emplace<EmbeddedName>(); | ||
111 | char* const name{ std::get<EmbeddedName>(m_name).data() }; | ||
112 | memcpy(name, name_, len_); | ||
113 | } | ||
114 | else | ||
115 | { | ||
116 | AllocatedName& name = std::get<AllocatedName>(m_name); | ||
117 | name.name = static_cast<char*>(U->internal_allocator.alloc(len_)); | ||
118 | name.len = len_; | ||
119 | memcpy(name.name, name_, len_); | ||
120 | } | ||
121 | } | ||
122 | |||
123 | public: | ||
124 | |||
125 | ptrdiff_t hashSeed() const { return group ? group : std::bit_cast<ptrdiff_t>(this); } | ||
126 | |||
127 | char const* getName() const | ||
128 | { | ||
129 | if (std::holds_alternative<AllocatedName>(m_name)) | ||
130 | { | ||
131 | AllocatedName const& name = std::get<AllocatedName>(m_name); | ||
132 | return name.name; | ||
133 | } | ||
134 | if (std::holds_alternative<EmbeddedName>(m_name)) | ||
135 | { | ||
136 | char const* const name{ std::get<EmbeddedName>(m_name).data() }; | ||
137 | return name; | ||
138 | } | ||
139 | return nullptr; | ||
140 | } | ||
141 | }; | ||
61 | static void* linda_id( lua_State*, DeepOp); | 142 | static void* linda_id( lua_State*, DeepOp); |
62 | 143 | ||
63 | static inline struct s_Linda* lua_toLinda( lua_State* L, int idx_) | 144 | template<bool OPT> |
145 | static inline Linda* lua_toLinda(lua_State* L, int idx_) | ||
64 | { | 146 | { |
65 | struct s_Linda* linda = (struct s_Linda*) luaG_todeep( L, linda_id, idx_); | 147 | Linda* const linda{ static_cast<Linda*>(luaG_todeep(L, linda_id, idx_)) }; |
66 | luaL_argcheck( L, linda != nullptr, idx_, "expecting a linda object"); | 148 | if (!OPT) |
149 | { | ||
150 | luaL_argcheck(L, linda != nullptr, idx_, "expecting a linda object"); | ||
151 | } | ||
152 | ASSERT_L(linda->U == universe_get(L)); | ||
67 | return linda; | 153 | return linda; |
68 | } | 154 | } |
69 | 155 | ||
70 | static void check_key_types( lua_State* L, int start_, int end_) | 156 | // ################################################################################################# |
157 | |||
158 | static void check_key_types(lua_State* L, int start_, int end_) | ||
71 | { | 159 | { |
72 | int i; | 160 | int i; |
73 | for( i = start_; i <= end_; ++ i) | 161 | for( i = start_; i <= end_; ++ i) |
@@ -81,13 +169,14 @@ static void check_key_types( lua_State* L, int start_, int end_) | |||
81 | } | 169 | } |
82 | } | 170 | } |
83 | 171 | ||
84 | LUAG_FUNC( linda_protected_call) | 172 | // ################################################################################################# |
173 | |||
174 | LUAG_FUNC(linda_protected_call) | ||
85 | { | 175 | { |
86 | int rc = LUA_OK; | 176 | Linda* const linda{ lua_toLinda<false>(L, 1) }; |
87 | struct s_Linda* linda = lua_toLinda( L, 1); | ||
88 | 177 | ||
89 | // acquire the keeper | 178 | // acquire the keeper |
90 | Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED(linda)); | 179 | Keeper* K = keeper_acquire( linda->U->keepers, linda->hashSeed()); |
91 | lua_State* KL = K ? K->L : nullptr; | 180 | lua_State* KL = K ? K->L : nullptr; |
92 | if( KL == nullptr) return 0; | 181 | if( KL == nullptr) return 0; |
93 | 182 | ||
@@ -95,7 +184,7 @@ LUAG_FUNC( linda_protected_call) | |||
95 | lua_pushvalue( L, lua_upvalueindex( 1)); | 184 | lua_pushvalue( L, lua_upvalueindex( 1)); |
96 | lua_insert( L, 1); | 185 | lua_insert( L, 1); |
97 | // do a protected call | 186 | // do a protected call |
98 | rc = lua_pcall( L, lua_gettop( L) - 1, LUA_MULTRET, 0); | 187 | int const rc{ lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0) }; |
99 | 188 | ||
100 | // release the keeper | 189 | // release the keeper |
101 | keeper_release( K); | 190 | keeper_release( K); |
@@ -109,6 +198,8 @@ LUAG_FUNC( linda_protected_call) | |||
109 | return lua_gettop( L); | 198 | return lua_gettop( L); |
110 | } | 199 | } |
111 | 200 | ||
201 | // ################################################################################################# | ||
202 | |||
112 | /* | 203 | /* |
113 | * bool= linda_send( linda_ud, [timeout_secs=-1,] [linda.null,] key_num|str|bool|lightuserdata, ... ) | 204 | * bool= linda_send( linda_ud, [timeout_secs=-1,] [linda.null,] key_num|str|bool|lightuserdata, ... ) |
114 | * | 205 | * |
@@ -120,7 +211,7 @@ LUAG_FUNC( linda_protected_call) | |||
120 | */ | 211 | */ |
121 | LUAG_FUNC( linda_send) | 212 | LUAG_FUNC( linda_send) |
122 | { | 213 | { |
123 | struct s_Linda* linda = lua_toLinda( L, 1); | 214 | Linda* const linda{ lua_toLinda<false>(L, 1) }; |
124 | bool ret{ false }; | 215 | bool ret{ false }; |
125 | CancelRequest cancel{ CancelRequest::None }; | 216 | CancelRequest cancel{ CancelRequest::None }; |
126 | int pushed; | 217 | int pushed; |
@@ -167,8 +258,8 @@ LUAG_FUNC( linda_send) | |||
167 | keeper_toggle_nil_sentinels( L, key_i + 1, eLM_ToKeeper); | 258 | keeper_toggle_nil_sentinels( L, key_i + 1, eLM_ToKeeper); |
168 | 259 | ||
169 | { | 260 | { |
170 | Lane* const s = get_lane_from_registry( L); | 261 | Lane* const s{ get_lane_from_registry(L) }; |
171 | Keeper* const K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); | 262 | Keeper* const K{ which_keeper(linda->U->keepers, linda->hashSeed()) }; |
172 | lua_State* KL = K ? K->L : nullptr; | 263 | lua_State* KL = K ? K->L : nullptr; |
173 | if( KL == nullptr) return 0; | 264 | if( KL == nullptr) return 0; |
174 | STACK_CHECK_START_REL(KL, 0); | 265 | STACK_CHECK_START_REL(KL, 0); |
@@ -256,6 +347,7 @@ LUAG_FUNC( linda_send) | |||
256 | } | 347 | } |
257 | } | 348 | } |
258 | 349 | ||
350 | // ################################################################################################# | ||
259 | 351 | ||
260 | /* | 352 | /* |
261 | * 2 modes of operation | 353 | * 2 modes of operation |
@@ -271,7 +363,7 @@ LUAG_FUNC( linda_send) | |||
271 | #define BATCH_SENTINEL "270e6c9d-280f-4983-8fee-a7ecdda01475" | 363 | #define BATCH_SENTINEL "270e6c9d-280f-4983-8fee-a7ecdda01475" |
272 | LUAG_FUNC( linda_receive) | 364 | LUAG_FUNC( linda_receive) |
273 | { | 365 | { |
274 | struct s_Linda* linda = lua_toLinda( L, 1); | 366 | Linda* const linda{ lua_toLinda<false>(L, 1) }; |
275 | int pushed, expected_pushed_min, expected_pushed_max; | 367 | int pushed, expected_pushed_min, expected_pushed_max; |
276 | CancelRequest cancel{ CancelRequest::None }; | 368 | CancelRequest cancel{ CancelRequest::None }; |
277 | keeper_api_t keeper_receive; | 369 | keeper_api_t keeper_receive; |
@@ -326,8 +418,8 @@ LUAG_FUNC( linda_receive) | |||
326 | } | 418 | } |
327 | 419 | ||
328 | { | 420 | { |
329 | Lane* const s = get_lane_from_registry( L); | 421 | Lane* const s{ get_lane_from_registry(L) }; |
330 | Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); | 422 | Keeper* const K{ which_keeper(linda->U->keepers, linda->hashSeed()) }; |
331 | if( K == nullptr) return 0; | 423 | if( K == nullptr) return 0; |
332 | for (bool try_again{ true };;) | 424 | for (bool try_again{ true };;) |
333 | { | 425 | { |
@@ -409,6 +501,7 @@ LUAG_FUNC( linda_receive) | |||
409 | } | 501 | } |
410 | } | 502 | } |
411 | 503 | ||
504 | // ################################################################################################# | ||
412 | 505 | ||
413 | /* | 506 | /* |
414 | * [true|lanes.cancel_error] = linda_set( linda_ud, key_num|str|bool|lightuserdata [, value [, ...]]) | 507 | * [true|lanes.cancel_error] = linda_set( linda_ud, key_num|str|bool|lightuserdata [, value [, ...]]) |
@@ -420,7 +513,7 @@ LUAG_FUNC( linda_receive) | |||
420 | */ | 513 | */ |
421 | LUAG_FUNC( linda_set) | 514 | LUAG_FUNC( linda_set) |
422 | { | 515 | { |
423 | struct s_Linda* const linda = lua_toLinda( L, 1); | 516 | Linda* const linda{ lua_toLinda<false>(L, 1) }; |
424 | int pushed; | 517 | int pushed; |
425 | bool const has_value{ lua_gettop(L) > 2 }; | 518 | bool const has_value{ lua_gettop(L) > 2 }; |
426 | 519 | ||
@@ -428,7 +521,7 @@ LUAG_FUNC( linda_set) | |||
428 | check_key_types( L, 2, 2); | 521 | check_key_types( L, 2, 2); |
429 | 522 | ||
430 | { | 523 | { |
431 | Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); | 524 | Keeper* const K{ which_keeper(linda->U->keepers, linda->hashSeed()) }; |
432 | 525 | ||
433 | if (linda->simulate_cancel == CancelRequest::None) | 526 | if (linda->simulate_cancel == CancelRequest::None) |
434 | { | 527 | { |
@@ -467,6 +560,7 @@ LUAG_FUNC( linda_set) | |||
467 | return (pushed < 0) ? luaL_error( L, "tried to copy unsupported types") : pushed; | 560 | return (pushed < 0) ? luaL_error( L, "tried to copy unsupported types") : pushed; |
468 | } | 561 | } |
469 | 562 | ||
563 | // ################################################################################################# | ||
470 | 564 | ||
471 | /* | 565 | /* |
472 | * [val] = linda_count( linda_ud, [key [, ...]]) | 566 | * [val] = linda_count( linda_ud, [key [, ...]]) |
@@ -475,14 +569,14 @@ LUAG_FUNC( linda_set) | |||
475 | */ | 569 | */ |
476 | LUAG_FUNC( linda_count) | 570 | LUAG_FUNC( linda_count) |
477 | { | 571 | { |
478 | struct s_Linda* linda = lua_toLinda( L, 1); | 572 | Linda* const linda{ lua_toLinda<false>(L, 1) }; |
479 | int pushed; | 573 | int pushed; |
480 | 574 | ||
481 | // make sure the keys are of a valid type | 575 | // make sure the keys are of a valid type |
482 | check_key_types( L, 2, lua_gettop( L)); | 576 | check_key_types( L, 2, lua_gettop( L)); |
483 | 577 | ||
484 | { | 578 | { |
485 | Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); | 579 | Keeper* const K{ which_keeper(linda->U->keepers, linda->hashSeed()) }; |
486 | pushed = keeper_call( linda->U, K->L, KEEPER_API( count), L, linda, 2); | 580 | pushed = keeper_call( linda->U, K->L, KEEPER_API( count), L, linda, 2); |
487 | if( pushed < 0) | 581 | if( pushed < 0) |
488 | { | 582 | { |
@@ -492,6 +586,7 @@ LUAG_FUNC( linda_count) | |||
492 | return pushed; | 586 | return pushed; |
493 | } | 587 | } |
494 | 588 | ||
589 | // ################################################################################################# | ||
495 | 590 | ||
496 | /* | 591 | /* |
497 | * [val [, ...]] = linda_get( linda_ud, key_num|str|bool|lightuserdata [, count = 1]) | 592 | * [val [, ...]] = linda_get( linda_ud, key_num|str|bool|lightuserdata [, count = 1]) |
@@ -500,7 +595,7 @@ LUAG_FUNC( linda_count) | |||
500 | */ | 595 | */ |
501 | LUAG_FUNC( linda_get) | 596 | LUAG_FUNC( linda_get) |
502 | { | 597 | { |
503 | struct s_Linda* const linda = lua_toLinda( L, 1); | 598 | Linda* const linda{ lua_toLinda<false>(L, 1) }; |
504 | int pushed; | 599 | int pushed; |
505 | lua_Integer count = luaL_optinteger( L, 3, 1); | 600 | lua_Integer count = luaL_optinteger( L, 3, 1); |
506 | luaL_argcheck( L, count >= 1, 3, "count should be >= 1"); | 601 | luaL_argcheck( L, count >= 1, 3, "count should be >= 1"); |
@@ -509,7 +604,7 @@ LUAG_FUNC( linda_get) | |||
509 | // make sure the key is of a valid type (throws an error if not the case) | 604 | // make sure the key is of a valid type (throws an error if not the case) |
510 | check_key_types( L, 2, 2); | 605 | check_key_types( L, 2, 2); |
511 | { | 606 | { |
512 | Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); | 607 | Keeper* const K{ which_keeper(linda->U->keepers, linda->hashSeed()) }; |
513 | 608 | ||
514 | if (linda->simulate_cancel == CancelRequest::None) | 609 | if (linda->simulate_cancel == CancelRequest::None) |
515 | { | 610 | { |
@@ -535,6 +630,7 @@ LUAG_FUNC( linda_get) | |||
535 | return pushed; | 630 | return pushed; |
536 | } | 631 | } |
537 | 632 | ||
633 | // ################################################################################################# | ||
538 | 634 | ||
539 | /* | 635 | /* |
540 | * [true] = linda_limit( linda_ud, key_num|str|bool|lightuserdata, int) | 636 | * [true] = linda_limit( linda_ud, key_num|str|bool|lightuserdata, int) |
@@ -544,7 +640,7 @@ LUAG_FUNC( linda_get) | |||
544 | */ | 640 | */ |
545 | LUAG_FUNC( linda_limit) | 641 | LUAG_FUNC( linda_limit) |
546 | { | 642 | { |
547 | struct s_Linda* linda = lua_toLinda( L, 1); | 643 | Linda* const linda{ lua_toLinda<false>(L, 1) }; |
548 | int pushed; | 644 | int pushed; |
549 | 645 | ||
550 | // make sure we got 3 arguments: the linda, a key and a limit | 646 | // make sure we got 3 arguments: the linda, a key and a limit |
@@ -555,7 +651,7 @@ LUAG_FUNC( linda_limit) | |||
555 | check_key_types( L, 2, 2); | 651 | check_key_types( L, 2, 2); |
556 | 652 | ||
557 | { | 653 | { |
558 | Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); | 654 | Keeper* const K{ which_keeper(linda->U->keepers, linda->hashSeed()) }; |
559 | 655 | ||
560 | if (linda->simulate_cancel == CancelRequest::None) | 656 | if (linda->simulate_cancel == CancelRequest::None) |
561 | { | 657 | { |
@@ -578,6 +674,7 @@ LUAG_FUNC( linda_limit) | |||
578 | return pushed; | 674 | return pushed; |
579 | } | 675 | } |
580 | 676 | ||
677 | // ################################################################################################# | ||
581 | 678 | ||
582 | /* | 679 | /* |
583 | * (void) = linda_cancel( linda_ud, "read"|"write"|"both"|"none") | 680 | * (void) = linda_cancel( linda_ud, "read"|"write"|"both"|"none") |
@@ -586,7 +683,7 @@ LUAG_FUNC( linda_limit) | |||
586 | */ | 683 | */ |
587 | LUAG_FUNC( linda_cancel) | 684 | LUAG_FUNC( linda_cancel) |
588 | { | 685 | { |
589 | struct s_Linda* linda = lua_toLinda( L, 1); | 686 | Linda* const linda{ lua_toLinda<false>(L, 1) }; |
590 | char const* who = luaL_optstring( L, 2, "both"); | 687 | char const* who = luaL_optstring( L, 2, "both"); |
591 | 688 | ||
592 | // make sure we got 3 arguments: the linda, a key and a limit | 689 | // make sure we got 3 arguments: the linda, a key and a limit |
@@ -617,6 +714,7 @@ LUAG_FUNC( linda_cancel) | |||
617 | return 0; | 714 | return 0; |
618 | } | 715 | } |
619 | 716 | ||
717 | // ################################################################################################# | ||
620 | 718 | ||
621 | /* | 719 | /* |
622 | * lightuserdata= linda_deep( linda_ud ) | 720 | * lightuserdata= linda_deep( linda_ud ) |
@@ -630,11 +728,12 @@ LUAG_FUNC( linda_cancel) | |||
630 | */ | 728 | */ |
631 | LUAG_FUNC( linda_deep) | 729 | LUAG_FUNC( linda_deep) |
632 | { | 730 | { |
633 | struct s_Linda* linda= lua_toLinda( L, 1); | 731 | Linda* const linda{ lua_toLinda<false>(L, 1) }; |
634 | lua_pushlightuserdata( L, linda); // just the address | 732 | lua_pushlightuserdata( L, linda); // just the address |
635 | return 1; | 733 | return 1; |
636 | } | 734 | } |
637 | 735 | ||
736 | // ################################################################################################# | ||
638 | 737 | ||
639 | /* | 738 | /* |
640 | * string = linda:__tostring( linda_ud) | 739 | * string = linda:__tostring( linda_ud) |
@@ -644,19 +743,16 @@ LUAG_FUNC( linda_deep) | |||
644 | * Useful for concatenation or debugging purposes | 743 | * Useful for concatenation or debugging purposes |
645 | */ | 744 | */ |
646 | 745 | ||
647 | static int linda_tostring( lua_State* L, int idx_, bool opt_) | 746 | template <bool OPT> |
747 | static int linda_tostring(lua_State* L, int idx_) | ||
648 | { | 748 | { |
649 | struct s_Linda* linda = (struct s_Linda*) luaG_todeep( L, linda_id, idx_); | 749 | Linda* const linda{ lua_toLinda<OPT>(L, idx_) }; |
650 | if( !opt_) | ||
651 | { | ||
652 | luaL_argcheck( L, linda, idx_, "expecting a linda object"); | ||
653 | } | ||
654 | if( linda != nullptr) | 750 | if( linda != nullptr) |
655 | { | 751 | { |
656 | char text[128]; | 752 | char text[128]; |
657 | int len; | 753 | int len; |
658 | if( linda->name[0]) | 754 | if( linda->getName()) |
659 | len = sprintf( text, "Linda: %.*s", (int)sizeof(text) - 8, linda->name); | 755 | len = sprintf( text, "Linda: %.*s", (int)sizeof(text) - 8, linda->getName()); |
660 | else | 756 | else |
661 | len = sprintf( text, "Linda: %p", linda); | 757 | len = sprintf( text, "Linda: %p", linda); |
662 | lua_pushlstring( L, text, len); | 758 | lua_pushlstring( L, text, len); |
@@ -667,9 +763,10 @@ static int linda_tostring( lua_State* L, int idx_, bool opt_) | |||
667 | 763 | ||
668 | LUAG_FUNC( linda_tostring) | 764 | LUAG_FUNC( linda_tostring) |
669 | { | 765 | { |
670 | return linda_tostring( L, 1, false); | 766 | return linda_tostring<false>(L, 1); |
671 | } | 767 | } |
672 | 768 | ||
769 | // ################################################################################################# | ||
673 | 770 | ||
674 | /* | 771 | /* |
675 | * string = linda:__concat( a, b) | 772 | * string = linda:__concat( a, b) |
@@ -682,12 +779,12 @@ LUAG_FUNC( linda_concat) | |||
682 | { // linda1? linda2? | 779 | { // linda1? linda2? |
683 | bool atLeastOneLinda{ false }; | 780 | bool atLeastOneLinda{ false }; |
684 | // Lua semantics enforce that one of the 2 arguments is a Linda, but not necessarily both. | 781 | // Lua semantics enforce that one of the 2 arguments is a Linda, but not necessarily both. |
685 | if( linda_tostring( L, 1, true)) | 782 | if( linda_tostring<true>( L, 1)) |
686 | { | 783 | { |
687 | atLeastOneLinda = true; | 784 | atLeastOneLinda = true; |
688 | lua_replace( L, 1); | 785 | lua_replace( L, 1); |
689 | } | 786 | } |
690 | if( linda_tostring( L, 2, true)) | 787 | if( linda_tostring<true>( L, 2)) |
691 | { | 788 | { |
692 | atLeastOneLinda = true; | 789 | atLeastOneLinda = true; |
693 | lua_replace( L, 2); | 790 | lua_replace( L, 2); |
@@ -700,15 +797,16 @@ LUAG_FUNC( linda_concat) | |||
700 | return 1; | 797 | return 1; |
701 | } | 798 | } |
702 | 799 | ||
800 | // ################################################################################################# | ||
801 | |||
703 | /* | 802 | /* |
704 | * table = linda:dump() | 803 | * table = linda:dump() |
705 | * return a table listing all pending data inside the linda | 804 | * return a table listing all pending data inside the linda |
706 | */ | 805 | */ |
707 | LUAG_FUNC( linda_dump) | 806 | LUAG_FUNC( linda_dump) |
708 | { | 807 | { |
709 | struct s_Linda* linda = lua_toLinda( L, 1); | 808 | Linda* const linda{ lua_toLinda<false>(L, 1) }; |
710 | ASSERT_L( linda->U == universe_get( L)); | 809 | return keeper_push_linda_storage(linda->U, L, linda, linda->hashSeed()); |
711 | return keeper_push_linda_storage( linda->U, L, linda, LINDA_KEEPER_HASHSEED( linda)); | ||
712 | } | 810 | } |
713 | 811 | ||
714 | /* | 812 | /* |
@@ -717,14 +815,12 @@ LUAG_FUNC( linda_dump) | |||
717 | */ | 815 | */ |
718 | LUAG_FUNC( linda_towatch) | 816 | LUAG_FUNC( linda_towatch) |
719 | { | 817 | { |
720 | struct s_Linda* linda = lua_toLinda( L, 1); | 818 | Linda* const linda{ lua_toLinda<false>(L, 1) }; |
721 | int pushed; | 819 | int pushed{ keeper_push_linda_storage(linda->U, L, linda, linda->hashSeed()) }; |
722 | ASSERT_L( linda->U == universe_get( L)); | 820 | if (pushed == 0) |
723 | pushed = keeper_push_linda_storage( linda->U, L, linda, LINDA_KEEPER_HASHSEED( linda)); | ||
724 | if( pushed == 0) | ||
725 | { | 821 | { |
726 | // if the linda is empty, don't return nil | 822 | // if the linda is empty, don't return nil |
727 | pushed = linda_tostring( L, 1, false); | 823 | pushed = linda_tostring<false>(L, 1); |
728 | } | 824 | } |
729 | return pushed; | 825 | return pushed; |
730 | } | 826 | } |
@@ -791,28 +887,21 @@ static void* linda_id( lua_State* L, DeepOp op_) | |||
791 | * just don't use L's allocF because we don't know which state will get the honor of GCing the linda | 887 | * just don't use L's allocF because we don't know which state will get the honor of GCing the linda |
792 | */ | 888 | */ |
793 | Universe* const U{ universe_get(L) }; | 889 | Universe* const U{ universe_get(L) }; |
794 | struct s_Linda* s{ static_cast<struct s_Linda*>(U->internal_allocator.alloc(sizeof(struct s_Linda) + name_len)) }; // terminating 0 is already included | 890 | Linda* s{ static_cast<Linda*>(U->internal_allocator.alloc(sizeof(Linda))) }; // terminating 0 is already included |
795 | if (s) | 891 | if (s) |
796 | { | 892 | { |
797 | s->prelude.DeepPrelude::DeepPrelude(); | 893 | s->Linda::Linda(U, linda_group, linda_name, name_len); |
798 | SIGNAL_INIT( &s->read_happened); | ||
799 | SIGNAL_INIT( &s->write_happened); | ||
800 | s->U = U; | ||
801 | s->simulate_cancel = CancelRequest::None; | ||
802 | s->group = linda_group << KEEPER_MAGIC_SHIFT; | ||
803 | s->name[0] = 0; | ||
804 | memcpy( s->name, linda_name, name_len ? name_len + 1 : 0); | ||
805 | } | 894 | } |
806 | return s; | 895 | return s; |
807 | } | 896 | } |
808 | 897 | ||
809 | case eDO_delete: | 898 | case eDO_delete: |
810 | { | 899 | { |
811 | struct s_Linda* const linda{ lua_tolightuserdata<struct s_Linda>(L, 1) }; | 900 | Linda* const linda{ lua_tolightuserdata<Linda>(L, 1) }; |
812 | ASSERT_L( linda); | 901 | ASSERT_L( linda); |
813 | 902 | ||
814 | // Clean associated structures in the keeper state. | 903 | // Clean associated structures in the keeper state. |
815 | Keeper* const K{ keeper_acquire(linda->U->keepers, LINDA_KEEPER_HASHSEED(linda)) }; | 904 | Keeper* const K{ keeper_acquire(linda->U->keepers, linda->hashSeed()) }; |
816 | if( K && K->L) // can be nullptr if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup) | 905 | if( K && K->L) // can be nullptr if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup) |
817 | { | 906 | { |
818 | // hopefully this won't ever raise an error as we would jump to the closest pcall site while forgetting to release the keeper mutex... | 907 | // hopefully this won't ever raise an error as we would jump to the closest pcall site while forgetting to release the keeper mutex... |
@@ -820,11 +909,8 @@ static void* linda_id( lua_State* L, DeepOp op_) | |||
820 | } | 909 | } |
821 | keeper_release( K); | 910 | keeper_release( K); |
822 | 911 | ||
823 | // There aren't any lanes waiting on these lindas, since all proxies have been gc'ed. Right? | 912 | linda->Linda::~Linda(); |
824 | SIGNAL_FREE( &linda->read_happened); | 913 | linda->U->internal_allocator.free(linda, sizeof(Linda)); |
825 | SIGNAL_FREE( &linda->write_happened); | ||
826 | linda->prelude.DeepPrelude::~DeepPrelude(); | ||
827 | linda->U->internal_allocator.free(linda, sizeof(struct s_Linda) + strlen(linda->name)); | ||
828 | return nullptr; | 914 | return nullptr; |
829 | } | 915 | } |
830 | 916 | ||
diff --git a/tests/fifo.lua b/tests/fifo.lua index 3d6e140..498f540 100644 --- a/tests/fifo.lua +++ b/tests/fifo.lua | |||
@@ -52,7 +52,7 @@ for key,count in pairs(fifo_linda:count(A.channel, B.channel)) do | |||
52 | print("channel " .. key .. " contains " .. count .. " entries.") | 52 | print("channel " .. key .. " contains " .. count .. " entries.") |
53 | -- print(i, key_count[1], key_count[2]) | 53 | -- print(i, key_count[1], key_count[2]) |
54 | end | 54 | end |
55 | print "Dumping linda stats.. [3]" -- count everything | 55 | print "Dumping linda stats.. [4]" -- count everything |
56 | for key,contents in pairs(fifo_linda:dump()) do | 56 | for key,contents in pairs(fifo_linda:dump()) do |
57 | print("channel " .. key .. ": limit=".. contents.limit, " first=" .. contents.first, " count=" .. contents.count) | 57 | print("channel " .. key .. ": limit=".. contents.limit, " first=" .. contents.first, " count=" .. contents.count) |
58 | for k,v in pairs(contents.fifo) do | 58 | for k,v in pairs(contents.fifo) do |
diff --git a/tests/keeper.lua b/tests/keeper.lua index 11bbe17..9b38f02 100644 --- a/tests/keeper.lua +++ b/tests/keeper.lua | |||
@@ -6,6 +6,14 @@ | |||
6 | 6 | ||
7 | local lanes = require "lanes".configure{ with_timers = false, nb_keepers = 200} | 7 | local lanes = require "lanes".configure{ with_timers = false, nb_keepers = 200} |
8 | 8 | ||
9 | do | ||
10 | print "Linda names test:" | ||
11 | local unnamedLinda = lanes.linda() | ||
12 | local unnamedLinda2 = lanes.linda("") | ||
13 | local veeeerrrryyyylooongNamedLinda= lanes.linda( "veeeerrrryyyylooongNamedLinda", 1) | ||
14 | print(unnamedLinda, unnamedLinda2, veeeerrrryyyylooongNamedLinda) | ||
15 | end | ||
16 | |||
9 | local print_id = 0 | 17 | local print_id = 0 |
10 | local PRINT = function(...) | 18 | local PRINT = function(...) |
11 | print_id = print_id + 1 | 19 | print_id = print_id + 1 |
@@ -33,6 +41,7 @@ local B= keeper( lindaB ) | |||
33 | 41 | ||
34 | local lindaC= lanes.linda( "C", 3) | 42 | local lindaC= lanes.linda( "C", 3) |
35 | local C= keeper( lindaC ) | 43 | local C= keeper( lindaC ) |
44 | print("Created", lindaA, lindaB, lindaC) | ||
36 | 45 | ||
37 | A.some= 1 | 46 | A.some= 1 |
38 | PRINT("A.some == " .. A.some ) | 47 | PRINT("A.some == " .. A.some ) |