aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2024-06-12 18:18:24 +0200
committerBenoit Germain <benoit.germain@ubisoft.com>2024-06-12 18:18:24 +0200
commitdddc28153796f9c8eb256eddb335c8643226fd0b (patch)
tree641caa9a01933d0397a99f127cff249d3a77fdb5 /src
parentc305ff3ed1f51d86ced2bb83b10b5e0632cd98a3 (diff)
downloadlanes-dddc28153796f9c8eb256eddb335c8643226fd0b.tar.gz
lanes-dddc28153796f9c8eb256eddb335c8643226fd0b.tar.bz2
lanes-dddc28153796f9c8eb256eddb335c8643226fd0b.zip
linda :get(), :set(), :limit() return value changes
Diffstat (limited to 'src')
-rw-r--r--src/keeper.cpp47
-rw-r--r--src/lanes.lua41
-rw-r--r--src/linda.cpp38
3 files changed, 72 insertions, 54 deletions
diff --git a/src/keeper.cpp b/src/keeper.cpp
index 7000372..4175d84 100644
--- a/src/keeper.cpp
+++ b/src/keeper.cpp
@@ -123,26 +123,32 @@ KeyUD* KeyUD::GetPtr(KeeperState const K_, int idx_)
123// ################################################################################################# 123// #################################################################################################
124 124
125// in: fifo 125// in: fifo
126// out: ...|nothing 126// out: bool ...
127// pops the fifo, push as much data as is available (up to the specified count) without consuming it 127// pops the fifo, push bool + as much data as is available (up to the specified count) without consuming it
128// bool is true if the requested count was served, else false
128void KeyUD::peek(KeeperState const K_, int const count_) 129void KeyUD::peek(KeeperState const K_, int const count_)
129{ 130{
130 LUA_ASSERT(K_, KeyUD::GetPtr(K_, -1) == this); 131 STACK_CHECK_START_ABS(K_, 1);
132 LUA_ASSERT(K_, KeyUD::GetPtr(K_, -1) == this); // K_: KeyUD
131 if (count <= 0) { // no data is available 133 if (count <= 0) { // no data is available
132 lua_pop(K_, 1); // K_: 134 lua_pop(K_, 1); // K_:
135 lua_pushinteger(K_, 0); // K_: 0
133 return; 136 return;
134 } 137 }
135 138
136 // read <count_> value off the fifo 139 // read <count_> value off the fifo, if possible
137 prepareAccess(K_, -1); // K_: fifo 140 prepareAccess(K_, -1); // K_: fifo
138 int const _at{ lua_gettop(K_) };
139 int const _count{ std::min(count_, count) }; 141 int const _count{ std::min(count_, count) };
142 lua_pushinteger(K_, _count); // K_: fifo _count
143 lua_insert(K_, 1); // K_: _count fifo
144 STACK_CHECK(K_, 2);
140 STACK_GROW(K_, _count); 145 STACK_GROW(K_, _count);
141 for (int const _i : std::ranges::iota_view{ 1, _count }) { // push val2 to valN 146 for (int const _i : std::ranges::iota_view{ 1, _count }) { // push val2 to valN
142 lua_rawgeti(K_, 1, first + _i); // K_: fifo val2..N 147 lua_rawgeti(K_, 2, first + _i); // K_: _count fifo val2..N
143 } 148 }
144 lua_rawgeti(K_, 1, first); // push val1 // K_: fifo val2..N val1 149 lua_rawgeti(K_, 2, first); // push val1 // K_: _count fifo val2..N val1
145 lua_replace(K_, _at); // replace fifo by val1 to get the output properly ordered // K_: val1..N 150 lua_replace(K_, 2); // replace fifo by val1 to get the output properly ordered // K_: _count val1..N
151 STACK_CHECK(K_, 1 + _count);
146} 152}
147 153
148// ################################################################################################# 154// #################################################################################################
@@ -418,7 +424,7 @@ int keepercall_destruct(lua_State* const L_)
418// ################################################################################################# 424// #################################################################################################
419 425
420// in: linda_ud key [count] 426// in: linda_ud key [count]
421// out: at most <count> values 427// out: bool + at most <count> values
422int keepercall_get(lua_State* const L_) 428int keepercall_get(lua_State* const L_)
423{ 429{
424 KeeperState const _K{ L_ }; 430 KeeperState const _K{ L_ };
@@ -433,11 +439,13 @@ int keepercall_get(lua_State* const L_)
433 lua_remove(_K, 1); // _K: KeyUD 439 lua_remove(_K, 1); // _K: KeyUD
434 KeyUD* const _key{ KeyUD::GetPtr(_K, -1) }; 440 KeyUD* const _key{ KeyUD::GetPtr(_K, -1) };
435 if (_key != nullptr) { 441 if (_key != nullptr) {
436 _key->peek(_K, _count); // _K: val... 442 _key->peek(_K, _count); // _K: N val...
437 } else { 443 } else {
438 // no fifo was ever registered for this key, or it is empty 444 // no fifo was ever registered for this key, or it is empty
439 lua_pop(_K, 1); // _K: 445 lua_pop(_K, 1); // _K:
446 lua_pushinteger(_K, 0); // _K: 0
440 } 447 }
448 LUA_ASSERT(_K, lua_isnumber(_K, 1));
441 return lua_gettop(_K); 449 return lua_gettop(_K);
442} 450}
443 451
@@ -462,13 +470,10 @@ int keepercall_limit(lua_State* const L_)
462 } 470 }
463 // remove any clutter on the stack 471 // remove any clutter on the stack
464 lua_settop(_K, 0); // _K: 472 lua_settop(_K, 0); // _K:
465 if (_key->changeLimit(_limit)) { 473 // return true if we decide that blocked threads waiting to write on that key should be awakened
466 // return true if we decide that blocked threads waiting to write on that key should be awakened 474 // this is the case if we detect the key was full but it is no longer the case
467 // this is the case if we detect the key was full but it is no longer the case 475 lua_pushboolean(_K, _key->changeLimit(_limit) ? 1 : 0); // _K: bool
468 lua_pushboolean(_K, 1); // _K: true 476 return 1;
469 }
470 // return 0 or 1 value
471 return lua_gettop(_K);
472} 477}
473 478
474// ################################################################################################# 479// #################################################################################################
@@ -570,7 +575,7 @@ int keepercall_send(lua_State* const L_)
570// ################################################################################################# 575// #################################################################################################
571 576
572// in: linda key [val...] 577// in: linda key [val...]
573// out: true if the linda was full but it's no longer the case, else nothing 578// out: true if the linda was full but it's no longer the case, else false
574int keepercall_set(lua_State* const L_) 579int keepercall_set(lua_State* const L_)
575{ 580{
576 KeeperState const _K{ L_ }; 581 KeeperState const _K{ L_ };
@@ -593,7 +598,7 @@ int keepercall_set(lua_State* const L_)
593 lua_pushnil(_K); // _K: KeysDB key nil 598 lua_pushnil(_K); // _K: KeysDB key nil
594 lua_rawset(_K, -3); // _K: KeysDB 599 lua_rawset(_K, -3); // _K: KeysDB
595 } else { 600 } else {
596 lua_remove(_K, -2); // _K: KeysDB KeyUD 601 lua_remove(_K, -2); // KeyUD::reset expects KeyUD at the top // _K: KeysDB KeyUD
597 // we create room if the KeyUD was full but it is no longer the case 602 // we create room if the KeyUD was full but it is no longer the case
598 _should_wake_writers = _key->reset(_K); 603 _should_wake_writers = _key->reset(_K);
599 } 604 }
@@ -619,7 +624,9 @@ int keepercall_set(lua_State* const L_)
619 lua_replace(_K, -2 - _count); // _K: KeysDB KeyUD val... 624 lua_replace(_K, -2 - _count); // _K: KeysDB KeyUD val...
620 [[maybe_unused]] bool const _pushed{ _key->push(_K, _count) }; // _K: KeysDB 625 [[maybe_unused]] bool const _pushed{ _key->push(_K, _count) }; // _K: KeysDB
621 } 626 }
622 return _should_wake_writers ? (lua_pushboolean(_K, 1), 1) : 0; 627 // stack isn't the same here depending on what we did before, but that's not a problem
628 lua_pushboolean(_K, _should_wake_writers ? 1 : 0); // _K: ... bool
629 return 1;
623} 630}
624 631
625// ################################################################################################# 632// #################################################################################################
diff --git a/src/lanes.lua b/src/lanes.lua
index d890adf..c860ba0 100644
--- a/src/lanes.lua
+++ b/src/lanes.lua
@@ -400,7 +400,8 @@ local configure_timers = function()
400 400
401 -- Timer lane; initialize only on the first 'require "lanes"' instance (which naturally has 'table' always declared) 401 -- Timer lane; initialize only on the first 'require "lanes"' instance (which naturally has 'table' always declared)
402 local first_time_key = "first time" 402 local first_time_key = "first time"
403 local first_time = timerLinda:get(first_time_key) == nil 403 local _, _first_time_val = timerLinda:get(first_time_key)
404 local first_time = (_first_time_val == nil)
404 timerLinda:set(first_time_key, true) 405 timerLinda:set(first_time_key, true)
405 if first_time then 406 if first_time then
406 407
@@ -490,8 +491,8 @@ local configure_timers = function()
490 -- 491 --
491 local t2 = t1[key_] 492 local t2 = t1[key_]
492 if not t2 then 493 if not t2 then
493 t2= {} 494 t2 = {}
494 t1[key_]= t2 495 t1[key_] = t2
495 end 496 end
496 497
497 t2[1] = wakeup_at_ 498 t2[1] = wakeup_at_
@@ -507,10 +508,10 @@ local configure_timers = function()
507 local now = now_secs() 508 local now = now_secs()
508 local next_wakeup 509 local next_wakeup
509 510
510 for linda_deep,t1 in pairs(collection) do 511 for linda_deep, t1 in pairs(collection) do
511 for key,t2 in pairs(t1) do 512 for key, t2 in pairs(t1) do
512 -- 513 --
513 if key==linda_deep then 514 if key == linda_deep then
514 -- no 'continue' in Lua :/ 515 -- no 'continue' in Lua :/
515 else 516 else
516 -- 't2': { wakeup_at_secs [,period_secs] } 517 -- 't2': { wakeup_at_secs [,period_secs] }
@@ -519,10 +520,10 @@ local configure_timers = function()
519 local period= t2[2] -- may be 'nil' 520 local period= t2[2] -- may be 'nil'
520 521
521 if wakeup_at <= now then 522 if wakeup_at <= now then
522 local linda= t1[linda_deep] 523 local linda = t1[linda_deep]
523 assert(linda) 524 assert(linda)
524 525
525 linda:set(key, now ) 526 linda:set(key, now)
526 527
527 -- 'pairs()' allows the values to be modified (and even 528 -- 'pairs()' allows the values to be modified (and even
528 -- removed) as far as keys are not touched 529 -- removed) as far as keys are not touched
@@ -530,13 +531,13 @@ local configure_timers = function()
530 if not period then 531 if not period then
531 -- one-time timer; gone 532 -- one-time timer; gone
532 -- 533 --
533 t1[key]= nil 534 t1[key] = nil
534 wakeup_at= nil -- no 'continue' in Lua :/ 535 wakeup_at = nil -- no 'continue' in Lua :/
535 else 536 else
536 -- repeating timer; find next wakeup (may jump multiple repeats) 537 -- repeating timer; find next wakeup (may jump multiple repeats)
537 -- 538 --
538 repeat 539 repeat
539 wakeup_at= wakeup_at+period 540 wakeup_at= wakeup_at+period
540 until wakeup_at > now 541 until wakeup_at > now
541 542
542 t2[1]= wakeup_at 543 t2[1]= wakeup_at
@@ -544,7 +545,7 @@ local configure_timers = function()
544 end 545 end
545 546
546 if wakeup_at and ((not next_wakeup) or (wakeup_at < next_wakeup)) then 547 if wakeup_at and ((not next_wakeup) or (wakeup_at < next_wakeup)) then
547 next_wakeup= wakeup_at 548 next_wakeup = wakeup_at
548 end 549 end
549 end 550 end
550 end -- t2 loop 551 end -- t2 loop
@@ -675,7 +676,12 @@ local cancel_error
675local genlock = function(linda_, key_, N) 676local genlock = function(linda_, key_, N)
676 -- clear existing data and set the limit 677 -- clear existing data and set the limit
677 N = N or 1 678 N = N or 1
678 if linda_:set(key_) == cancel_error or linda_:limit(key_, N) == cancel_error then 679 local _status, _err = linda_:set(key_)
680 if _err == cancel_error then
681 return cancel_error
682 end
683 local _status, _err = linda_:limit(key_, N)
684 if _err == cancel_error then
679 return cancel_error 685 return cancel_error
680 end 686 end
681 687
@@ -723,7 +729,12 @@ end -- genlock
723-- 729--
724local genatomic = function(linda_, key_, initial_val_) 730local genatomic = function(linda_, key_, initial_val_)
725 -- clears existing data (also queue). the slot may contain the stored value, and an additional boolean value 731 -- clears existing data (also queue). the slot may contain the stored value, and an additional boolean value
726 if linda_:limit(key_, 2) == cancel_error or linda_:set(key_, initial_val_ or 0.0) == cancel_error then 732 local _status, _err = linda_:limit(key_, 2)
733 if _err == cancel_error then
734 return cancel_error
735 end
736 local _status, _err = linda_:set(key_, initial_val_ or 0.0)
737 if _err == cancel_error then
727 return cancel_error 738 return cancel_error
728 end 739 end
729 740
@@ -734,7 +745,7 @@ local genatomic = function(linda_, key_, initial_val_)
734 if _err == cancel_error then 745 if _err == cancel_error then
735 return cancel_error 746 return cancel_error
736 end 747 end
737 local val = linda_:get(key_) 748 local _, val = linda_:get(key_)
738 if val ~= cancel_error then 749 if val ~= cancel_error then
739 val = val + (diff_ or 1.0) 750 val = val + (diff_ or 1.0)
740 -- set() releases the lock by emptying queue 751 -- set() releases the lock by emptying queue
diff --git a/src/linda.cpp b/src/linda.cpp
index 91138c5..316e917 100644
--- a/src/linda.cpp
+++ b/src/linda.cpp
@@ -393,7 +393,7 @@ LUAG_FUNC(linda_dump)
393// ################################################################################################# 393// #################################################################################################
394 394
395/* 395/*
396 * [val [, ...]] = linda_get( linda_ud, key_num|str|bool|lightuserdata [, count = 1]) 396 * count, [val [, ...]]|nil,cancel_error = linda:get(key_num|str|bool|lightuserdata [, count = 1])
397 * 397 *
398 * Get one or more values from Linda. 398 * Get one or more values from Linda.
399 */ 399 */
@@ -412,9 +412,10 @@ LUAG_FUNC(linda_get)
412 Keeper* const _keeper{ _linda->whichKeeper() }; 412 Keeper* const _keeper{ _linda->whichKeeper() };
413 _pushed = keeper_call(_keeper->K, KEEPER_API(get), L_, _linda, 2); 413 _pushed = keeper_call(_keeper->K, KEEPER_API(get), L_, _linda, 2);
414 } else { // linda is cancelled 414 } else { // linda is cancelled
415 // do nothing and return lanes.cancel_error 415 // do nothing and return nil,lanes.cancel_error
416 lua_pushnil(L_);
416 kCancelError.pushKey(L_); 417 kCancelError.pushKey(L_);
417 _pushed.emplace(1); 418 _pushed.emplace(2);
418 } 419 }
419 // an error can be raised if we attempt to read an unregistered function 420 // an error can be raised if we attempt to read an unregistered function
420 return OptionalValue(_pushed, L_, "tried to copy unsupported types"); 421 return OptionalValue(_pushed, L_, "tried to copy unsupported types");
@@ -425,7 +426,7 @@ LUAG_FUNC(linda_get)
425// ################################################################################################# 426// #################################################################################################
426 427
427/* 428/*
428 * [true] = linda_limit( linda_ud, key_num|str|bool|lightuserdata, [int]) 429 * [bool]|nil,cancel_error = linda:limit(key_num|str|bool|lightuserdata, [int])
429 * 430 *
430 * Set limit to 1 Linda keys. 431 * Set limit to 1 Linda keys.
431 * Optionally wake threads waiting to write on the linda, in case the limit enables them to do so 432 * Optionally wake threads waiting to write on the linda, in case the limit enables them to do so
@@ -450,15 +451,15 @@ LUAG_FUNC(linda_limit)
450 if (_linda->cancelRequest == CancelRequest::None) { 451 if (_linda->cancelRequest == CancelRequest::None) {
451 Keeper* const _keeper{ _linda->whichKeeper() }; 452 Keeper* const _keeper{ _linda->whichKeeper() };
452 _pushed = keeper_call(_keeper->K, KEEPER_API(limit), L_, _linda, 2); 453 _pushed = keeper_call(_keeper->K, KEEPER_API(limit), L_, _linda, 2);
453 LUA_ASSERT(L_, _pushed.has_value() && (_pushed.value() == 0 || _pushed.value() == 1)); // no error, optional boolean value saying if we should wake blocked writer threads 454 LUA_ASSERT(L_, _pushed.has_value() && (_pushed.value() == 1) && luaG_type(L_, -1) == LuaType::BOOLEAN); // no error, boolean value saying if we should wake blocked writer threads
454 if (_pushed.value() == 1) { 455 if (lua_toboolean(L_, -1)) {
455 LUA_ASSERT(L_, luaG_type(L_, -1) == LuaType::BOOLEAN && lua_toboolean(L_, -1) == 1);
456 _linda->readHappened.notify_all(); // To be done from within the 'K' locking area 456 _linda->readHappened.notify_all(); // To be done from within the 'K' locking area
457 } 457 }
458 } else { // linda is cancelled 458 } else { // linda is cancelled
459 // do nothing and return lanes.cancel_error 459 // do nothing and return nil,lanes.cancel_error
460 lua_pushnil(L_);
460 kCancelError.pushKey(L_); 461 kCancelError.pushKey(L_);
461 _pushed.emplace(1); 462 _pushed.emplace(2);
462 } 463 }
463 // propagate pushed boolean if any 464 // propagate pushed boolean if any
464 return _pushed.value(); 465 return _pushed.value();
@@ -470,14 +471,13 @@ LUAG_FUNC(linda_limit)
470 471
471/* 472/*
472 * 2 modes of operation 473 * 2 modes of operation
473 * [val, key]= linda_receive( linda_ud, [timeout_secs_num=nil], key_num|str|bool|lightuserdata [, ...] ) 474 * [val, key]= linda:receive([timeout_secs_num=nil], key_num|str|bool|lightuserdata [, ...] )
474 * Consumes a single value from the Linda, in any key. 475 * Consumes a single value from the Linda, in any key.
475 * Returns: received value (which is consumed from the slot), and the key which had it 476 * Returns: received value (which is consumed from the slot), and the key which had it
476 477
477 * [val1, ... valCOUNT]= linda_receive( linda_ud, [timeout_secs_num=-1], linda.batched, key_num|str|bool|lightuserdata, min_COUNT[, max_COUNT]) 478 * [val1, ... valCOUNT]= linda_receive( linda_ud, [timeout_secs_num=-1], linda.batched, key_num|str|bool|lightuserdata, min_COUNT[, max_COUNT])
478 * Consumes between min_COUNT and max_COUNT values from the linda, from a single key. 479 * Consumes between min_COUNT and max_COUNT values from the linda, from a single key.
479 * returns the actual consumed values, or nil if there weren't enough values to consume 480 * returns the actual consumed values, or nil if there weren't enough values to consume
480 *
481 */ 481 */
482LUAG_FUNC(linda_receive) 482LUAG_FUNC(linda_receive)
483{ 483{
@@ -763,7 +763,7 @@ LUAG_FUNC(linda_send)
763// ################################################################################################# 763// #################################################################################################
764 764
765/* 765/*
766 * [true|lanes.cancel_error] = linda_set( linda_ud, key_num|str|bool|lightuserdata [, value [, ...]]) 766 * [true|nil,lanes.cancel_error] = linda:set(key_num|str|bool|lightuserdata [, value [, ...]])
767 * 767 *
768 * Set one or more value to Linda. Ignores limits. 768 * Set one or more value to Linda. Ignores limits.
769 * 769 *
@@ -773,7 +773,7 @@ LUAG_FUNC(linda_set)
773{ 773{
774 auto set = [](lua_State* L_) { 774 auto set = [](lua_State* L_) {
775 Linda* const _linda{ ToLinda<false>(L_, 1) }; 775 Linda* const _linda{ ToLinda<false>(L_, 1) };
776 bool const _has_value{ lua_gettop(L_) > 2 }; 776 bool const _has_data{ lua_gettop(L_) > 2 };
777 // make sure the key is of a valid type (throws an error if not the case) 777 // make sure the key is of a valid type (throws an error if not the case)
778 check_key_types(L_, 2, 2); 778 check_key_types(L_, 2, 2);
779 779
@@ -782,22 +782,22 @@ LUAG_FUNC(linda_set)
782 if (_linda->cancelRequest == CancelRequest::None) { 782 if (_linda->cancelRequest == CancelRequest::None) {
783 _pushed = keeper_call(_keeper->K, KEEPER_API(set), L_, _linda, 2); 783 _pushed = keeper_call(_keeper->K, KEEPER_API(set), L_, _linda, 2);
784 if (_pushed.has_value()) { // no error? 784 if (_pushed.has_value()) { // no error?
785 LUA_ASSERT(L_, _pushed.value() == 0 || _pushed.value() == 1); 785 LUA_ASSERT(L_, _pushed.value() == 1 && luaG_type(L_, -1) == LuaType::BOOLEAN);
786 786
787 if (_has_value) { 787 if (_has_data) {
788 // we put some data in the slot, tell readers that they should wake 788 // we put some data in the slot, tell readers that they should wake
789 _linda->writeHappened.notify_all(); // To be done from within the 'K' locking area 789 _linda->writeHappened.notify_all(); // To be done from within the 'K' locking area
790 } 790 }
791 if (_pushed.value() == 1) { 791 if (lua_toboolean(L_, -1)) {
792 // the key was full, but it is no longer the case, tell writers they should wake 792 // the key was full, but it is no longer the case, tell writers they should wake
793 LUA_ASSERT(L_, luaG_type(L_, -1) == LuaType::BOOLEAN && lua_toboolean(L_, -1) == 1);
794 _linda->readHappened.notify_all(); // To be done from within the 'K' locking area 793 _linda->readHappened.notify_all(); // To be done from within the 'K' locking area
795 } 794 }
796 } 795 }
797 } else { // linda is cancelled 796 } else { // linda is cancelled
798 // do nothing and return lanes.cancel_error 797 // do nothing and return nil,lanes.cancel_error
798 lua_pushnil(L_);
799 kCancelError.pushKey(L_); 799 kCancelError.pushKey(L_);
800 _pushed.emplace(1); 800 _pushed.emplace(2);
801 } 801 }
802 802
803 // must trigger any error after keeper state has been released 803 // must trigger any error after keeper state has been released