diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/keeper.cpp | 75 | ||||
-rw-r--r-- | src/lane.cpp | 2 | ||||
-rw-r--r-- | src/lanes.lua | 3 | ||||
-rw-r--r-- | src/linda.cpp | 20 |
4 files changed, 72 insertions, 28 deletions
diff --git a/src/keeper.cpp b/src/keeper.cpp index ae09b37..cfeebbb 100644 --- a/src/keeper.cpp +++ b/src/keeper.cpp | |||
@@ -66,6 +66,10 @@ class KeyUD | |||
66 | static constexpr int kContentsTableIndex{ 1 }; | 66 | static constexpr int kContentsTableIndex{ 1 }; |
67 | 67 | ||
68 | public: | 68 | public: |
69 | static constexpr std::string_view kUnder{ "under" }; | ||
70 | static constexpr std::string_view kExact{ "exact" }; | ||
71 | static constexpr std::string_view kOver{ "over" }; | ||
72 | |||
69 | int first{ 1 }; | 73 | int first{ 1 }; |
70 | int count{ 0 }; | 74 | int count{ 0 }; |
71 | LindaLimit limit{ -1 }; | 75 | LindaLimit limit{ -1 }; |
@@ -83,6 +87,8 @@ class KeyUD | |||
83 | [[nodiscard]] int pop(KeeperState K_, int minCount_, int maxCount_); // keepercall_receive[_batched] | 87 | [[nodiscard]] int pop(KeeperState K_, int minCount_, int maxCount_); // keepercall_receive[_batched] |
84 | void prepareAccess(KeeperState K_, int idx_) const; | 88 | void prepareAccess(KeeperState K_, int idx_) const; |
85 | [[nodiscard]] bool push(KeeperState K_, int count_, bool enforceLimit_); // keepercall_send and keepercall_set | 89 | [[nodiscard]] bool push(KeeperState K_, int count_, bool enforceLimit_); // keepercall_send and keepercall_set |
90 | void pushFillStatus(KeeperState K_) const; | ||
91 | static void PushFillStatus(KeeperState K_, KeyUD const* key_); | ||
86 | [[nodiscard]] bool reset(KeeperState K_); | 92 | [[nodiscard]] bool reset(KeeperState K_); |
87 | }; | 93 | }; |
88 | 94 | ||
@@ -232,6 +238,35 @@ bool KeyUD::push(KeeperState const K_, int const count_, bool const enforceLimit | |||
232 | 238 | ||
233 | // ################################################################################################# | 239 | // ################################################################################################# |
234 | 240 | ||
241 | void KeyUD::pushFillStatus(KeeperState const K_) const | ||
242 | { | ||
243 | if (limit < 0) { | ||
244 | luaG_pushstring(K_, kUnder); | ||
245 | return; | ||
246 | } | ||
247 | int const _delta{limit - count}; | ||
248 | if (_delta < 0) { | ||
249 | luaG_pushstring(K_, kOver); | ||
250 | } else if (_delta > 0) { | ||
251 | luaG_pushstring(K_, kUnder); | ||
252 | } else { | ||
253 | luaG_pushstring(K_, kExact); | ||
254 | } | ||
255 | } | ||
256 | |||
257 | // ################################################################################################# | ||
258 | |||
259 | void KeyUD::PushFillStatus(KeeperState const K_, KeyUD const* const key_) | ||
260 | { | ||
261 | if (key_) { | ||
262 | key_->pushFillStatus(K_); // _K: ... <fill status> | ||
263 | } else { | ||
264 | luaG_pushstring(K_, KeyUD::kUnder); // _K: ... "under" | ||
265 | } | ||
266 | } | ||
267 | |||
268 | // ################################################################################################# | ||
269 | |||
235 | // expects 'this' on top of the stack | 270 | // expects 'this' on top of the stack |
236 | bool KeyUD::reset(KeeperState const K_) | 271 | bool KeyUD::reset(KeeperState const K_) |
237 | { | 272 | { |
@@ -394,10 +429,11 @@ int keepercall_get(lua_State* const L_) | |||
394 | // ################################################################################################# | 429 | // ################################################################################################# |
395 | 430 | ||
396 | // in: linda key [n|nil] | 431 | // in: linda key [n|nil] |
397 | // out: true or nil | 432 | // out: boolean, <fill status: string> |
398 | int keepercall_limit(lua_State* const L_) | 433 | int keepercall_limit(lua_State* const L_) |
399 | { | 434 | { |
400 | KeeperState const _K{ L_ }; | 435 | KeeperState const _K{ L_ }; |
436 | STACK_CHECK_START_ABS(_K, lua_gettop(_K)); | ||
401 | // no limit to set, means we read and return the current limit instead | 437 | // no limit to set, means we read and return the current limit instead |
402 | bool const _reading{ lua_gettop(_K) == 2 }; | 438 | bool const _reading{ lua_gettop(_K) == 2 }; |
403 | LindaLimit const _limit{ static_cast<LindaLimit::type>(luaL_optinteger(_K, 3, -1)) }; // -1 if we read nil because the argument is absent | 439 | LindaLimit const _limit{ static_cast<LindaLimit::type>(luaL_optinteger(_K, 3, -1)) }; // -1 if we read nil because the argument is absent |
@@ -408,10 +444,12 @@ int keepercall_limit(lua_State* const L_) | |||
408 | lua_rawget(_K, -3); // _K: KeysDB key KeyUD|nil | 444 | lua_rawget(_K, -3); // _K: KeysDB key KeyUD|nil |
409 | KeyUD* _key{ KeyUD::GetPtr(_K, -1) }; | 445 | KeyUD* _key{ KeyUD::GetPtr(_K, -1) }; |
410 | if (_reading) { | 446 | if (_reading) { |
447 | // remove any clutter on the stack | ||
448 | lua_settop(_K, 0); // _K: | ||
411 | if (_key && _key->limit >= 0) { | 449 | if (_key && _key->limit >= 0) { |
412 | lua_pushinteger(_K, _key->limit); // _K: KeysDB key KeyUD limit | 450 | lua_pushinteger(_K, _key->limit); // _K: limit |
413 | } else { // if the key doesn't exist, it is unlimited by default | 451 | } else { // if the key doesn't exist, it is unlimited by default |
414 | luaG_pushstring(_K, "unlimited"); // _K: KeysDB key KeyUD "unlimited" | 452 | luaG_pushstring(_K, "unlimited"); // _K: "unlimited" |
415 | } | 453 | } |
416 | // return a single value: the limit of the key | 454 | // return a single value: the limit of the key |
417 | } else { | 455 | } else { |
@@ -426,7 +464,9 @@ int keepercall_limit(lua_State* const L_) | |||
426 | // this is the case if we detect the key was full but it is no longer the case | 464 | // this is the case if we detect the key was full but it is no longer the case |
427 | lua_pushboolean(_K, _key->changeLimit(_limit) ? 1 : 0); // _K: bool | 465 | lua_pushboolean(_K, _key->changeLimit(_limit) ? 1 : 0); // _K: bool |
428 | } | 466 | } |
429 | return 1; | 467 | KeyUD::PushFillStatus(_K, _key); // _K: limit|bool <fill status> |
468 | STACK_CHECK(_K, 2); | ||
469 | return 2; | ||
430 | } | 470 | } |
431 | 471 | ||
432 | // ################################################################################################# | 472 | // ################################################################################################# |
@@ -538,12 +578,12 @@ int keepercall_set(lua_State* const L_) | |||
538 | // retrieve KeysDB associated with the linda | 578 | // retrieve KeysDB associated with the linda |
539 | PushKeysDB(_K, 1); // _K: linda key val... KeysDB | 579 | PushKeysDB(_K, 1); // _K: linda key val... KeysDB |
540 | lua_replace(_K, 1); // _K: KeysDB key val... | 580 | lua_replace(_K, 1); // _K: KeysDB key val... |
581 | lua_pushvalue(_K, 2); // _K: KeysDB key val... key | ||
582 | lua_rawget(_K, 1); // _K: KeysDB key val KeyUD|nil | ||
583 | KeyUD* _key{ KeyUD::GetPtr(_K, -1) }; | ||
541 | 584 | ||
542 | if (lua_gettop(_K) == 2) { // no value to set // _K: KeysDB key | 585 | if (lua_gettop(_K) == 3) { // no value to set // _K: KeysDB key KeyUD|nil |
543 | lua_pushvalue(_K, -1); // _K: KeysDB key key | ||
544 | lua_rawget(_K, 1); // _K: KeysDB key KeyUD|nil | ||
545 | // empty the KeyUD for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! | 586 | // empty the KeyUD for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! |
546 | KeyUD* const _key{ KeyUD::GetPtr(_K, -1) }; | ||
547 | if (_key != nullptr) { // might be nullptr if we set a nonexistent key to nil // _K: KeysDB key KeyUD | 587 | if (_key != nullptr) { // might be nullptr if we set a nonexistent key to nil // _K: KeysDB key KeyUD |
548 | if (_key->limit < 0) { // KeyUD limit value is the default (unlimited): we can totally remove it | 588 | if (_key->limit < 0) { // KeyUD limit value is the default (unlimited): we can totally remove it |
549 | lua_pop(_K, 1); // _K: KeysDB key | 589 | lua_pop(_K, 1); // _K: KeysDB key |
@@ -555,18 +595,17 @@ int keepercall_set(lua_State* const L_) | |||
555 | _should_wake_writers = _key->reset(_K); | 595 | _should_wake_writers = _key->reset(_K); |
556 | } | 596 | } |
557 | } | 597 | } |
598 | lua_settop(_K, 0); // we are done, remove everything // _K: | ||
558 | } else { // set/replace contents stored at the specified key? | 599 | } else { // set/replace contents stored at the specified key? |
559 | int const _count{ lua_gettop(_K) - 2 }; // number of items we want to store | 600 | int const _count{ lua_gettop(_K) - 3 }; // number of items we want to store // _K: KeysDB key val... KeyUD|nil |
560 | lua_pushvalue(_K, 2); // _K: KeysDB key val... key | 601 | if (_key == nullptr) { // can be nullptr if we store a value at a new key // _K: KeysDB key val... nil |
561 | lua_rawget(_K, 1); // _K: KeysDB key val... KeyUD|nil | 602 | assert(lua_isnil(_K, -1)); |
562 | KeyUD* _key{ KeyUD::GetPtr(_K, -1) }; | ||
563 | if (_key == nullptr) { // can be nullptr if we store a value at a new key // KeysDB key val... nil | ||
564 | // no need to wake writers in that case, because a writer can't wait on an inexistent key | ||
565 | lua_pop(_K, 1); // _K: KeysDB key val... | 603 | lua_pop(_K, 1); // _K: KeysDB key val... |
566 | _key = KeyUD::Create(KeeperState{ _K }); // _K: KeysDB key val... KeyUD | 604 | _key = KeyUD::Create(KeeperState{ _K }); // _K: KeysDB key val... KeyUD |
567 | lua_pushvalue(_K, 2); // _K: KeysDB key val... KeyUD key | 605 | lua_pushvalue(_K, 2); // _K: KeysDB key val... KeyUD key |
568 | lua_pushvalue(_K, -2); // _K: KeysDB key val... KeyUD key KeyUD | 606 | lua_pushvalue(_K, -2); // _K: KeysDB key val... KeyUD key KeyUD |
569 | lua_rawset(_K, 1); // _K: KeysDB key val... KeyUD | 607 | lua_rawset(_K, 1); // _K: KeysDB key val... KeyUD |
608 | // no need to wake writers, because a writer can't wait on an inexistent key | ||
570 | } else { // _K: KeysDB key val... KeyUD | 609 | } else { // _K: KeysDB key val... KeyUD |
571 | // the KeyUD exists, we just want to update its contents | 610 | // the KeyUD exists, we just want to update its contents |
572 | // we create room if the KeyUD was full but we didn't refill it to the brim with new data | 611 | // we create room if the KeyUD was full but we didn't refill it to the brim with new data |
@@ -575,10 +614,12 @@ int keepercall_set(lua_State* const L_) | |||
575 | // replace the key with the KeyUD in the stack | 614 | // replace the key with the KeyUD in the stack |
576 | lua_replace(_K, -2 - _count); // _K: KeysDB KeyUD val... | 615 | lua_replace(_K, -2 - _count); // _K: KeysDB KeyUD val... |
577 | [[maybe_unused]] bool const _pushed{ _key->push(_K, _count, false) }; // _K: KeysDB | 616 | [[maybe_unused]] bool const _pushed{ _key->push(_K, _count, false) }; // _K: KeysDB |
617 | lua_pop(_K, 1); // _K: | ||
578 | } | 618 | } |
579 | // stack isn't the same here depending on what we did before, but that's not a problem | 619 | assert(lua_gettop(_K) == 0); |
580 | lua_pushboolean(_K, _should_wake_writers ? 1 : 0); // _K: ... bool | 620 | lua_pushboolean(_K, _should_wake_writers ? 1 : 0); // _K: bool |
581 | return 1; | 621 | KeyUD::PushFillStatus(_K, _key); // _K: bool <fill status> |
622 | return 2; | ||
582 | } | 623 | } |
583 | 624 | ||
584 | // ################################################################################################# | 625 | // ################################################################################################# |
diff --git a/src/lane.cpp b/src/lane.cpp index d4175c6..ba24af3 100644 --- a/src/lane.cpp +++ b/src/lane.cpp | |||
@@ -435,7 +435,7 @@ static constexpr RegistryUniqueKey kStackTraceRegKey{ 0x3F327747CACAA904ull }; | |||
435 | [[nodiscard]] static int lane_error(lua_State* L_) | 435 | [[nodiscard]] static int lane_error(lua_State* L_) |
436 | { | 436 | { |
437 | // error message (any type) | 437 | // error message (any type) |
438 | STACK_CHECK_START_ABS(L_, 1); // L_: some_error | 438 | STACK_CHECK_START_ABS(L_, 1); // L_: some_error |
439 | 439 | ||
440 | // Don't do stack survey for cancelled lanes. | 440 | // Don't do stack survey for cancelled lanes. |
441 | // | 441 | // |
diff --git a/src/lanes.lua b/src/lanes.lua index 6a4f149..48ebeb6 100644 --- a/src/lanes.lua +++ b/src/lanes.lua | |||
@@ -792,7 +792,8 @@ local genatomic = function(linda_, key_, initial_val_) | |||
792 | if val ~= cancel_error then | 792 | if val ~= cancel_error then |
793 | val = val + (diff_ or 1.0) | 793 | val = val + (diff_ or 1.0) |
794 | -- set() releases the lock by emptying queue | 794 | -- set() releases the lock by emptying queue |
795 | if linda_:set(key_, val) == cancel_error then | 795 | local _res, _err = linda_:set(key_, val) |
796 | if _err == cancel_error then | ||
796 | val = cancel_error | 797 | val = cancel_error |
797 | end | 798 | end |
798 | end | 799 | end |
diff --git a/src/linda.cpp b/src/linda.cpp index f4dd7e7..13627aa 100644 --- a/src/linda.cpp +++ b/src/linda.cpp | |||
@@ -477,22 +477,24 @@ LUAG_FUNC(linda_limit) | |||
477 | 477 | ||
478 | KeeperCallResult _pushed; | 478 | KeeperCallResult _pushed; |
479 | if (_linda->cancelRequest == CancelRequest::None) { | 479 | if (_linda->cancelRequest == CancelRequest::None) { |
480 | Keeper* const _keeper{ _linda->whichKeeper() }; | ||
481 | if (_unlimited) { | 480 | if (_unlimited) { |
482 | LUA_ASSERT(L_, lua_gettop(L_) == 3 && luaG_tostring(L_, 3) == "unlimited"); | 481 | LUA_ASSERT(L_, lua_gettop(L_) == 3 && luaG_tostring(L_, 3) == "unlimited"); |
483 | // inside the Keeper, unlimited is signified with a -1 limit (can't use nil because of nil kNilSentinel conversions!) | 482 | // inside the Keeper, unlimited is signified with a -1 limit (can't use nil because of nil kNilSentinel conversions!) |
484 | lua_pop(L_, 1); // L_: linda key | 483 | lua_pop(L_, 1); // L_: linda key |
485 | lua_pushinteger(L_, -1); // L_: linda key nil | 484 | lua_pushinteger(L_, -1); // L_: linda key nil |
486 | } | 485 | } |
486 | Keeper* const _keeper{ _linda->whichKeeper() }; | ||
487 | _pushed = keeper_call(_keeper->K, KEEPER_API(limit), L_, _linda, 2); | 487 | _pushed = keeper_call(_keeper->K, KEEPER_API(limit), L_, _linda, 2); |
488 | LUA_ASSERT(L_, _pushed.has_value() && (_pushed.value() == 1)); | 488 | LUA_ASSERT(L_, _pushed.has_value() && (_pushed.value() == 2) && luaG_type(L_, -1) == LuaType::STRING); |
489 | if (_nargs == 3) { // 3 args: setting the limit | 489 | if (_nargs == 3) { // 3 args: setting the limit |
490 | LUA_ASSERT(L_, luaG_type(L_, -1) == LuaType::BOOLEAN); // changing the limit: no error, boolean value saying if we should wake blocked writer threads | 490 | // changing the limit: no error, boolean value saying if we should wake blocked writer threads |
491 | if (lua_toboolean(L_, -1)) { | 491 | LUA_ASSERT(L_, luaG_type(L_, -2) == LuaType::BOOLEAN); // L_: bool string |
492 | if (lua_toboolean(L_, -2)) { | ||
492 | _linda->readHappened.notify_all(); // To be done from within the 'K' locking area | 493 | _linda->readHappened.notify_all(); // To be done from within the 'K' locking area |
493 | } | 494 | } |
494 | } else { // 2 args: reading the limit | 495 | } else { // 2 args: reading the limit |
495 | LUA_ASSERT(L_, luaG_type(L_, -1) == LuaType::NUMBER || luaG_tostring(L_, -1) == "unlimited"); // reading the limit: a number >=0 or "unlimited" | 496 | // reading the limit: a number >=0 or "unlimited" |
497 | LUA_ASSERT(L_, luaG_type(L_, -2) == LuaType::NUMBER || luaG_tostring(L_, -2) == "unlimited"); | ||
496 | } | 498 | } |
497 | } else { // linda is cancelled | 499 | } else { // linda is cancelled |
498 | // do nothing and return nil,lanes.cancel_error | 500 | // do nothing and return nil,lanes.cancel_error |
@@ -500,7 +502,7 @@ LUAG_FUNC(linda_limit) | |||
500 | kCancelError.pushKey(L_); | 502 | kCancelError.pushKey(L_); |
501 | _pushed.emplace(2); | 503 | _pushed.emplace(2); |
502 | } | 504 | } |
503 | // propagate pushed boolean if any | 505 | // propagate returned values |
504 | return _pushed.value(); | 506 | return _pushed.value(); |
505 | } | 507 | } |
506 | }; | 508 | }; |
@@ -807,7 +809,7 @@ LUAG_FUNC(linda_send) | |||
807 | // ################################################################################################# | 809 | // ################################################################################################# |
808 | 810 | ||
809 | /* | 811 | /* |
810 | * [true|nil,lanes.cancel_error] = linda:set(key_num|str|bool|lightuserdata [, value [, ...]]) | 812 | * (boolean,string)|(nil,lanes.cancel_error) = linda:set(key_num|str|bool|lightuserdata [, value [, ...]]) |
811 | * | 813 | * |
812 | * Set one or more value to Linda. Ignores limits. | 814 | * Set one or more value to Linda. Ignores limits. |
813 | * | 815 | * |
@@ -827,13 +829,13 @@ LUAG_FUNC(linda_set) | |||
827 | Keeper* const _keeper{ _linda->whichKeeper() }; | 829 | Keeper* const _keeper{ _linda->whichKeeper() }; |
828 | _pushed = keeper_call(_keeper->K, KEEPER_API(set), L_, _linda, 2); | 830 | _pushed = keeper_call(_keeper->K, KEEPER_API(set), L_, _linda, 2); |
829 | if (_pushed.has_value()) { // no error? | 831 | if (_pushed.has_value()) { // no error? |
830 | LUA_ASSERT(L_, _pushed.value() == 1 && luaG_type(L_, -1) == LuaType::BOOLEAN); | 832 | LUA_ASSERT(L_, _pushed.value() == 2 && luaG_type(L_, -1) == LuaType::STRING && luaG_type(L_, -2) == LuaType::BOOLEAN); |
831 | 833 | ||
832 | if (_has_data) { | 834 | if (_has_data) { |
833 | // we put some data in the slot, tell readers that they should wake | 835 | // we put some data in the slot, tell readers that they should wake |
834 | _linda->writeHappened.notify_all(); // To be done from within the 'K' locking area | 836 | _linda->writeHappened.notify_all(); // To be done from within the 'K' locking area |
835 | } | 837 | } |
836 | if (lua_toboolean(L_, -1)) { | 838 | if (lua_toboolean(L_, -2)) { |
837 | // the key was full, but it is no longer the case, tell writers they should wake | 839 | // the key was full, but it is no longer the case, tell writers they should wake |
838 | _linda->readHappened.notify_all(); // To be done from within the 'K' locking area | 840 | _linda->readHappened.notify_all(); // To be done from within the 'K' locking area |
839 | } | 841 | } |