aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/keeper.cpp75
-rw-r--r--src/lane.cpp2
-rw-r--r--src/lanes.lua3
-rw-r--r--src/linda.cpp20
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
241void 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
259void 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
236bool KeyUD::reset(KeeperState const K_) 271bool 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>
398int keepercall_limit(lua_State* const L_) 433int 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 }