aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2024-06-27 12:40:36 +0200
committerBenoit Germain <benoit.germain@ubisoft.com>2024-06-27 12:40:36 +0200
commit726aee3fbb909946e69866cc6c4497c5ec365fe8 (patch)
tree3d90edeb2a97039b464e7e61e7d87d901319e625
parent62a7eab66f8f6af66c94390138815c3171b62810 (diff)
downloadlanes-726aee3fbb909946e69866cc6c4497c5ec365fe8.tar.gz
lanes-726aee3fbb909946e69866cc6c4497c5ec365fe8.tar.bz2
lanes-726aee3fbb909946e69866cc6c4497c5ec365fe8.zip
linda:limit() and linda:set() return a second value, a string representing the fill status
Diffstat (limited to '')
-rw-r--r--docs/index.html37
-rw-r--r--src/keeper.cpp75
-rw-r--r--src/lane.cpp2
-rw-r--r--src/lanes.lua3
-rw-r--r--src/linda.cpp20
-rw-r--r--tests/atomic.lua1
6 files changed, 92 insertions, 46 deletions
diff --git a/docs/index.html b/docs/index.html
index 8e84fcb..148b5ab 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -1222,15 +1222,16 @@
1222</p> 1222</p>
1223 1223
1224<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> 1224<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre>
1225 bool|(nil,[lanes.cancel_error|"timeout"]) = h:limit(key, &lt;limit&gt;) 1225 bool,string|(nil,[lanes.cancel_error|"timeout"]) = h:limit(key, &lt;limit&gt;)
1226 &gt;limit&lt; = h:limit(key) 1226 (number|string),string = h:limit(key)
1227</pre></td></tr></table> 1227</pre></td></tr></table>
1228 1228
1229<p> 1229<p>
1230 By default, queue sizes are unlimited but limits can be enforced using the <tt>limit()</tt> method. This can be useful to balance execution speeds in a producer/consumer scenario.<br /> 1230 By default, queue sizes are unlimited but limits can be enforced using the <tt>limit()</tt> method. This can be useful to balance execution speeds in a producer/consumer scenario.<br />
1231 A limit of 0 is allowed to block everything. <tt>"unlimited"</tt> removes the limit.<br /> 1231 A limit of 0 is allowed to block everything. <tt>"unlimited"</tt> removes the limit.<br />
1232 If the key was full but the limit change added some room, <tt>limit()</tt> returns <tt>true</tt> and the Linda is signalled so that <tt>send()</tt>-blocked threads are awakened, else the return value is <tt>false</tt>. 1232 If the key was full but the limit change added some room, <tt>limit()</tt> first return value is <tt>true</tt> and the Linda is signalled so that <tt>send()</tt>-blocked threads are awakened, else the return value is <tt>false</tt>.
1233 If no limit is provided, <tt>limit()</tt> returns a single value, the current limit for the specified key.<br /> 1233 If no limit is provided, <tt>limit()</tt> first return value is the current limit for the specified key.<br />
1234 The second returned value is a string representing the fill status relatively to the key's current limit (one of <tt>"over"</tt>, <tt>"under"</tt>, <tt>"exact"</tt>).
1234 Whether reading or writing, if the Linda is cancelled, <tt>limit()</tt> returns <tt>nil, lanes.cancel_error</tt>. 1235 Whether reading or writing, if the Linda is cancelled, <tt>limit()</tt> returns <tt>nil, lanes.cancel_error</tt>.
1235</p> 1236</p>
1236 1237
@@ -1292,30 +1293,30 @@
1292</p> 1293</p>
1293 1294
1294<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> 1295<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre>
1295 true|nil,lanes.cancel_error = linda_h:set(key [, val [, ...]]) 1296 (bool,string)|(nil,lanes.cancel_error) = linda_h:set(key [, val [, ...]])
1296 1297
1297 [number,[val [, ...]]|nil,lanes.cancel_error] = linda_h:get(key [, count = 1]) 1298 (number,[val [, ...]])|(nil,lanes.cancel_error) = linda_h:get(key [, count = 1])
1298</pre></td></tr></table> 1299</pre></td></tr></table>
1299 1300
1300<p> 1301<p>
1301 The table access methods are for accessing a slot without queuing or consuming. They can be used for making shared tables of storage among the lanes.<br /> 1302 <tt>get()</tt>/<tt>set()</tt> and <tt>send()</tt>/<tt>receive()</tt> can be used together; reading a slot essentially peeks the next outcoming value of a queue.<br />
1302 Writing to a slot never blocks because it ignores the limit. It overwrites existing value and clears any possible queued entries.<br /> 1303 <tt>get()</tt>/<tt>set()</tt> are for accessing a key without queuing or consuming. They can be used for making shared tables of storage among the lanes.<br />
1303 Reading doesn't block either because <tt>get()</tt> returns: 1304 Writing to a key never blocks because it ignores the limit. It overwrites existing values and clears any possible queued entries.<br />
1305</p>
1306<p>
1307 <tt>get()</tt> can read several values at once, and does not block. Return values ares:
1304 <ul> 1308 <ul>
1305 <li><tt>nil, lanes.cancel_error</tt> in case of cancellation.</li> 1309 <li><tt>nil, lanes.cancel_error</tt> in case of cancellation.</li>
1306 <li><tt>number, val...</tt> where number is the actual count of items obtained from the linda (can be 0).</li> 1310 <li><tt>number, val...</tt> where number is the actual count of items obtained from the linda (can be 0).</li>
1307 </ul> 1311 </ul>
1308 Table access and <tt>send()</tt>/<tt>receive()</tt> can be used together; reading a slot essentially peeks the next outcoming value of a queue.
1309</p>
1310
1311<p>
1312 <tt>set()</tt> signals the Linda for write if a value is stored. If nothing special happens, <tt>set() </tt>returns nothing.<br />
1313 If the key was full but the new data count of the key after <tt>set()</tt> is below its limit, <tt>set()</tt> returns <tt>true</tt> and the Linda is also signaled for read so that <tt>send()</tt>-blocked threads are awakened.
1314</p> 1312</p>
1315
1316<p> 1313<p>
1317 <tt>set()</tt> can write several values at the specified key, writing <tt>nil</tt> values is now possible, and clearing the contents at the specified key is done by not providing any value.<br /> 1314 <tt>set()</tt> can write several values at the specified key. Writing <tt>nil</tt> values is possible, and clearing the contents at the specified key is done by not providing any value.<br />
1318 Also, <tt>get()</tt> can read several values at once. If the key contains no data, <tt>get()</tt> returns no value. This can be used to separate the case when reading stored <tt>nil</tt> values. 1315 If <tt>set()</tt> actually stores data, the Linda is signalled for write, so that <tt>receive()</tt>-blocked Lanes are awakened.<br />
1316 Clearing the contents of a non-existent key does not create it!<br />
1317 If the key was full but the new data count of the key after <tt>set()</tt> is below its limit, <tt>set()</tt> first return value is <tt>true</tt> and the Linda is also signaled for read, so that <tt>send()</tt>-blocked Lanes are awakened.<br />
1318 If the key was not already full, nothing additional happens, and <tt>set()</tt> first return value is <tt>false</tt>.<br />
1319 The second return value is a string representing the fill status relatively to the key's current limit (one of <tt>"over"</tt>, <tt>"under"</tt>, <tt>"exact"</tt>).
1319</p> 1320</p>
1320 1321
1321<p> 1322<p>
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 }
diff --git a/tests/atomic.lua b/tests/atomic.lua
index 2de8f52..511a19e 100644
--- a/tests/atomic.lua
+++ b/tests/atomic.lua
@@ -9,6 +9,7 @@ local lanes = require "lanes"
9local linda= lanes.linda() 9local linda= lanes.linda()
10local key= "$" 10local key= "$"
11 11
12-- TODO: test what happens when we cancel the linda
12local f= lanes.genatomic( linda, key, 5 ) 13local f= lanes.genatomic( linda, key, 5 )
13 14
14local v 15local v