aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2024-06-10 16:49:58 +0200
committerBenoit Germain <benoit.germain@ubisoft.com>2024-06-10 16:49:58 +0200
commitae582acdb1bfb3fb4171682b884545d174e95aa9 (patch)
treeb0c9c0b14f6d57cd8ce1c14d4d23df1adb0bc539
parent3f5c16116a3a7740ac4ac62b663661d772543c2e (diff)
downloadlanes-ae582acdb1bfb3fb4171682b884545d174e95aa9.tar.gz
lanes-ae582acdb1bfb3fb4171682b884545d174e95aa9.tar.bz2
lanes-ae582acdb1bfb3fb4171682b884545d174e95aa9.zip
linda:send() returns nil,<something> in case of error
-rw-r--r--docs/index.html41
-rw-r--r--src/lanes.cpp4
-rw-r--r--src/lanes.lua3
-rw-r--r--src/linda.cpp16
-rw-r--r--tests/basic.lua14
5 files changed, 47 insertions, 31 deletions
diff --git a/docs/index.html b/docs/index.html
index 24c7c52..5675f65 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -1221,7 +1221,7 @@
1221</p> 1221</p>
1222 1222
1223<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> 1223<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre>
1224 true|lanes.cancel_error = h:limit(key, n_uint) 1224 true|(nil,[lanes.cancel_error|"timeout"]) = h:limit(key, n_uint)
1225</pre></td></tr></table> 1225</pre></td></tr></table>
1226 1226
1227<p> 1227<p>
@@ -1238,42 +1238,49 @@
1238 Timeouts are given in seconds (&gt= 0, millisecond accuracy) or <tt>nil</tt>. Timeout can be omitted only if the first key is not a number (then it is equivalent to an infinite duration).<br/> 1238 Timeouts are given in seconds (&gt= 0, millisecond accuracy) or <tt>nil</tt>. Timeout can be omitted only if the first key is not a number (then it is equivalent to an infinite duration).<br/>
1239 Each key acts as a FIFO queue. There is no limit to the number of keys a Linda may contain. Different Lindas can have identical keys, which are totally unrelated. 1239 Each key acts as a FIFO queue. There is no limit to the number of keys a Linda may contain. Different Lindas can have identical keys, which are totally unrelated.
1240</p> 1240</p>
1241
1242<p>
1243 Multiple values can be sent to a given key at once, atomically (the send will fail unless all the values fit within the queue limit). This can be useful for multiple producer scenarios, if the protocols used are giving data in streams of multiple units.
1244 Atomicity avoids the producers from garbling each others messages, which could happen if the units were sent individually.
1245</p>
1246
1241<p> 1247<p>
1242 If no data is provided after the key, <tt>send()</tt> raises an error.<br/> 1248 If no data is provided after the key, <tt>send()</tt> raises an error.<br/>
1243 Also, if <tt>linda.null</tt> or <tt>lanes.null</tt> is sent as data in a Linda, it will be read as a <tt>nil</tt>.<br/> 1249 Also, if <tt>linda.null</tt> or <tt>lanes.null</tt> is sent as data in a Linda, it will be read as a <tt>nil</tt>.<br/>
1244 <tt>send()</tt> returns <tt>true</tt> if the sending succeeded, and <tt>false</tt> if the queue limit was met, and the queue did not empty enough during the given timeout.<br/> 1250 <tt>send()</tt> return values can be:
1245 <tt>send()</tt> returns <tt>lanes.cancel_error</tt> if interrupted by a soft cancel request.<br/> 1251 <ul>
1252 <li><tt>true</tt> on success.</li>
1253 <li><tt>nil, "timeout"</tt> if the queue limit was met, and the queue did not empty enough during the given duration.</li>
1254 <li><tt>nil, lanes.cancel_error</tt> if interrupted by a soft cancel request.</li>
1255 <li>Raises <tt>lanes.cancel_error</tt> if interrupted by a hard cancel request.</li>
1256 </ul>
1246</p> 1257</p>
1247 1258
1248<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> 1259<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre>
1249 key, val = h:receive([timeout_secs,] key [, key...]) 1260 key, val = h:receive([timeout_secs,] key [, key...])
1250 1261
1251 key, val [, val...] = h:receive(timeout, h.batched, key, n_uint_min[, n_uint_max]) 1262 key, val [, val...] = h:receive([timeout,] h.batched, key, n_uint_min[, n_uint_max])
1252</pre></td></tr></table> 1263</pre></td></tr></table>
1253 1264
1254
1255<p>
1256 The <tt>send()</tt> and <tt>receive()</tt> methods use Linda keys as FIFO stacks (first in, first out).<br/>
1257 In batched mode, <tt>linda:receive()</tt> will raise an error if <tt>min_count < 1</tt> or <tt>max_count < min_count</tt>.
1258</p>
1259
1260<p> 1265<p>
1261 Note that any number of lanes can be reading or writing a Linda. There can be many producers, and many consumers. It is up to you. 1266 Unbatched <tt>receive()</tt> return values can be:
1267 <ul>
1268 <li><tt>nil, lanes.cancel_error</tt> if interrupted by a hard cancel request.</li>
1269 <li><tt>nil, "timeout"</tt> if nothing was available.</li>
1270 <li>A key and the value extracted from it. Note that <tt>nil</tt> can be sent and received; the <tt>key</tt> value will tell it apart from a timeout.</li>
1271 </ul>
1262</p> 1272</p>
1263 1273
1264<p> 1274<p>
1265 <a href="#cancelling">Hard cancellation</a> will cause pending Linda operations to abort execution of the lane through a cancellation error. This means that you have to install a <a href="#finalizers">finalizer</a> in your lane if you want to run some code in that situation. 1275 In batched mode, <tt>linda:receive()</tt> will raise an error if <tt>min_count < 1</tt> or <tt>max_count < min_count</tt>.
1266</p> 1276</p>
1267 1277
1268<p> 1278<p>
1269 Equally, <tt>receive()</tt> returns a key and the value extracted from it. Note that <tt>nil</tt>s can be sent and received; the <tt>key</tt> value will tell it apart from a timeout.<br/> 1279 Note that any number of lanes can be reading or writing a Linda. There can be many producers, and many consumers. It is up to you.
1270 <tt>receive()</tt> returns <tt>nil, lanes.cancel_error</tt> if interrupted by a hard cancel request.<br/>
1271 <tt>receive()</tt> returns <tt>nil, "timeout"</tt> if nothing was available.
1272</p> 1280</p>
1273 1281
1274<p> 1282<p>
1275 Multiple values can be sent to a given key at once, atomically (the send will fail unless all the values fit within the queue limit). This can be useful for multiple producer scenarios, if the protocols used are giving data in streams of multiple units. 1283 Remember that <a href="#cancelling">Hard cancellation</a> will cause pending Linda operations to abort execution of the lane through a cancellation error. This means that you have to install a <a href="#finalizers">finalizer</a> in your lane if you want to run some code in that situation.
1276 Atomicity avoids the producers from garbling each others messages, which could happen if the units were sent individually.
1277</p> 1284</p>
1278 1285
1279<p> 1286<p>
diff --git a/src/lanes.cpp b/src/lanes.cpp
index 9b3b28c..5d40ed4 100644
--- a/src/lanes.cpp
+++ b/src/lanes.cpp
@@ -867,10 +867,10 @@ LANES_API void luaopen_lanes_embedded(lua_State* L_, lua_CFunction _luaopen_lane
867{ 867{
868 STACK_CHECK_START_REL(L_, 0); 868 STACK_CHECK_START_REL(L_, 0);
869 // pre-require lanes.core so that when lanes.lua calls require "lanes.core" it finds it is already loaded 869 // pre-require lanes.core so that when lanes.lua calls require "lanes.core" it finds it is already loaded
870 luaL_requiref(L_, "lanes.core", luaopen_lanes_core, 0); // L_: ... lanes.core 870 luaL_requiref(L_, kLanesCoreLibName, luaopen_lanes_core, 0); // L_: ... lanes.core
871 lua_pop(L_, 1); // L_: ... 871 lua_pop(L_, 1); // L_: ...
872 STACK_CHECK(L_, 0); 872 STACK_CHECK(L_, 0);
873 // call user-provided function that runs the chunk "lanes.lua" from wherever they stored it 873 // call user-provided function that runs the chunk "lanes.lua" from wherever they stored it
874 luaL_requiref(L_, "lanes", _luaopen_lanes ? _luaopen_lanes : default_luaopen_lanes, 0); // L_: ... lanes 874 luaL_requiref(L_, kLanesLibName, _luaopen_lanes ? _luaopen_lanes : default_luaopen_lanes, 0); // L_: ... lanes
875 STACK_CHECK(L_, 1); 875 STACK_CHECK(L_, 1);
876} 876}
diff --git a/src/lanes.lua b/src/lanes.lua
index 95c4eff..92e773a 100644
--- a/src/lanes.lua
+++ b/src/lanes.lua
@@ -728,7 +728,8 @@ local genatomic = function(linda_, key_, initial_val_)
728 return function(diff_) 728 return function(diff_)
729 -- 'nil' allows 'key_' to be numeric 729 -- 'nil' allows 'key_' to be numeric
730 -- suspends until our 'true' is in 730 -- suspends until our 'true' is in
731 if linda_:send(nil, key_, true) == cancel_error then 731 local _res, _err = linda_:send(nil, key_, true)
732 if _err == cancel_error then
732 return cancel_error 733 return cancel_error
733 end 734 end
734 local val = linda_:get(key_) 735 local val = linda_:get(key_)
diff --git a/src/linda.cpp b/src/linda.cpp
index 4dc2162..1bd5d16 100644
--- a/src/linda.cpp
+++ b/src/linda.cpp
@@ -709,17 +709,25 @@ LUAG_FUNC(linda_send)
709 709
710 switch (_cancel) { 710 switch (_cancel) {
711 case CancelRequest::Soft: 711 case CancelRequest::Soft:
712 // if user wants to soft-cancel, the call returns lanes.cancel_error 712 // if user wants to soft-cancel, the call returns nil, kCancelError
713 lua_pushnil(L_);
713 kCancelError.pushKey(L_); 714 kCancelError.pushKey(L_);
714 return 1; 715 return 2;
715 716
716 case CancelRequest::Hard: 717 case CancelRequest::Hard:
717 // raise an error interrupting execution only in case of hard cancel 718 // raise an error interrupting execution only in case of hard cancel
718 raise_cancel_error(L_); // raises an error and doesn't return 719 raise_cancel_error(L_); // raises an error and doesn't return
719 720
720 default: 721 default:
721 lua_pushboolean(L_, _ret); // true (success) or false (timeout) 722 if (_ret) {
722 return 1; 723 lua_pushboolean(L_, _ret); // true (success)
724 return 1;
725 } else {
726 // not enough room in the Linda slot to fulfill the request, return nil, "timeout"
727 lua_pushnil(L_);
728 std::ignore = luaG_pushstring(L_, "timeout");
729 return 2;
730 }
723 } 731 }
724 }; 732 };
725 return Linda::ProtectedCall(L_, _send); 733 return Linda::ProtectedCall(L_, _send);
diff --git a/tests/basic.lua b/tests/basic.lua
index 28f0334..cad3764 100644
--- a/tests/basic.lua
+++ b/tests/basic.lua
@@ -218,16 +218,16 @@ local function WR(...) io.stderr:write(...) end
218 218
219local chunk= function(linda) 219local chunk= function(linda)
220 local function receive() return linda:receive("->") end 220 local function receive() return linda:receive("->") end
221 local function send(...) linda:send("<-", ...) end 221 local function send(...) local _res, _err = linda:send("<-", ...) assert(_res == true and _err == nil) end
222 222
223 WR("chunk ", "Lane starts!\n") 223 WR("chunk ", "Lane starts!\n")
224 224
225 local k,v 225 local k,v
226 k,v=receive(); WR("chunk ", v.." received (expecting 1)\n"); assert(v==1) 226 k,v=receive(); WR("chunk ", v.." received (expecting 1)\n"); assert(k and v==1)
227 k,v=receive(); WR("chunk ", v.." received (expecting 2)\n"); assert(v==2) 227 k,v=receive(); WR("chunk ", v.." received (expecting 2)\n"); assert(k and v==2)
228 k,v=receive(); WR("chunk ", v.." received (expecting 3)\n"); assert(v==3) 228 k,v=receive(); WR("chunk ", v.." received (expecting 3)\n"); assert(k and v==3)
229 k,v=receive(); WR("chunk ", tostring(v).." received (expecting nil from __lanesconvert)\n"); assert(v==nil, "table with __lanesconvert==lanes.null should be received as nil, got " .. tostring(v)) -- a table with __lanesconvert was sent 229 k,v=receive(); WR("chunk ", tostring(v).." received (expecting nil from __lanesconvert)\n"); assert(k and v==nil, "table with __lanesconvert==lanes.null should be received as nil, got " .. tostring(v)) -- a table with __lanesconvert was sent
230 k,v=receive(); WR("chunk ", tostring(v).." received (expecting nil)\n"); assert(v==nil) 230 k,v=receive(); WR("chunk ", tostring(v).." received (expecting nil)\n"); assert(k and v==nil)
231 231
232 send(4,5,6); WR("chunk ", "4,5,6 sent\n") 232 send(4,5,6); WR("chunk ", "4,5,6 sent\n")
233 send 'aaa'; WR("chunk ", "'aaa' sent\n") 233 send 'aaa'; WR("chunk ", "'aaa' sent\n")
@@ -269,7 +269,7 @@ assert(x == nil and y == nil and z == nil and w == nil)
269WR "ok\n" 269WR "ok\n"
270 270
271local function PEEK(...) return linda:get("<-", ...) end 271local function PEEK(...) return linda:get("<-", ...) end
272local function SEND(...) linda:send("->", ...) end 272local function SEND(...) local _res, _err = linda:send("->", ...) assert(_res == true and _err == nil) end
273local function RECEIVE() local k,v = linda:receive(1, "<-") return v end 273local function RECEIVE() local k,v = linda:receive(1, "<-") return v end
274 274
275local comms_lane = lanes_gen("io", {gc_cb = gc_cb, name = "auto"}, chunk)(linda) -- prepare & launch 275local comms_lane = lanes_gen("io", {gc_cb = gc_cb, name = "auto"}, chunk)(linda) -- prepare & launch