diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cancel.cpp | 2 | ||||
-rw-r--r-- | src/compat.hpp | 10 | ||||
-rw-r--r-- | src/keeper.cpp | 145 | ||||
-rw-r--r-- | src/keeper.hpp | 14 | ||||
-rw-r--r-- | src/lanes.lua | 1 | ||||
-rw-r--r-- | src/linda.cpp | 104 |
6 files changed, 239 insertions, 37 deletions
diff --git a/src/cancel.cpp b/src/cancel.cpp index 8fa68d5..31656c4 100644 --- a/src/cancel.cpp +++ b/src/cancel.cpp | |||
@@ -164,7 +164,7 @@ LUAG_FUNC(lane_cancel) | |||
164 | raise_luaL_argerror(L_, StackIndex{ 2 }, "duration cannot be < 0"); | 164 | raise_luaL_argerror(L_, StackIndex{ 2 }, "duration cannot be < 0"); |
165 | } | 165 | } |
166 | lua_remove(L_, 2); // argument is processed, remove it | 166 | lua_remove(L_, 2); // argument is processed, remove it |
167 | } else if (lua_isnil(L_, 2)) { // alternate explicit "infinite timeout" by passing nil before the key | 167 | } else if (lua_isnil(L_, 2)) { // alternate explicit "infinite timeout" by passing nil |
168 | lua_remove(L_, 2); // argument is processed, remove it | 168 | lua_remove(L_, 2); // argument is processed, remove it |
169 | } | 169 | } |
170 | 170 | ||
diff --git a/src/compat.hpp b/src/compat.hpp index f66f703..81f1665 100644 --- a/src/compat.hpp +++ b/src/compat.hpp | |||
@@ -272,6 +272,16 @@ LuaType luaG_getmodule(lua_State* L_, std::string_view const& name_); | |||
272 | 272 | ||
273 | // ################################################################################################# | 273 | // ################################################################################################# |
274 | 274 | ||
275 | template<typename ENUM> | ||
276 | requires std::is_enum_v<ENUM> | ||
277 | [[nodiscard]] | ||
278 | ENUM luaG_optenum(lua_State* const L_, StackIndex const idx_, ENUM const def_) | ||
279 | { | ||
280 | return static_cast<ENUM>(luaL_optinteger(L_, idx_, static_cast<std::underlying_type_t<ENUM>>(def_))); | ||
281 | } | ||
282 | |||
283 | // ################################################################################################# | ||
284 | |||
275 | inline void luaG_registerlibfuncs(lua_State* L_, luaL_Reg const* funcs_) | 285 | inline void luaG_registerlibfuncs(lua_State* L_, luaL_Reg const* funcs_) |
276 | { | 286 | { |
277 | // fake externs to make clang happy... | 287 | // fake externs to make clang happy... |
diff --git a/src/keeper.cpp b/src/keeper.cpp index 8a99a36..e7b02e6 100644 --- a/src/keeper.cpp +++ b/src/keeper.cpp | |||
@@ -73,6 +73,7 @@ class KeyUD | |||
73 | int first{ 1 }; | 73 | int first{ 1 }; |
74 | int count{ 0 }; | 74 | int count{ 0 }; |
75 | LindaLimit limit{ -1 }; | 75 | LindaLimit limit{ -1 }; |
76 | LindaRestrict restrict { LindaRestrict::None }; | ||
76 | 77 | ||
77 | // a fifo full userdata has one uservalue, the table that holds the actual fifo contents | 78 | // a fifo full userdata has one uservalue, the table that holds the actual fifo contents |
78 | [[nodiscard]] | 79 | [[nodiscard]] |
@@ -84,6 +85,8 @@ class KeyUD | |||
84 | [[nodiscard]] | 85 | [[nodiscard]] |
85 | bool changeLimit(LindaLimit limit_); | 86 | bool changeLimit(LindaLimit limit_); |
86 | [[nodiscard]] | 87 | [[nodiscard]] |
88 | LindaRestrict changeRestrict(LindaRestrict restrict_); | ||
89 | [[nodiscard]] | ||
87 | static KeyUD* Create(KeeperState K_); | 90 | static KeyUD* Create(KeeperState K_); |
88 | [[nodiscard]] | 91 | [[nodiscard]] |
89 | static KeyUD* GetPtr(KeeperState K_, StackIndex idx_); | 92 | static KeyUD* GetPtr(KeeperState K_, StackIndex idx_); |
@@ -114,6 +117,14 @@ bool KeyUD::changeLimit(LindaLimit const limit_) | |||
114 | 117 | ||
115 | // ################################################################################################# | 118 | // ################################################################################################# |
116 | 119 | ||
120 | [[nodiscard]] | ||
121 | LindaRestrict KeyUD::changeRestrict(LindaRestrict const restrict_) | ||
122 | { | ||
123 | return std::exchange(restrict, restrict_); | ||
124 | } | ||
125 | |||
126 | // ################################################################################################# | ||
127 | |||
117 | // in: nothing | 128 | // in: nothing |
118 | // out: { first = 1, count = 0, limit = -1} | 129 | // out: { first = 1, count = 0, limit = -1} |
119 | KeyUD* KeyUD::Create(KeeperState const K_) | 130 | KeyUD* KeyUD::Create(KeeperState const K_) |
@@ -280,7 +291,7 @@ bool KeyUD::reset(KeeperState const K_) | |||
280 | LUA_ASSERT(K_, KeyUD::GetPtr(K_, kIdxTop) == this); | 291 | LUA_ASSERT(K_, KeyUD::GetPtr(K_, kIdxTop) == this); |
281 | STACK_CHECK_START_REL(K_, 0); | 292 | STACK_CHECK_START_REL(K_, 0); |
282 | bool const _wasFull{ (limit > 0) && (count >= limit) }; | 293 | bool const _wasFull{ (limit > 0) && (count >= limit) }; |
283 | // empty the KeyUD: replace uservalue with a virgin table, reset counters, but leave limit unchanged! | 294 | // empty the KeyUD: replace uservalue with a virgin table, reset counters, but leave limit and restrict unchanged! |
284 | // if we have an actual limit, use it to preconfigure the table | 295 | // if we have an actual limit, use it to preconfigure the table |
285 | lua_createtable(K_, (limit <= 0) ? 0 : limit.value(), 0); // K_: KeysDB key val... KeyUD {} | 296 | lua_createtable(K_, (limit <= 0) ? 0 : limit.value(), 0); // K_: KeysDB key val... KeyUD {} |
286 | lua_setiuservalue(K_, StackIndex{ -2 }, kContentsTableIndex); // K_: KeysDB key val... KeyUD | 297 | lua_setiuservalue(K_, StackIndex{ -2 }, kContentsTableIndex); // K_: KeysDB key val... KeyUD |
@@ -408,7 +419,7 @@ int keepercall_destruct(lua_State* const L_) | |||
408 | // ################################################################################################# | 419 | // ################################################################################################# |
409 | 420 | ||
410 | // in: linda_ud key [count] | 421 | // in: linda_ud key [count] |
411 | // out: bool + at most <count> values | 422 | // out: N <N values>|kRestrictedChannel |
412 | int keepercall_get(lua_State* const L_) | 423 | int keepercall_get(lua_State* const L_) |
413 | { | 424 | { |
414 | KeeperState const _K{ L_ }; | 425 | KeeperState const _K{ L_ }; |
@@ -423,7 +434,13 @@ int keepercall_get(lua_State* const L_) | |||
423 | lua_remove(_K, 1); // _K: KeyUD | 434 | lua_remove(_K, 1); // _K: KeyUD |
424 | KeyUD const* const _key{ KeyUD::GetPtr(_K, kIdxTop) }; | 435 | KeyUD const* const _key{ KeyUD::GetPtr(_K, kIdxTop) }; |
425 | if (_key != nullptr) { | 436 | if (_key != nullptr) { |
426 | _key->peek(_K, _count); // _K: N val... | 437 | if (_key->restrict == LindaRestrict::SendReceive) { // can we use set/get? |
438 | lua_settop(_K, 0); // _K: | ||
439 | kRestrictedChannel.pushKey(_K); // _K: kRestrictedChannel | ||
440 | return 1; | ||
441 | } else { | ||
442 | _key->peek(_K, _count); // _K: N val... | ||
443 | } | ||
427 | } else { | 444 | } else { |
428 | // no fifo was ever registered for this key, or it is empty | 445 | // no fifo was ever registered for this key, or it is empty |
429 | lua_pop(_K, 1); // _K: | 446 | lua_pop(_K, 1); // _K: |
@@ -492,6 +509,17 @@ int keepercall_receive(lua_State* const L_) | |||
492 | lua_rawget(_K, 1); // _K: KeysDB keys... KeyUD | 509 | lua_rawget(_K, 1); // _K: KeysDB keys... KeyUD |
493 | KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) }; | 510 | KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) }; |
494 | if (_key != nullptr) { // it's fine to attempt a read on a key that wasn't yet written to | 511 | if (_key != nullptr) { // it's fine to attempt a read on a key that wasn't yet written to |
512 | if (_key->restrict == LindaRestrict::SetGet) { // can we use send/receive? | ||
513 | kRestrictedChannel.pushKey(_K); // _K: KeysDB keys... key[i] kRestrictedChannel | ||
514 | lua_replace(_K, 1); // _K: kRestrictedChannel keys... key[i] | ||
515 | lua_settop(_K, _keyIdx); // _K: kRestrictedChannel keys... key[i] | ||
516 | if (_keyIdx != 2) { | ||
517 | lua_replace(_K, 2); // _K: kRestrictedChannel key[i] keys... | ||
518 | lua_settop(_K, 2); // _K: kRestrictedChannel key[i] | ||
519 | } | ||
520 | lua_insert(_K, 1); // _K: key kRestrictedChannel | ||
521 | return 2; | ||
522 | } | ||
495 | int const _popped{ _key->pop(_K, 1, 1) }; // _K: KeysDB keys... val | 523 | int const _popped{ _key->pop(_K, 1, 1) }; // _K: KeysDB keys... val |
496 | if (_popped > 0) { | 524 | if (_popped > 0) { |
497 | lua_replace(_K, 1); // _K: val keys... | 525 | lua_replace(_K, 1); // _K: val keys... |
@@ -527,19 +555,89 @@ int keepercall_receive_batched(lua_State* const L_) | |||
527 | lua_rawget(_K, 2); // _K: key KeysDB KeyUD | 555 | lua_rawget(_K, 2); // _K: key KeysDB KeyUD |
528 | lua_remove(_K, 2); // _K: key KeyUD | 556 | lua_remove(_K, 2); // _K: key KeyUD |
529 | KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) }; | 557 | KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) }; |
530 | if (_key == nullptr || _key->pop(_K, _min_count, _max_count) == 0) { // _K: [key val...]|crap | 558 | if (!_key) { |
531 | // Lua will adjust the stack for us when we return | 559 | return 0; // Lua will adjust the stack for us when we return |
532 | return 0; | 560 | } |
561 | if (_key->restrict == LindaRestrict::SetGet) { // can we use send/receive? | ||
562 | lua_settop(_K, 1); // _K: key | ||
563 | kRestrictedChannel.pushKey(_K); // _K: key kRestrictedChannel | ||
564 | return 2; | ||
565 | } | ||
566 | if (_key->pop(_K, _min_count, _max_count) == 0) { // _K: [key val...]|crap | ||
567 | return 0; // Lua will adjust the stack for us when we return | ||
568 | } | ||
569 | // return whatever remains on the stack at that point: the key and the values we pulled from the fifo | ||
570 | return lua_gettop(_K); | ||
571 | } | ||
572 | |||
573 | // ################################################################################################# | ||
574 | |||
575 | // in: linda key [mode] | ||
576 | // out: mode | ||
577 | int keepercall_restrict(lua_State* const L_) | ||
578 | { | ||
579 | KeeperState const _K{ L_ }; | ||
580 | STACK_CHECK_START_ABS(_K, lua_gettop(_K)); | ||
581 | // no restriction to set, means we read and return the current restriction instead | ||
582 | bool const _reading{ lua_gettop(_K) == 2 }; | ||
583 | auto _decodeRestrict = [_K, _reading]() { | ||
584 | if (_reading) { | ||
585 | return LindaRestrict::None; | ||
586 | } | ||
587 | std::string_view const _val{ luaG_tostring(_K, StackIndex{ 3 }) }; | ||
588 | if (_val == "set/get") { | ||
589 | return LindaRestrict::SetGet; | ||
590 | } | ||
591 | if (_val == "send/receive") { | ||
592 | return LindaRestrict::SendReceive; | ||
593 | } | ||
594 | return LindaRestrict::None; | ||
595 | }; | ||
596 | auto _encodeRestrict = [](LindaRestrict const val_) { | ||
597 | switch (val_) { | ||
598 | default: | ||
599 | case LindaRestrict::None: | ||
600 | return std::string_view{ "none" }; | ||
601 | case LindaRestrict::SetGet: | ||
602 | return std::string_view{ "set/get" }; | ||
603 | case LindaRestrict::SendReceive: | ||
604 | return std::string_view{ "send/receive" }; | ||
605 | } | ||
606 | }; | ||
607 | LindaRestrict const _rstrct{ _decodeRestrict() }; // if we read nil because the argument is absent | ||
608 | lua_settop(_K, 2); // _K: linda key | ||
609 | PushKeysDB(_K, StackIndex{ 1 }); // _K: linda key KeysDB | ||
610 | lua_replace(_K, 1); // _K: KeysDB key | ||
611 | lua_pushvalue(_K, -1); // _K: KeysDB key key | ||
612 | lua_rawget(_K, -3); // _K: KeysDB key KeyUD|nil | ||
613 | KeyUD* _key{ KeyUD::GetPtr(_K, kIdxTop) }; | ||
614 | if (_reading) { | ||
615 | // remove any clutter on the stack | ||
616 | lua_settop(_K, 0); // _K: | ||
617 | auto const _prevRstrct{ _key ? _key->restrict : LindaRestrict::None }; | ||
618 | // return a single value: the restrict mode of the key | ||
619 | luaG_pushstring(_K, _encodeRestrict(_prevRstrct)); // _K: _previous | ||
533 | } else { | 620 | } else { |
534 | // return whatever remains on the stack at that point: the key and the values we pulled from the fifo | 621 | if (_key == nullptr) { // _K: KeysDB key nil |
535 | return lua_gettop(_K); | 622 | lua_pop(_K, 1); // _K: KeysDB key |
623 | _key = KeyUD::Create(_K); // _K: KeysDB key KeyUD | ||
624 | lua_rawset(_K, -3); // _K: KeysDB | ||
625 | } | ||
626 | // remove any clutter on the stack | ||
627 | lua_settop(_K, 0); // _K: | ||
628 | // return true if we decide that blocked threads waiting to write on that key should be awakened | ||
629 | // this is the case if we detect the key was full but it is no longer the case | ||
630 | LindaRestrict const _previous{ _key->changeRestrict(_rstrct) }; | ||
631 | luaG_pushstring(_K, _encodeRestrict(_previous)); // _K: _previous | ||
536 | } | 632 | } |
633 | STACK_CHECK(_K, 1); | ||
634 | return 1; | ||
537 | } | 635 | } |
538 | 636 | ||
539 | // ################################################################################################# | 637 | // ################################################################################################# |
540 | 638 | ||
541 | // in: linda, key, ... | 639 | // in: linda, key, ... |
542 | // out: true|false | 640 | // out: true|false|kRestrictedChannel |
543 | int keepercall_send(lua_State* const L_) | 641 | int keepercall_send(lua_State* const L_) |
544 | { | 642 | { |
545 | KeeperState const _K{ L_ }; | 643 | KeeperState const _K{ L_ }; |
@@ -561,7 +659,11 @@ int keepercall_send(lua_State* const L_) | |||
561 | lua_pop(_K, 1); // _K: linda KeyUD val... | 659 | lua_pop(_K, 1); // _K: linda KeyUD val... |
562 | STACK_CHECK(_K, 0); | 660 | STACK_CHECK(_K, 0); |
563 | KeyUD* const _key{ KeyUD::GetPtr(_K, StackIndex{ 2 }) }; | 661 | KeyUD* const _key{ KeyUD::GetPtr(_K, StackIndex{ 2 }) }; |
564 | if (_key && _key->push(_K, _n, true)) { // not enough room? | 662 | if (_key->restrict == LindaRestrict::SetGet) { // can we use send/receive? |
663 | lua_settop(_K, 0); // _K: | ||
664 | kRestrictedChannel.pushKey(_K); // _K: kRestrictedChannel | ||
665 | } | ||
666 | else if (_key->push(_K, _n, true)) { // not enough room? | ||
565 | lua_settop(_K, 0); // _K: | 667 | lua_settop(_K, 0); // _K: |
566 | lua_pushboolean(_K, 1); // _K: true | 668 | lua_pushboolean(_K, 1); // _K: true |
567 | } else { | 669 | } else { |
@@ -575,7 +677,7 @@ int keepercall_send(lua_State* const L_) | |||
575 | // ################################################################################################# | 677 | // ################################################################################################# |
576 | 678 | ||
577 | // in: linda key [val...] | 679 | // in: linda key [val...] |
578 | // out: true if the linda was full but it's no longer the case, else false | 680 | // out: true if the linda was full but it's no longer the case, else false, or kRestrictedChannel if the key is restricted |
579 | int keepercall_set(lua_State* const L_) | 681 | int keepercall_set(lua_State* const L_) |
580 | { | 682 | { |
581 | KeeperState const _K{ L_ }; | 683 | KeeperState const _K{ L_ }; |
@@ -588,11 +690,16 @@ int keepercall_set(lua_State* const L_) | |||
588 | lua_pushvalue(_K, 2); // _K: KeysDB key val... key | 690 | lua_pushvalue(_K, 2); // _K: KeysDB key val... key |
589 | lua_rawget(_K, 1); // _K: KeysDB key val KeyUD|nil | 691 | lua_rawget(_K, 1); // _K: KeysDB key val KeyUD|nil |
590 | KeyUD* _key{ KeyUD::GetPtr(_K, kIdxTop) }; | 692 | KeyUD* _key{ KeyUD::GetPtr(_K, kIdxTop) }; |
693 | if (_key && _key->restrict == LindaRestrict::SendReceive) { // can we use send/receive? | ||
694 | lua_settop(_K, 0); // _K: | ||
695 | kRestrictedChannel.pushKey(_K); // _K: kRestrictedChannel | ||
696 | return 1; | ||
697 | } | ||
591 | 698 | ||
592 | if (lua_gettop(_K) == 3) { // no value to set // _K: KeysDB key KeyUD|nil | 699 | if (lua_gettop(_K) == 3) { // no value to set // _K: KeysDB key KeyUD|nil |
593 | // empty the KeyUD for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! | 700 | // empty the KeyUD for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! |
594 | if (_key != nullptr) { // might be nullptr if we set a nonexistent key to nil // _K: KeysDB key KeyUD | 701 | if (_key != nullptr) { // might be nullptr if we set a nonexistent key to nil // _K: KeysDB key KeyUD |
595 | if (_key->limit < 0) { // KeyUD limit value is the default (unlimited): we can totally remove it | 702 | if (_key->limit < 0 && _key->restrict == LindaRestrict::None) { // KeyUD limit value and restrict mode are the default (unlimited/none): we can totally remove it |
596 | lua_pop(_K, 1); // _K: KeysDB key | 703 | lua_pop(_K, 1); // _K: KeysDB key |
597 | lua_pushnil(_K); // _K: KeysDB key nil | 704 | lua_pushnil(_K); // _K: KeysDB key nil |
598 | lua_rawset(_K, -3); // _K: KeysDB | 705 | lua_rawset(_K, -3); // _K: KeysDB |
@@ -777,6 +884,20 @@ int Keeper::PushLindaStorage(Linda& linda_, DestState const L_) | |||
777 | } | 884 | } |
778 | STACK_CHECK(L_, 5); | 885 | STACK_CHECK(L_, 5); |
779 | lua_setfield(L_, -3, "limit"); // _K: KeysDB key L_: out key keyout fifo | 886 | lua_setfield(L_, -3, "limit"); // _K: KeysDB key L_: out key keyout fifo |
887 | // keyout.restrict | ||
888 | switch (_key->restrict) { | ||
889 | case LindaRestrict::None: | ||
890 | luaG_pushstring(L_, "none"); // _K: KeysDB key L_: out key keyout fifo restrict | ||
891 | break; | ||
892 | case LindaRestrict::SetGet: | ||
893 | luaG_pushstring(L_, "set/get"); // _K: KeysDB key L_: out key keyout fifo restrict | ||
894 | break; | ||
895 | case LindaRestrict::SendReceive: | ||
896 | luaG_pushstring(L_, "send/receive"); // _K: KeysDB key L_: out key keyout fifo restrict | ||
897 | break; | ||
898 | } | ||
899 | STACK_CHECK(L_, 5); | ||
900 | lua_setfield(L_, -3, "restrict"); // _K: KeysDB key L_: out key keyout fifo | ||
780 | // keyout.fifo | 901 | // keyout.fifo |
781 | lua_setfield(L_, -2, "fifo"); // _K: KeysDB key L_: out key keyout | 902 | lua_setfield(L_, -2, "fifo"); // _K: KeysDB key L_: out key keyout |
782 | // out[key] = keyout | 903 | // out[key] = keyout |
diff --git a/src/keeper.hpp b/src/keeper.hpp index b77f1a9..e2ad445 100644 --- a/src/keeper.hpp +++ b/src/keeper.hpp | |||
@@ -13,6 +13,15 @@ DECLARE_UNIQUE_TYPE(KeeperIndex, int); | |||
13 | 13 | ||
14 | // ################################################################################################# | 14 | // ################################################################################################# |
15 | 15 | ||
16 | enum class LindaRestrict | ||
17 | { | ||
18 | None, | ||
19 | SetGet, | ||
20 | SendReceive | ||
21 | }; | ||
22 | |||
23 | // ################################################################################################# | ||
24 | |||
16 | struct Keeper | 25 | struct Keeper |
17 | { | 26 | { |
18 | std::mutex mutex; | 27 | std::mutex mutex; |
@@ -79,6 +88,9 @@ DECLARE_UNIQUE_TYPE(KeeperCallResult, std::optional<int>); | |||
79 | // xxh64 of string "kNilSentinel" generated at https://www.pelock.com/products/hash-calculator | 88 | // xxh64 of string "kNilSentinel" generated at https://www.pelock.com/products/hash-calculator |
80 | static constexpr UniqueKey kNilSentinel{ 0xC457D4EDDB05B5E4ull, "lanes.null" }; | 89 | static constexpr UniqueKey kNilSentinel{ 0xC457D4EDDB05B5E4ull, "lanes.null" }; |
81 | 90 | ||
91 | // xxh64 of string "kRestrictedChannel" generated at https://www.pelock.com/products/hash-calculator | ||
92 | static constexpr UniqueKey kRestrictedChannel{ 0x4C8B879ECDE110F7ull }; | ||
93 | |||
82 | using keeper_api_t = lua_CFunction; | 94 | using keeper_api_t = lua_CFunction; |
83 | #define KEEPER_API(_op) keepercall_##_op | 95 | #define KEEPER_API(_op) keepercall_##_op |
84 | 96 | ||
@@ -96,6 +108,8 @@ int keepercall_receive(lua_State* L_); | |||
96 | [[nodiscard]] | 108 | [[nodiscard]] |
97 | int keepercall_receive_batched(lua_State* L_); | 109 | int keepercall_receive_batched(lua_State* L_); |
98 | [[nodiscard]] | 110 | [[nodiscard]] |
111 | int keepercall_restrict(lua_State* L_); | ||
112 | [[nodiscard]] | ||
99 | int keepercall_send(lua_State* L_); | 113 | int keepercall_send(lua_State* L_); |
100 | [[nodiscard]] | 114 | [[nodiscard]] |
101 | int keepercall_set(lua_State* L_); | 115 | int keepercall_set(lua_State* L_); |
diff --git a/src/lanes.lua b/src/lanes.lua index dfa959d..8d8f25d 100644 --- a/src/lanes.lua +++ b/src/lanes.lua | |||
@@ -448,6 +448,7 @@ local configure_timers = function() | |||
448 | 448 | ||
449 | -- Timer lane; initialize only on the first 'require "lanes"' instance (which naturally has 'table' always declared) | 449 | -- Timer lane; initialize only on the first 'require "lanes"' instance (which naturally has 'table' always declared) |
450 | local first_time_key = "first time" | 450 | local first_time_key = "first time" |
451 | timerLinda:restrict(first_time_key, "set/get") | ||
451 | local _, _first_time_val = timerLinda:get(first_time_key) | 452 | local _, _first_time_val = timerLinda:get(first_time_key) |
452 | local first_time = (_first_time_val == nil) | 453 | local first_time = (_first_time_val == nil) |
453 | timerLinda:set(first_time_key, true) | 454 | timerLinda:set(first_time_key, true) |
diff --git a/src/linda.cpp b/src/linda.cpp index 43d2a91..6ebbc1f 100644 --- a/src/linda.cpp +++ b/src/linda.cpp | |||
@@ -57,7 +57,7 @@ namespace { | |||
57 | 57 | ||
58 | case LuaType::USERDATA: | 58 | case LuaType::USERDATA: |
59 | if (!DeepFactory::IsDeepUserdata(L_, _i)) { | 59 | if (!DeepFactory::IsDeepUserdata(L_, _i)) { |
60 | raise_luaL_error(L_, "argument #%d: can't use non-deep userdata as a key", _i); | 60 | raise_luaL_error(L_, "argument #%d: can't use non-deep userdata as a slot", _i); |
61 | } | 61 | } |
62 | break; | 62 | break; |
63 | 63 | ||
@@ -66,7 +66,7 @@ namespace { | |||
66 | static constexpr std::array<std::reference_wrapper<UniqueKey const>, 3> kKeysToCheck{ kLindaBatched, kCancelError, kNilSentinel }; | 66 | static constexpr std::array<std::reference_wrapper<UniqueKey const>, 3> kKeysToCheck{ kLindaBatched, kCancelError, kNilSentinel }; |
67 | for (UniqueKey const& _key : kKeysToCheck) { | 67 | for (UniqueKey const& _key : kKeysToCheck) { |
68 | if (_key.equals(L_, _i)) { | 68 | if (_key.equals(L_, _i)) { |
69 | raise_luaL_error(L_, "argument #%d: can't use %s as a key", _i, _key.debugName.data()); | 69 | raise_luaL_error(L_, "argument #%d: can't use %s as a slot", _i, _key.debugName.data()); |
70 | break; | 70 | break; |
71 | } | 71 | } |
72 | } | 72 | } |
@@ -74,7 +74,7 @@ namespace { | |||
74 | break; | 74 | break; |
75 | 75 | ||
76 | default: | 76 | default: |
77 | raise_luaL_error(L_, "argument #%d: invalid key type (not a boolean, string, number or light userdata)", _i); | 77 | raise_luaL_error(L_, "argument #%d: invalid slot type (not a boolean, string, number or light userdata)", _i); |
78 | } | 78 | } |
79 | } | 79 | } |
80 | STACK_CHECK(L_, 0); | 80 | STACK_CHECK(L_, 0); |
@@ -416,7 +416,7 @@ static LUAG_FUNC(linda_index) | |||
416 | // ################################################################################################# | 416 | // ################################################################################################# |
417 | 417 | ||
418 | /* | 418 | /* |
419 | * [val] = linda_count( linda_ud, [key [, ...]]) | 419 | * [val] = linda_count( linda_ud, [slot [, ...]]) |
420 | * | 420 | * |
421 | * Get a count of the pending elements in the specified keys | 421 | * Get a count of the pending elements in the specified keys |
422 | */ | 422 | */ |
@@ -430,7 +430,7 @@ LUAG_FUNC(linda_count) | |||
430 | 430 | ||
431 | Keeper* const _keeper{ _linda->whichKeeper() }; | 431 | Keeper* const _keeper{ _linda->whichKeeper() }; |
432 | KeeperCallResult const _pushed{ keeper_call(_keeper->K, KEEPER_API(count), L_, _linda, StackIndex{ 2 }) }; | 432 | KeeperCallResult const _pushed{ keeper_call(_keeper->K, KEEPER_API(count), L_, _linda, StackIndex{ 2 }) }; |
433 | return OptionalValue(_pushed, L_, "tried to count an invalid key"); | 433 | return OptionalValue(_pushed, L_, "Tried to count an invalid slot"); |
434 | } | 434 | } |
435 | }; | 435 | }; |
436 | return Linda::ProtectedCall(L_, _count); | 436 | return Linda::ProtectedCall(L_, _count); |
@@ -487,13 +487,16 @@ LUAG_FUNC(linda_get) | |||
487 | lua_Integer const _count{ luaL_optinteger(L_, 3, 1) }; | 487 | lua_Integer const _count{ luaL_optinteger(L_, 3, 1) }; |
488 | luaL_argcheck(L_, _count >= 1, 3, "count should be >= 1"); | 488 | luaL_argcheck(L_, _count >= 1, 3, "count should be >= 1"); |
489 | luaL_argcheck(L_, lua_gettop(L_) <= 3, 4, "too many arguments"); | 489 | luaL_argcheck(L_, lua_gettop(L_) <= 3, 4, "too many arguments"); |
490 | // make sure the key is of a valid type (throws an error if not the case) | 490 | // make sure the slot is of a valid type (throws an error if not the case) |
491 | CheckKeyTypes(L_, StackIndex{ 2 }, StackIndex{ 2 }); | 491 | CheckKeyTypes(L_, StackIndex{ 2 }, StackIndex{ 2 }); |
492 | 492 | ||
493 | KeeperCallResult _pushed; | 493 | KeeperCallResult _pushed; |
494 | if (_linda->cancelStatus == Linda::Active) { | 494 | if (_linda->cancelStatus == Linda::Active) { |
495 | Keeper* const _keeper{ _linda->whichKeeper() }; | 495 | Keeper* const _keeper{ _linda->whichKeeper() }; |
496 | _pushed = keeper_call(_keeper->K, KEEPER_API(get), L_, _linda, StackIndex{ 2 }); | 496 | _pushed = keeper_call(_keeper->K, KEEPER_API(get), L_, _linda, StackIndex{ 2 }); |
497 | if (_pushed.has_value() && kRestrictedChannel.equals(L_, kIdxTop)) { | ||
498 | raise_luaL_error(L_, "Key is restricted"); | ||
499 | } | ||
497 | } else { // linda is cancelled | 500 | } else { // linda is cancelled |
498 | // do nothing and return nil,lanes.cancel_error | 501 | // do nothing and return nil,lanes.cancel_error |
499 | lua_pushnil(L_); | 502 | lua_pushnil(L_); |
@@ -511,7 +514,7 @@ LUAG_FUNC(linda_get) | |||
511 | 514 | ||
512 | /* | 515 | /* |
513 | * [bool]|nil,cancel_error = linda:limit(key_num|str|bool|lightuserdata, [int]) | 516 | * [bool]|nil,cancel_error = linda:limit(key_num|str|bool|lightuserdata, [int]) |
514 | * "unlimited"|number = linda:limit(key) | 517 | * "unlimited"|number = linda:limit(slot) |
515 | * | 518 | * |
516 | * Read or set limit to 1 Linda keys. | 519 | * Read or set limit to 1 Linda keys. |
517 | * Optionally wake threads waiting to write on the linda, in case the limit enables them to do so | 520 | * Optionally wake threads waiting to write on the linda, in case the limit enables them to do so |
@@ -522,7 +525,7 @@ LUAG_FUNC(linda_limit) | |||
522 | static constexpr lua_CFunction _limit{ | 525 | static constexpr lua_CFunction _limit{ |
523 | +[](lua_State* const L_) { | 526 | +[](lua_State* const L_) { |
524 | Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) }; | 527 | Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) }; |
525 | // make sure we got 2 or 3 arguments: the linda, a key and optionally a limit | 528 | // make sure we got 2 or 3 arguments: the linda, a slot and optionally a limit |
526 | int const _nargs{ lua_gettop(L_) }; | 529 | int const _nargs{ lua_gettop(L_) }; |
527 | luaL_argcheck(L_, _nargs == 2 || _nargs == 3, 2, "wrong number of arguments"); | 530 | luaL_argcheck(L_, _nargs == 2 || _nargs == 3, 2, "wrong number of arguments"); |
528 | // make sure we got a numeric limit, or "unlimited", (or nothing) | 531 | // make sure we got a numeric limit, or "unlimited", (or nothing) |
@@ -531,7 +534,7 @@ LUAG_FUNC(linda_limit) | |||
531 | if (_val < 0) { | 534 | if (_val < 0) { |
532 | raise_luaL_argerror(L_, StackIndex{ 3 }, "limit must be >= 0"); | 535 | raise_luaL_argerror(L_, StackIndex{ 3 }, "limit must be >= 0"); |
533 | } | 536 | } |
534 | // make sure the key is of a valid type | 537 | // make sure the slot is of a valid type |
535 | CheckKeyTypes(L_, StackIndex{ 2 }, StackIndex{ 2 }); | 538 | CheckKeyTypes(L_, StackIndex{ 2 }, StackIndex{ 2 }); |
536 | 539 | ||
537 | KeeperCallResult _pushed; | 540 | KeeperCallResult _pushed; |
@@ -539,8 +542,8 @@ LUAG_FUNC(linda_limit) | |||
539 | if (_unlimited) { | 542 | if (_unlimited) { |
540 | LUA_ASSERT(L_, lua_gettop(L_) == 3 && luaG_tostring(L_, StackIndex{ 3 }) == "unlimited"); | 543 | LUA_ASSERT(L_, lua_gettop(L_) == 3 && luaG_tostring(L_, StackIndex{ 3 }) == "unlimited"); |
541 | // inside the Keeper, unlimited is signified with a -1 limit (can't use nil because of nil kNilSentinel conversions!) | 544 | // inside the Keeper, unlimited is signified with a -1 limit (can't use nil because of nil kNilSentinel conversions!) |
542 | lua_pop(L_, 1); // L_: linda key | 545 | lua_pop(L_, 1); // L_: linda slot |
543 | lua_pushinteger(L_, -1); // L_: linda key nil | 546 | lua_pushinteger(L_, -1); // L_: linda slot nil |
544 | } | 547 | } |
545 | Keeper* const _keeper{ _linda->whichKeeper() }; | 548 | Keeper* const _keeper{ _linda->whichKeeper() }; |
546 | _pushed = keeper_call(_keeper->K, KEEPER_API(limit), L_, _linda, StackIndex{ 2 }); | 549 | _pushed = keeper_call(_keeper->K, KEEPER_API(limit), L_, _linda, StackIndex{ 2 }); |
@@ -572,12 +575,12 @@ LUAG_FUNC(linda_limit) | |||
572 | 575 | ||
573 | /* | 576 | /* |
574 | * 2 modes of operation | 577 | * 2 modes of operation |
575 | * [val, key]= linda:receive([timeout_secs_num=nil], key_num|str|bool|lightuserdata [, ...] ) | 578 | * [val, slot]= linda:receive([timeout_secs_num=nil], key_num|str|bool|lightuserdata [, ...] ) |
576 | * Consumes a single value from the Linda, in any key. | 579 | * Consumes a single value from the Linda, in any slot. |
577 | * Returns: received value (which is consumed from the slot), and the key which had it | 580 | * Returns: received value (which is consumed from the slot), and the slot which had it |
578 | 581 | ||
579 | * [val1, ... valCOUNT]= linda_receive( linda_ud, [timeout_secs_num=-1], linda.batched, key_num|str|bool|lightuserdata, min_COUNT[, max_COUNT]) | 582 | * [val1, ... valCOUNT]= linda_receive( linda_ud, [timeout_secs_num=-1], linda.batched, key_num|str|bool|lightuserdata, min_COUNT[, max_COUNT]) |
580 | * Consumes between min_COUNT and max_COUNT values from the linda, from a single key. | 583 | * Consumes between min_COUNT and max_COUNT values from the linda, from a single slot. |
581 | * returns the actual consumed values, or nil if there weren't enough values to consume | 584 | * returns the actual consumed values, or nil if there weren't enough values to consume |
582 | */ | 585 | */ |
583 | LUAG_FUNC(linda_receive) | 586 | LUAG_FUNC(linda_receive) |
@@ -585,7 +588,7 @@ LUAG_FUNC(linda_receive) | |||
585 | static constexpr lua_CFunction _receive{ | 588 | static constexpr lua_CFunction _receive{ |
586 | +[](lua_State* const L_) { | 589 | +[](lua_State* const L_) { |
587 | Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) }; | 590 | Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) }; |
588 | StackIndex _key_i{ 2 }; // index of first key, if timeout not there | 591 | StackIndex _key_i{ 2 }; // index of first slot, if timeout not there |
589 | 592 | ||
590 | std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; | 593 | std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; |
591 | if (luaG_type(L_, StackIndex{ 2 }) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion | 594 | if (luaG_type(L_, StackIndex{ 2 }) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion |
@@ -596,7 +599,7 @@ LUAG_FUNC(linda_receive) | |||
596 | raise_luaL_argerror(L_, StackIndex{ 2 }, "duration cannot be < 0"); | 599 | raise_luaL_argerror(L_, StackIndex{ 2 }, "duration cannot be < 0"); |
597 | } | 600 | } |
598 | ++_key_i; | 601 | ++_key_i; |
599 | } else if (lua_isnil(L_, 2)) { // alternate explicit "infinite timeout" by passing nil before the key | 602 | } else if (lua_isnil(L_, 2)) { // alternate explicit "infinite timeout" by passing nil before the slot |
600 | ++_key_i; | 603 | ++_key_i; |
601 | } | 604 | } |
602 | 605 | ||
@@ -616,7 +619,7 @@ LUAG_FUNC(linda_receive) | |||
616 | raise_luaL_argerror(L_, StackIndex{ _key_i + 1 }, "bad min count"); | 619 | raise_luaL_argerror(L_, StackIndex{ _key_i + 1 }, "bad min count"); |
617 | } | 620 | } |
618 | _expected_pushed_max = (int) luaL_optinteger(L_, _key_i + 2, _expected_pushed_min); | 621 | _expected_pushed_max = (int) luaL_optinteger(L_, _key_i + 2, _expected_pushed_min); |
619 | // don't forget to count the key in addition to the values | 622 | // don't forget to count the slot in addition to the values |
620 | ++_expected_pushed_min; | 623 | ++_expected_pushed_min; |
621 | ++_expected_pushed_max; | 624 | ++_expected_pushed_max; |
622 | if (_expected_pushed_min > _expected_pushed_max) { | 625 | if (_expected_pushed_min > _expected_pushed_max) { |
@@ -627,7 +630,7 @@ LUAG_FUNC(linda_receive) | |||
627 | CheckKeyTypes(L_, _key_i, StackIndex{ lua_gettop(L_) }); | 630 | CheckKeyTypes(L_, _key_i, StackIndex{ lua_gettop(L_) }); |
628 | // receive a single value, checking multiple slots | 631 | // receive a single value, checking multiple slots |
629 | _selected_keeper_receive = KEEPER_API(receive); | 632 | _selected_keeper_receive = KEEPER_API(receive); |
630 | // we expect a single (value, key) pair of returned values | 633 | // we expect a single (value, slot) pair of returned values |
631 | _expected_pushed_min = _expected_pushed_max = 2; | 634 | _expected_pushed_min = _expected_pushed_max = 2; |
632 | } | 635 | } |
633 | 636 | ||
@@ -660,6 +663,9 @@ LUAG_FUNC(linda_receive) | |||
660 | } | 663 | } |
661 | if (_pushed.value() > 0) { | 664 | if (_pushed.value() > 0) { |
662 | LUA_ASSERT(L_, _pushed.value() >= _expected_pushed_min && _pushed.value() <= _expected_pushed_max); | 665 | LUA_ASSERT(L_, _pushed.value() >= _expected_pushed_min && _pushed.value() <= _expected_pushed_max); |
666 | if (kRestrictedChannel.equals(L_, StackIndex{ kIdxTop })) { | ||
667 | raise_luaL_error(L_, "Key is restricted"); | ||
668 | } | ||
663 | _linda->readHappened.notify_all(); | 669 | _linda->readHappened.notify_all(); |
664 | break; | 670 | break; |
665 | } | 671 | } |
@@ -730,6 +736,49 @@ LUAG_FUNC(linda_receive) | |||
730 | // ################################################################################################# | 736 | // ################################################################################################# |
731 | 737 | ||
732 | /* | 738 | /* |
739 | * "string" = linda:restrict(key_num|str|bool|lightuserdata, [string]) | ||
740 | * "string" = linda:restrict(slot) | ||
741 | * | ||
742 | * Read or set restrict mode to 1 Linda slot. | ||
743 | */ | ||
744 | LUAG_FUNC(linda_restrict) | ||
745 | { | ||
746 | static constexpr lua_CFunction _rstrct{ | ||
747 | +[](lua_State* const L_) { | ||
748 | Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) }; | ||
749 | // make sure we got 2 or 3 arguments: the linda, a slot and optionally a restrict mode | ||
750 | int const _nargs{ lua_gettop(L_) }; | ||
751 | luaL_argcheck(L_, _nargs == 2 || _nargs == 3, 2, "wrong number of arguments"); | ||
752 | // make sure we got a known restrict mode, (or nothing) | ||
753 | std::string_view const _mode{ luaG_tostring(L_, StackIndex{ 3 }) }; | ||
754 | if (!_mode.empty() && (_mode != "none" && _mode != "set/get" && _mode != "send/receive")) { | ||
755 | raise_luaL_argerror(L_, StackIndex{ 3 }, "unknown restrict mode"); | ||
756 | } | ||
757 | // make sure the slot is of a valid type | ||
758 | CheckKeyTypes(L_, StackIndex{ 2 }, StackIndex{ 2 }); | ||
759 | |||
760 | KeeperCallResult _pushed; | ||
761 | if (_linda->cancelStatus == Linda::Active) { | ||
762 | Keeper* const _keeper{ _linda->whichKeeper() }; | ||
763 | _pushed = keeper_call(_keeper->K, KEEPER_API(restrict), L_, _linda, StackIndex{ 2 }); | ||
764 | // we should get a single return value: the string describing the previous restrict mode | ||
765 | LUA_ASSERT(L_, _pushed.has_value() && (_pushed.value() == 1) && luaG_type(L_, kIdxTop) == LuaType::STRING); | ||
766 | } else { // linda is cancelled | ||
767 | // do nothing and return nil,lanes.cancel_error | ||
768 | lua_pushnil(L_); | ||
769 | kCancelError.pushKey(L_); | ||
770 | _pushed.emplace(2); | ||
771 | } | ||
772 | // propagate returned values | ||
773 | return _pushed.value(); | ||
774 | } | ||
775 | }; | ||
776 | return Linda::ProtectedCall(L_, _rstrct); | ||
777 | } | ||
778 | |||
779 | // ################################################################################################# | ||
780 | |||
781 | /* | ||
733 | * bool= linda:linda_send([timeout_secs=nil,] key_num|str|bool|lightuserdata, ...) | 782 | * bool= linda:linda_send([timeout_secs=nil,] key_num|str|bool|lightuserdata, ...) |
734 | * | 783 | * |
735 | * Send one or more values to a Linda. If there is a limit, all values must fit. | 784 | * Send one or more values to a Linda. If there is a limit, all values must fit. |
@@ -743,7 +792,7 @@ LUAG_FUNC(linda_send) | |||
743 | static constexpr lua_CFunction _send{ | 792 | static constexpr lua_CFunction _send{ |
744 | +[](lua_State* const L_) { | 793 | +[](lua_State* const L_) { |
745 | Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) }; | 794 | Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) }; |
746 | StackIndex _key_i{ 2 }; // index of first key, if timeout not there | 795 | StackIndex _key_i{ 2 }; // index of first slot, if timeout not there |
747 | 796 | ||
748 | std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; | 797 | std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; |
749 | if (luaG_type(L_, StackIndex{ 2 }) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion | 798 | if (luaG_type(L_, StackIndex{ 2 }) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion |
@@ -754,11 +803,11 @@ LUAG_FUNC(linda_send) | |||
754 | raise_luaL_argerror(L_, StackIndex{ 2 }, "duration cannot be < 0"); | 803 | raise_luaL_argerror(L_, StackIndex{ 2 }, "duration cannot be < 0"); |
755 | } | 804 | } |
756 | ++_key_i; | 805 | ++_key_i; |
757 | } else if (lua_isnil(L_, 2)) { // alternate explicit "infinite timeout" by passing nil before the key | 806 | } else if (lua_isnil(L_, 2)) { // alternate explicit "infinite timeout" by passing nil before the slot |
758 | ++_key_i; | 807 | ++_key_i; |
759 | } | 808 | } |
760 | 809 | ||
761 | // make sure the key is of a valid type | 810 | // make sure the slot is of a valid type |
762 | CheckKeyTypes(L_, _key_i, _key_i); | 811 | CheckKeyTypes(L_, _key_i, _key_i); |
763 | 812 | ||
764 | STACK_GROW(L_, 1); | 813 | STACK_GROW(L_, 1); |
@@ -799,6 +848,9 @@ LUAG_FUNC(linda_send) | |||
799 | } | 848 | } |
800 | LUA_ASSERT(L_, _pushed.value() == 1); | 849 | LUA_ASSERT(L_, _pushed.value() == 1); |
801 | 850 | ||
851 | if (kRestrictedChannel.equals(L_, StackIndex{ kIdxTop })) { | ||
852 | raise_luaL_error(L_, "Key is restricted"); | ||
853 | } | ||
802 | _ret = lua_toboolean(L_, -1) ? true : false; | 854 | _ret = lua_toboolean(L_, -1) ? true : false; |
803 | lua_pop(L_, 1); | 855 | lua_pop(L_, 1); |
804 | 856 | ||
@@ -884,7 +936,7 @@ LUAG_FUNC(linda_set) | |||
884 | +[](lua_State* const L_) { | 936 | +[](lua_State* const L_) { |
885 | Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) }; | 937 | Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) }; |
886 | bool const _has_data{ lua_gettop(L_) > 2 }; | 938 | bool const _has_data{ lua_gettop(L_) > 2 }; |
887 | // make sure the key is of a valid type (throws an error if not the case) | 939 | // make sure the slot is of a valid type (throws an error if not the case) |
888 | CheckKeyTypes(L_, StackIndex{ 2 }, StackIndex{ 2 }); | 940 | CheckKeyTypes(L_, StackIndex{ 2 }, StackIndex{ 2 }); |
889 | 941 | ||
890 | KeeperCallResult _pushed; | 942 | KeeperCallResult _pushed; |
@@ -892,6 +944,9 @@ LUAG_FUNC(linda_set) | |||
892 | Keeper* const _keeper{ _linda->whichKeeper() }; | 944 | Keeper* const _keeper{ _linda->whichKeeper() }; |
893 | _pushed = keeper_call(_keeper->K, KEEPER_API(set), L_, _linda, StackIndex{ 2 }); | 945 | _pushed = keeper_call(_keeper->K, KEEPER_API(set), L_, _linda, StackIndex{ 2 }); |
894 | if (_pushed.has_value()) { // no error? | 946 | if (_pushed.has_value()) { // no error? |
947 | if (kRestrictedChannel.equals(L_, kIdxTop)) { | ||
948 | raise_luaL_error(L_, "Key is restricted"); | ||
949 | } | ||
895 | LUA_ASSERT(L_, _pushed.value() == 2 && luaG_type(L_, kIdxTop) == LuaType::STRING && luaG_type(L_, StackIndex{ -2 }) == LuaType::BOOLEAN); | 950 | LUA_ASSERT(L_, _pushed.value() == 2 && luaG_type(L_, kIdxTop) == LuaType::STRING && luaG_type(L_, StackIndex{ -2 }) == LuaType::BOOLEAN); |
896 | 951 | ||
897 | if (_has_data) { | 952 | if (_has_data) { |
@@ -899,7 +954,7 @@ LUAG_FUNC(linda_set) | |||
899 | _linda->writeHappened.notify_all(); // To be done from within the 'K' locking area | 954 | _linda->writeHappened.notify_all(); // To be done from within the 'K' locking area |
900 | } | 955 | } |
901 | if (lua_toboolean(L_, -2)) { | 956 | if (lua_toboolean(L_, -2)) { |
902 | // the key was full, but it is no longer the case, tell writers they should wake | 957 | // the slot was full, but it is no longer the case, tell writers they should wake |
903 | _linda->readHappened.notify_all(); // To be done from within the 'K' locking area | 958 | _linda->readHappened.notify_all(); // To be done from within the 'K' locking area |
904 | } | 959 | } |
905 | } | 960 | } |
@@ -992,6 +1047,7 @@ namespace { | |||
992 | { "get", LG_linda_get }, | 1047 | { "get", LG_linda_get }, |
993 | { "limit", LG_linda_limit }, | 1048 | { "limit", LG_linda_limit }, |
994 | { "receive", LG_linda_receive }, | 1049 | { "receive", LG_linda_receive }, |
1050 | { "restrict", LG_linda_restrict }, | ||
995 | { "send", LG_linda_send }, | 1051 | { "send", LG_linda_send }, |
996 | { "set", LG_linda_set }, | 1052 | { "set", LG_linda_set }, |
997 | { "wake", LG_linda_wake }, | 1053 | { "wake", LG_linda_wake }, |