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 }, |
