diff options
-rw-r--r-- | src/intercopycontext.cpp | 15 | ||||
-rw-r--r-- | src/keeper.cpp | 20 | ||||
-rw-r--r-- | src/keeper.h | 1 | ||||
-rw-r--r-- | src/linda.cpp | 13 | ||||
-rw-r--r-- | tests/basic.lua | 42 |
5 files changed, 35 insertions, 56 deletions
diff --git a/src/intercopycontext.cpp b/src/intercopycontext.cpp index 0301382..6ebbbb0 100644 --- a/src/intercopycontext.cpp +++ b/src/intercopycontext.cpp | |||
@@ -28,6 +28,7 @@ THE SOFTWARE. | |||
28 | 28 | ||
29 | #include "debugspew.h" | 29 | #include "debugspew.h" |
30 | #include "deep.h" | 30 | #include "deep.h" |
31 | #include "keeper.h" | ||
31 | #include "universe.h" | 32 | #include "universe.h" |
32 | 33 | ||
33 | // ################################################################################################# | 34 | // ################################################################################################# |
@@ -887,7 +888,12 @@ void InterCopyContext::inter_copy_keyvaluepair() const | |||
887 | { | 888 | { |
888 | void* const _p{ lua_touserdata(L1, L1_i) }; | 889 | void* const _p{ lua_touserdata(L1, L1_i) }; |
889 | DEBUGSPEW_CODE(fprintf(stderr, "%p\n", _p)); | 890 | DEBUGSPEW_CODE(fprintf(stderr, "%p\n", _p)); |
890 | lua_pushlightuserdata(L2, _p); | 891 | // when copying a nil sentinel in a non-keeper, write a nil in the destination |
892 | if (mode != LookupMode::ToKeeper && kNilSentinel.equals(L1, L1_i)) { | ||
893 | lua_pushnil(L2); | ||
894 | } else { | ||
895 | lua_pushlightuserdata(L2, _p); | ||
896 | } | ||
891 | return true; | 897 | return true; |
892 | } | 898 | } |
893 | 899 | ||
@@ -898,7 +904,12 @@ void InterCopyContext::inter_copy_keyvaluepair() const | |||
898 | if (vt == VT::KEY) { | 904 | if (vt == VT::KEY) { |
899 | return false; | 905 | return false; |
900 | } | 906 | } |
901 | lua_pushnil(L2); | 907 | // when copying a nil in a keeper, write a nil sentinel in the destination |
908 | if (mode == LookupMode::ToKeeper) { | ||
909 | kNilSentinel.pushKey(L2); | ||
910 | } else { | ||
911 | lua_pushnil(L2); | ||
912 | } | ||
902 | return true; | 913 | return true; |
903 | } | 914 | } |
904 | 915 | ||
diff --git a/src/keeper.cpp b/src/keeper.cpp index 9bde2d5..b0ed062 100644 --- a/src/keeper.cpp +++ b/src/keeper.cpp | |||
@@ -569,26 +569,6 @@ void Linda::releaseKeeper(Keeper* K_) const | |||
569 | 569 | ||
570 | // ################################################################################################# | 570 | // ################################################################################################# |
571 | 571 | ||
572 | void keeper_toggle_nil_sentinels(lua_State* L_, int start_, LookupMode const mode_) | ||
573 | { | ||
574 | int const _n{ lua_gettop(L_) }; | ||
575 | for (int _i = start_; _i <= _n; ++_i) { | ||
576 | if (mode_ == LookupMode::ToKeeper) { | ||
577 | if (lua_isnil(L_, _i)) { | ||
578 | kNilSentinel.pushKey(L_); | ||
579 | lua_replace(L_, _i); | ||
580 | } | ||
581 | } else { | ||
582 | if (kNilSentinel.equals(L_, _i)) { | ||
583 | lua_pushnil(L_); | ||
584 | lua_replace(L_, _i); | ||
585 | } | ||
586 | } | ||
587 | } | ||
588 | } | ||
589 | |||
590 | // ################################################################################################# | ||
591 | |||
592 | /* | 572 | /* |
593 | * Call a function ('func_name') in the keeper state, and pass on the returned | 573 | * Call a function ('func_name') in the keeper state, and pass on the returned |
594 | * values to 'L'. | 574 | * values to 'L'. |
diff --git a/src/keeper.h b/src/keeper.h index 62d9ec8..a902caa 100644 --- a/src/keeper.h +++ b/src/keeper.h | |||
@@ -40,7 +40,6 @@ struct Keepers | |||
40 | // xxh64 of string "kNilSentinel" generated at https://www.pelock.com/products/hash-calculator | 40 | // xxh64 of string "kNilSentinel" generated at https://www.pelock.com/products/hash-calculator |
41 | static constexpr UniqueKey kNilSentinel{ 0xC457D4EDDB05B5E4ull, "lanes.null" }; | 41 | static constexpr UniqueKey kNilSentinel{ 0xC457D4EDDB05B5E4ull, "lanes.null" }; |
42 | 42 | ||
43 | void keeper_toggle_nil_sentinels(lua_State* L_, int start_, LookupMode const mode_); | ||
44 | [[nodiscard]] int keeper_push_linda_storage(Linda& linda_, DestState L_); | 43 | [[nodiscard]] int keeper_push_linda_storage(Linda& linda_, DestState L_); |
45 | 44 | ||
46 | using keeper_api_t = lua_CFunction; | 45 | using keeper_api_t = lua_CFunction; |
diff --git a/src/linda.cpp b/src/linda.cpp index 1916629..4bd4553 100644 --- a/src/linda.cpp +++ b/src/linda.cpp | |||
@@ -344,9 +344,6 @@ LUAG_FUNC(linda_get) | |||
344 | if (_linda->cancelRequest == CancelRequest::None) { | 344 | if (_linda->cancelRequest == CancelRequest::None) { |
345 | Keeper* const _K{ _linda->whichKeeper() }; | 345 | Keeper* const _K{ _linda->whichKeeper() }; |
346 | _pushed = keeper_call(_K->L, KEEPER_API(get), L_, _linda, 2); | 346 | _pushed = keeper_call(_K->L, KEEPER_API(get), L_, _linda, 2); |
347 | if (_pushed.value_or(0) > 0) { | ||
348 | keeper_toggle_nil_sentinels(L_, lua_gettop(L_) - _pushed.value(), LookupMode::FromKeeper); | ||
349 | } | ||
350 | } else { // linda is cancelled | 347 | } else { // linda is cancelled |
351 | // do nothing and return lanes.cancel_error | 348 | // do nothing and return lanes.cancel_error |
352 | kCancelError.pushKey(L_); | 349 | kCancelError.pushKey(L_); |
@@ -492,10 +489,6 @@ LUAG_FUNC(linda_receive) | |||
492 | } | 489 | } |
493 | if (_pushed.value() > 0) { | 490 | if (_pushed.value() > 0) { |
494 | LUA_ASSERT(L_, _pushed.value() >= _expected_pushed_min && _pushed.value() <= _expected_pushed_max); | 491 | LUA_ASSERT(L_, _pushed.value() >= _expected_pushed_min && _pushed.value() <= _expected_pushed_max); |
495 | // replace sentinels with real nils | ||
496 | keeper_toggle_nil_sentinels(L_, lua_gettop(L_) - _pushed.value(), LookupMode::FromKeeper); | ||
497 | // To be done from within the 'K' locking area | ||
498 | // | ||
499 | _linda->readHappened.notify_all(); | 492 | _linda->readHappened.notify_all(); |
500 | break; | 493 | break; |
501 | } | 494 | } |
@@ -589,8 +582,6 @@ LUAG_FUNC(linda_send) | |||
589 | raise_luaL_error(L_, "no data to send"); | 582 | raise_luaL_error(L_, "no data to send"); |
590 | } | 583 | } |
591 | 584 | ||
592 | // convert nils to some special non-nil sentinel in sent values | ||
593 | keeper_toggle_nil_sentinels(L_, _key_i + 1, LookupMode::ToKeeper); | ||
594 | bool _ret{ false }; | 585 | bool _ret{ false }; |
595 | CancelRequest _cancel{ CancelRequest::None }; | 586 | CancelRequest _cancel{ CancelRequest::None }; |
596 | KeeperCallResult _pushed; | 587 | KeeperCallResult _pushed; |
@@ -701,10 +692,6 @@ LUAG_FUNC(linda_set) | |||
701 | Keeper* const _K{ _linda->whichKeeper() }; | 692 | Keeper* const _K{ _linda->whichKeeper() }; |
702 | KeeperCallResult _pushed; | 693 | KeeperCallResult _pushed; |
703 | if (_linda->cancelRequest == CancelRequest::None) { | 694 | if (_linda->cancelRequest == CancelRequest::None) { |
704 | if (_has_value) { | ||
705 | // convert nils to some special non-nil sentinel in sent values | ||
706 | keeper_toggle_nil_sentinels(L_, 3, LookupMode::ToKeeper); | ||
707 | } | ||
708 | _pushed = keeper_call(_K->L, KEEPER_API(set), L_, _linda, 2); | 695 | _pushed = keeper_call(_K->L, KEEPER_API(set), L_, _linda, 2); |
709 | if (_pushed.has_value()) { // no error? | 696 | if (_pushed.has_value()) { // no error? |
710 | LUA_ASSERT(L_, _pushed.value() == 0 || _pushed.value() == 1); | 697 | LUA_ASSERT(L_, _pushed.value() == 0 || _pushed.value() == 1); |
diff --git a/tests/basic.lua b/tests/basic.lua index d65728e..5a905e7 100644 --- a/tests/basic.lua +++ b/tests/basic.lua | |||
@@ -214,26 +214,27 @@ local chunk= function(linda) | |||
214 | local function receive() return linda:receive("->") end | 214 | local function receive() return linda:receive("->") end |
215 | local function send(...) linda:send("<-", ...) end | 215 | local function send(...) linda:send("<-", ...) end |
216 | 216 | ||
217 | WR("Lane starts!\n") | 217 | WR("chunk ", "Lane starts!\n") |
218 | 218 | ||
219 | local k,v | 219 | local k,v |
220 | k,v=receive(); WR(v.." received\n"); assert(v==1) | 220 | k,v=receive(); WR("chunk ", v.." received (expecting 1)\n"); assert(v==1) |
221 | k,v=receive(); WR(v.." received\n"); assert(v==2) | 221 | k,v=receive(); WR("chunk ", v.." received (expecting 2)\n"); assert(v==2) |
222 | k,v=receive(); WR(v.." received\n"); assert(v==3) | 222 | k,v=receive(); WR("chunk ", v.." received (expecting 3)\n"); assert(v==3) |
223 | k,v=receive(); WR(tostring(v).." received\n"); assert(v==nil) | 223 | k,v=receive(); WR("chunk ", tostring(v).." received (expecting nil from __lanesignore)\n"); assert(v==nil) -- a table with __lanesignore was sent |
224 | k,v=receive(); WR("chunk ", tostring(v).." received (expecting nil)\n"); assert(v==nil) | ||
224 | 225 | ||
225 | send(1,2,3); WR("1,2,3 sent\n") | 226 | send(4,5,6); WR("chunk ", "4,5,6 sent\n") |
226 | send 'a'; WR("'a' sent\n") | 227 | send 'aaa'; WR("chunk ", "'aaa' sent\n") |
227 | send(nil); WR("nil sent\n") | 228 | send(nil); WR("chunk ", "nil sent\n") |
228 | send { 'a', 'b', 'c', d=10 }; WR("{'a','b','c',d=10} sent\n") | 229 | send { 'a', 'b', 'c', d=10 }; WR("chunk ","{'a','b','c',d=10} sent\n") |
229 | 230 | ||
230 | k,v=receive(); WR(v.." received\n"); assert(v==4) | 231 | k,v=receive(); WR("chunk ", v.." received\n"); assert(v==4) |
231 | 232 | ||
232 | local subT1 = { "subT1"} | 233 | local subT1 = { "subT1"} |
233 | local subT2 = { "subT2"} | 234 | local subT2 = { "subT2"} |
234 | send { subT1, subT2, subT1, subT2}; WR("{ subT1, subT2, subT1, subT2} sent\n") | 235 | send { subT1, subT2, subT1, subT2}; WR("chunk ", "{ subT1, subT2, subT1, subT2} sent\n") |
235 | 236 | ||
236 | WR("Lane ends!\n") | 237 | WR("chunk ", "Lane ends!\n") |
237 | end | 238 | end |
238 | 239 | ||
239 | local linda = lanes_linda("communications") | 240 | local linda = lanes_linda("communications") |
@@ -248,15 +249,16 @@ local function RECEIVE() local k,v = linda:receive(1, "<-") return v end | |||
248 | 249 | ||
249 | local comms_lane = lanes_gen("io", {gc_cb = gc_cb, name = "auto"}, chunk)(linda) -- prepare & launch | 250 | local comms_lane = lanes_gen("io", {gc_cb = gc_cb, name = "auto"}, chunk)(linda) -- prepare & launch |
250 | 251 | ||
251 | SEND(1); WR("1 sent\n") | 252 | SEND(1); WR("main ", "1 sent\n") |
252 | SEND(2); WR("2 sent\n") | 253 | SEND(2); WR("main ", "2 sent\n") |
253 | SEND(3); WR("3 sent\n") | 254 | SEND(3); WR("main ", "3 sent\n") |
255 | SEND(setmetatable({"should be ignored"},{__lanesignore=true})); WR("main ", "__lanesignore table sent\n") | ||
254 | for i=1,100 do | 256 | for i=1,100 do |
255 | WR "." | 257 | WR "." |
256 | lanes.sleep(0.0001) | 258 | lanes.sleep(0.0001) |
257 | assert(PEEK() == nil) -- nothing coming in, yet | 259 | assert(PEEK() == nil) -- nothing coming in, yet |
258 | end | 260 | end |
259 | SEND(nil); WR("\nnil sent\n") | 261 | SEND(nil); WR("\nmain ", "nil sent\n") |
260 | 262 | ||
261 | local a,b,c = RECEIVE(), RECEIVE(), RECEIVE() | 263 | local a,b,c = RECEIVE(), RECEIVE(), RECEIVE() |
262 | 264 | ||
@@ -264,13 +266,13 @@ print("lane status: " .. comms_lane.status) | |||
264 | if comms_lane.status == "error" then | 266 | if comms_lane.status == "error" then |
265 | print(comms_lane:join()) | 267 | print(comms_lane:join()) |
266 | else | 268 | else |
267 | WR(a..", "..b..", "..c.." received\n") | 269 | WR("main ", tostring(a)..", "..tostring(b)..", "..tostring(c).." received\n") |
268 | end | 270 | end |
269 | 271 | ||
270 | assert(a==1 and b==2 and c==3) | 272 | assert(a==4 and b==5 and c==6) |
271 | 273 | ||
272 | local a = RECEIVE(); WR(a.." received\n") | 274 | local aaa = RECEIVE(); WR("main ", aaa.." received\n") |
273 | assert(a=='a') | 275 | assert(aaa=='aaa') |
274 | 276 | ||
275 | local null = RECEIVE(); WR(tostring(null).." received\n") | 277 | local null = RECEIVE(); WR(tostring(null).." received\n") |
276 | assert(null==nil) | 278 | assert(null==nil) |