diff options
| author | Benoit Germain <benoit.germain@ubisoft.com> | 2025-06-05 16:03:22 +0200 |
|---|---|---|
| committer | Benoit Germain <benoit.germain@ubisoft.com> | 2025-06-05 16:03:22 +0200 |
| commit | bfdc7a92c4e3e99522abb6d90ef2cbb021f36fc8 (patch) | |
| tree | 00f6633878b21dda6cad1177d5619a501b4ac0a4 | |
| parent | f73702bcf4372a149b8b01a512c0e086b1e679e2 (diff) | |
| download | lanes-bfdc7a92c4e3e99522abb6d90ef2cbb021f36fc8.tar.gz lanes-bfdc7a92c4e3e99522abb6d90ef2cbb021f36fc8.tar.bz2 lanes-bfdc7a92c4e3e99522abb6d90ef2cbb021f36fc8.zip | |
Change lane:join() return values
* when no error is raised in the lane, lane:join() now precedes the lane returned values with true
* lane body is no longer forced to return something when used with join()
* adjusted all relevant unit tests accordingly
| -rw-r--r-- | CHANGES | 8 | ||||
| -rw-r--r-- | docs/index.html | 6 | ||||
| -rw-r--r-- | src/lane.cpp | 34 | ||||
| -rw-r--r-- | tests/appendud.lua | 2 | ||||
| -rw-r--r-- | tests/basic.lua | 17 | ||||
| -rw-r--r-- | tests/error.lua | 7 | ||||
| -rw-r--r-- | tests/finalizer.lua | 4 | ||||
| -rw-r--r-- | tests/func_is_string.lua | 13 | ||||
| -rw-r--r-- | tests/launchtest.lua | 4 | ||||
| -rw-r--r-- | tests/linda_perf.lua | 7 | ||||
| -rw-r--r-- | tests/perftest.lua | 4 | ||||
| -rw-r--r-- | tests/pingpong.lua | 8 | ||||
| -rw-r--r-- | tests/rupval.lua | 6 | ||||
| -rw-r--r-- | tests/tobeclosed.lua | 5 | ||||
| -rw-r--r-- | unit_tests/scripts/coro/basics.lua | 6 | ||||
| -rw-r--r-- | unit_tests/scripts/lane/tasking_join_test.lua | 16 | ||||
| -rw-r--r-- | unit_tests/scripts/linda/wake_period.lua | 5 |
17 files changed, 85 insertions, 67 deletions
| @@ -1,6 +1,6 @@ | |||
| 1 | CHANGES: | 1 | CHANGES: |
| 2 | 2 | ||
| 3 | CHANGE 2: BGe 27-Nov-24 | 3 | CHANGE 2: BGe 05-Jun-25 |
| 4 | * Internal changes | 4 | * Internal changes |
| 5 | - Lanes is implemented in C++20: thread, condition_variable, mutex, string_view, variant, lambdas, templates, and more! | 5 | - Lanes is implemented in C++20: thread, condition_variable, mutex, string_view, variant, lambdas, templates, and more! |
| 6 | - Almost all platform-specific code is gone (only a small bit for thread priority and affinity remains). | 6 | - Almost all platform-specific code is gone (only a small bit for thread priority and affinity remains). |
| @@ -37,11 +37,9 @@ CHANGE 2: BGe 27-Nov-24 | |||
| 37 | - name added. Can be used to set the name early (before the lane body calls lane_threadname()). | 37 | - name added. Can be used to set the name early (before the lane body calls lane_threadname()). |
| 38 | - New generator lanes.coro() to start a lane as a coroutine. | 38 | - New generator lanes.coro() to start a lane as a coroutine. |
| 39 | - New __close metamethod that calls join(). | 39 | - New __close metamethod that calls join(). |
| 40 | - lane:join() | 40 | - lane:join() returns nil, error in case of problem, else returns true followed by the lane body return values. |
| 41 | - Returns nil, error in case of problem. | ||
| 42 | - Forces lane function body must return a non-nil first value on success because of the above. | ||
| 43 | - lane:get_debug_threadname() renamed get_threadname(). | 41 | - lane:get_debug_threadname() renamed get_threadname(). |
| 44 | - cancel_test() returns "soft"/"hard" instead of true when a cancellation request is active | 42 | - cancel_test() returns "soft"/"hard" instead of true when a cancellation request is active. |
| 45 | - Lindas: | 43 | - Lindas: |
| 46 | - lanes.linda() | 44 | - lanes.linda() |
| 47 | - Arguments can be provided in any order. | 45 | - Arguments can be provided in any order. |
diff --git a/docs/index.html b/docs/index.html index be8ad7f..ab8aed2 100644 --- a/docs/index.html +++ b/docs/index.html | |||
| @@ -71,7 +71,7 @@ | |||
| 71 | </p> | 71 | </p> |
| 72 | 72 | ||
| 73 | <p> | 73 | <p> |
| 74 | This document was revised on 07-May-25, and applies to version <tt>4.0.0</tt>. | 74 | This document was revised on 05-Jun-25, and applies to version <tt>4.0.0</tt>. |
| 75 | </p> | 75 | </p> |
| 76 | </font> | 76 | </font> |
| 77 | </center> | 77 | </center> |
| @@ -1156,7 +1156,7 @@ | |||
| 1156 | </p> | 1156 | </p> |
| 1157 | 1157 | ||
| 1158 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> | 1158 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> |
| 1159 | [...]|[nil,err,stack_tbl]= lane_h:join([timeout]) | 1159 | [true, ...]|[nil,err,stack_tbl]= lane_h:join([timeout]) |
| 1160 | </pre></td></tr></table> | 1160 | </pre></td></tr></table> |
| 1161 | 1161 | ||
| 1162 | <p> | 1162 | <p> |
| @@ -1174,7 +1174,7 @@ | |||
| 1174 | </ul> | 1174 | </ul> |
| 1175 | </li> | 1175 | </li> |
| 1176 | <li><tt>nil, "killed"</tt> if forcefully killed.</li> | 1176 | <li><tt>nil, "killed"</tt> if forcefully killed.</li> |
| 1177 | <li>The return values of the lane function. If the first return value is <tt>nil</tt> (or there is no return value), an error is raised, to make sure you can tell timeout and error cases apart from successful return.</li> | 1177 | <li><tt>true [, returned-values]</tt>: The return values of the lane function.</li> |
| 1178 | </ul> | 1178 | </ul> |
| 1179 | If the lane handle obtained from <tt>lanes.gen()</tt> is to-be-closed, closing the value will cause a call to <tt>join()</tt>. Since it is implicit, the lane body isn't forced to return non-<tt>nil</tt> in that case. | 1179 | If the lane handle obtained from <tt>lanes.gen()</tt> is to-be-closed, closing the value will cause a call to <tt>join()</tt>. Since it is implicit, the lane body isn't forced to return non-<tt>nil</tt> in that case. |
| 1180 | </p> | 1180 | </p> |
diff --git a/src/lane.cpp b/src/lane.cpp index 65a776e..cb20930 100644 --- a/src/lane.cpp +++ b/src/lane.cpp | |||
| @@ -105,7 +105,7 @@ static LUAG_FUNC(lane_threadname) | |||
| 105 | // ################################################################################################# | 105 | // ################################################################################################# |
| 106 | 106 | ||
| 107 | //--- | 107 | //--- |
| 108 | // [...] | [nil, err_any, stack_tbl]= lane:join([wait_secs]) | 108 | // [true, ...] | [nil, err_any, stack_tbl]= lane:join([wait_secs]) |
| 109 | // | 109 | // |
| 110 | // timeout: returns nil | 110 | // timeout: returns nil |
| 111 | // done: returns return values (0..N) | 111 | // done: returns return values (0..N) |
| @@ -147,18 +147,19 @@ static LUAG_FUNC(lane_join) | |||
| 147 | switch (_lane->status.load(std::memory_order_acquire)) { | 147 | switch (_lane->status.load(std::memory_order_acquire)) { |
| 148 | case Lane::Suspended: // got yielded values | 148 | case Lane::Suspended: // got yielded values |
| 149 | case Lane::Done: // got regular return values | 149 | case Lane::Done: // got regular return values |
| 150 | { | 150 | if (_stored > 0) { |
| 151 | if (_stored == 0) { | ||
| 152 | raise_luaL_error(L_, _lane->L ? "First return value must be non-nil when using join()" : "Can't join() more than once or after indexing"); | ||
| 153 | } | ||
| 154 | lua_getiuservalue(L_, StackIndex{ 1 }, UserValueIndex{ 1 }); // L_: lane {uv} | 151 | lua_getiuservalue(L_, StackIndex{ 1 }, UserValueIndex{ 1 }); // L_: lane {uv} |
| 155 | for (int _i = 2; _i <= _stored; ++_i) { | 152 | for (int _i = 2; _i <= _stored; ++_i) { |
| 156 | lua_rawgeti(L_, 2, _i); // L_: lane {uv} results2...N | 153 | lua_rawgeti(L_, 2, _i); // L_: lane {uv} results2...N |
| 157 | } | 154 | } |
| 158 | lua_rawgeti(L_, 2, 1); // L_: lane {uv} results2...N result1 | 155 | lua_rawgeti(L_, 2, 1); // L_: lane {uv} results2...N result1 |
| 159 | lua_replace(L_, 2); // L_: lane results | 156 | lua_replace(L_, 2); // L_: lane results |
| 160 | _ret = _stored; | ||
| 161 | } | 157 | } |
| 158 | // we precede the lane body returned values with boolean true | ||
| 159 | lua_pushboolean(L_, 1); // L_: lane results true | ||
| 160 | lua_replace(L_, 1); // L_: true results | ||
| 161 | _ret = _stored + 1; | ||
| 162 | STACK_CHECK(L_, _stored); | ||
| 162 | break; | 163 | break; |
| 163 | 164 | ||
| 164 | case Lane::Error: | 165 | case Lane::Error: |
| @@ -174,25 +175,30 @@ static LUAG_FUNC(lane_join) | |||
| 174 | lua_replace(L_, 2); // L_: lane nil <error> <trace> | 175 | lua_replace(L_, 2); // L_: lane nil <error> <trace> |
| 175 | } | 176 | } |
| 176 | _ret = lua_gettop(L_) - 1; // 2 or 3 | 177 | _ret = lua_gettop(L_) - 1; // 2 or 3 |
| 178 | STACK_CHECK(L_, _ret); | ||
| 177 | } | 179 | } |
| 178 | break; | 180 | break; |
| 179 | 181 | ||
| 180 | case Lane::Cancelled: | 182 | case Lane::Cancelled: |
| 181 | LUA_ASSERT(L_, _stored == 2); | 183 | { |
| 182 | lua_getiuservalue(L_, StackIndex{ 1 }, UserValueIndex{ 1 }); // L_: lane {uv} | 184 | LUA_ASSERT(L_, _stored == 2); |
| 183 | lua_rawgeti(L_, 2, 2); // L_: lane {uv} cancel_error | 185 | lua_getiuservalue(L_, StackIndex{ 1 }, UserValueIndex{ 1 }); // L_: lane {uv} |
| 184 | lua_rawgeti(L_, 2, 1); // L_: lane {uv} cancel_error nil | 186 | lua_rawgeti(L_, 2, 2); // L_: lane {uv} cancel_error |
| 185 | lua_replace(L_, -3); // L_: lane nil cancel_error | 187 | lua_rawgeti(L_, 2, 1); // L_: lane {uv} cancel_error nil |
| 186 | LUA_ASSERT(L_, lua_isnil(L_, -2) && kCancelError.equals(L_, kIdxTop)); | 188 | lua_replace(L_, -3); // L_: lane nil cancel_error |
| 187 | _ret = 2; | 189 | LUA_ASSERT(L_, lua_isnil(L_, -2) && kCancelError.equals(L_, kIdxTop)); |
| 190 | _ret = 2; | ||
| 191 | STACK_CHECK(L_, _ret); | ||
| 192 | } | ||
| 188 | break; | 193 | break; |
| 189 | 194 | ||
| 190 | default: | 195 | default: |
| 191 | DEBUGSPEW_CODE(DebugSpew(nullptr) << "Unknown Lane status: " << static_cast<int>(_lane->status.load(std::memory_order_relaxed)) << std::endl); | 196 | DEBUGSPEW_CODE(DebugSpew(nullptr) << "Unknown Lane status: " << static_cast<int>(_lane->status.load(std::memory_order_relaxed)) << std::endl); |
| 192 | LUA_ASSERT(L_, false); | 197 | LUA_ASSERT(L_, false); |
| 193 | _ret = 0; | 198 | _ret = 0; |
| 199 | STACK_CHECK(L_, _ret); | ||
| 194 | } | 200 | } |
| 195 | STACK_CHECK(L_, _ret); | 201 | LUA_ASSERT(L_, lua_gettop(L_) >= _ret); |
| 196 | return _ret; | 202 | return _ret; |
| 197 | } | 203 | } |
| 198 | 204 | ||
diff --git a/tests/appendud.lua b/tests/appendud.lua index f6f99c1..2a8c8ce 100644 --- a/tests/appendud.lua +++ b/tests/appendud.lua | |||
| @@ -49,7 +49,7 @@ assert(not err) | |||
| 49 | -- test | 49 | -- test |
| 50 | -- print("t:join()") | 50 | -- print("t:join()") |
| 51 | a,b,c = t[1],t[2],t[3] -- Need to explicitly wait for the thread, since 'ipairs()' does not | 51 | a,b,c = t[1],t[2],t[3] -- Need to explicitly wait for the thread, since 'ipairs()' does not |
| 52 | --a,b,c = t:join() -- Need to explicitly wait for the thread, since 'ipairs()' does not | 52 | --r,a,b,c = t:join() -- Need to explicitly wait for the thread, since 'ipairs()' does not |
| 53 | -- value the '__index' metamethod (wouldn't it be cool if it did..?) | 53 | -- value the '__index' metamethod (wouldn't it be cool if it did..?) |
| 54 | 54 | ||
| 55 | print(a,b,c) | 55 | print(a,b,c) |
diff --git a/tests/basic.lua b/tests/basic.lua index 9aaad97..f393175 100644 --- a/tests/basic.lua +++ b/tests/basic.lua | |||
| @@ -507,19 +507,20 @@ local S = lanes.gen("table", { name = 'auto', gc_cb = gc_cb }, | |||
| 507 | return (unpack or table.unpack)(aux) | 507 | return (unpack or table.unpack)(aux) |
| 508 | end) | 508 | end) |
| 509 | 509 | ||
| 510 | h= S { 12, 13, 14 } -- execution starts, h[1..3] will get the return values | 510 | h = S { 12, 13, 14 } -- execution starts, h[1..3] will get the return values |
| 511 | -- wait a bit so that the lane has a chance to set its debug name | 511 | -- wait a bit so that the lane has a chance to set its debug name |
| 512 | SLEEP(0.5) | 512 | SLEEP(0.5) |
| 513 | print("joining with '" .. h:get_threadname() .. "'") | 513 | print("joining with '" .. h:get_threadname() .. "'") |
| 514 | local a,b,c,d= h:join() | 514 | local r,a,b,c,d= h:join() |
| 515 | if h.status == "error" then | 515 | if h.status == "error" then |
| 516 | print(h:get_threadname(), "error: " , a, b, c, d) | 516 | print(h:get_threadname(), "error: " , r, a, b, c, d) |
| 517 | else | 517 | else |
| 518 | print(h:get_threadname(), a,b,c,d) | 518 | print(h:get_threadname(), r,a,b,c,d) |
| 519 | assert(a==14) | 519 | assert(r == true) |
| 520 | assert(b==13) | 520 | assert(a == 14) |
| 521 | assert(c==12) | 521 | assert(b == 13) |
| 522 | assert(d==nil) | 522 | assert(c == 12) |
| 523 | assert(d == nil) | ||
| 523 | end | 524 | end |
| 524 | 525 | ||
| 525 | local nameof_type, nameof_name = lanes.nameof(print) | 526 | local nameof_type, nameof_name = lanes.nameof(print) |
diff --git a/tests/error.lua b/tests/error.lua index 28cfff1..76ceea4 100644 --- a/tests/error.lua +++ b/tests/error.lua | |||
| @@ -173,8 +173,7 @@ local do_error_catching_test = function(error_reporting_mode_, error_value_, fin | |||
| 173 | local h = start_lane(error_reporting_mode_, error_value_, finalizer_, finalizer_error_value_) | 173 | local h = start_lane(error_reporting_mode_, error_value_, finalizer_, finalizer_error_value_) |
| 174 | local ret,err,stack= h:join() -- wait for the lane (no automatic error propagation) | 174 | local ret,err,stack= h:join() -- wait for the lane (no automatic error propagation) |
| 175 | WR("Processing results for {", error_reporting_mode_, error_value_, finalizer_, finalizer_error_value_, "}") | 175 | WR("Processing results for {", error_reporting_mode_, error_value_, finalizer_, finalizer_error_value_, "}") |
| 176 | if err then | 176 | if ret == nil then |
| 177 | assert(ret == nil) | ||
| 178 | assert(error_reporting_mode_ == "minimal" or type(stack)=="table") -- only true if lane was configured with error_trace_level ~= "minimal" | 177 | assert(error_reporting_mode_ == "minimal" or type(stack)=="table") -- only true if lane was configured with error_trace_level ~= "minimal" |
| 179 | if err == error_value_ then | 178 | if err == error_value_ then |
| 180 | WR("Lane regular error: ", err) | 179 | WR("Lane regular error: ", err) |
| @@ -198,8 +197,8 @@ local do_error_catching_test = function(error_reporting_mode_, error_value_, fin | |||
| 198 | end | 197 | end |
| 199 | end | 198 | end |
| 200 | else -- no error | 199 | else -- no error |
| 201 | assert(ret == "success") | 200 | assert(ret == true and err == "success") |
| 202 | WR("No error in lane: ", ret) | 201 | WR("No error in lane: ", err, ret) |
| 203 | end | 202 | end |
| 204 | WR "TEST OK" | 203 | WR "TEST OK" |
| 205 | end | 204 | end |
diff --git a/tests/finalizer.lua b/tests/finalizer.lua index ac5ce8b..9fa12dc 100644 --- a/tests/finalizer.lua +++ b/tests/finalizer.lua | |||
| @@ -77,8 +77,8 @@ local do_test = function(error_) | |||
| 77 | 77 | ||
| 78 | local h = lgen(error_) | 78 | local h = lgen(error_) |
| 79 | 79 | ||
| 80 | local _,err,stack = h:join() -- wait for the lane (no automatic error propagation) | 80 | local r,err,stack = h:join() -- wait for the lane (no automatic error propagation) |
| 81 | if err then | 81 | if not r then |
| 82 | assert(stack, "no stack trace on error, check 'error_trace_level'") | 82 | assert(stack, "no stack trace on error, check 'error_trace_level'") |
| 83 | io.stderr:write( "Lane error: "..tostring(err).."\n" ) | 83 | io.stderr:write( "Lane error: "..tostring(err).."\n" ) |
| 84 | io.stderr:write( "\t", table.concat(stack,"\t\n"), "\n" ) | 84 | io.stderr:write( "\t", table.concat(stack,"\t\n"), "\n" ) |
diff --git a/tests/func_is_string.lua b/tests/func_is_string.lua index 5de4c60..3c91603 100644 --- a/tests/func_is_string.lua +++ b/tests/func_is_string.lua | |||
| @@ -21,16 +21,17 @@ end | |||
| 21 | 21 | ||
| 22 | local options = {globals = { b = 666 }} | 22 | local options = {globals = { b = 666 }} |
| 23 | 23 | ||
| 24 | local gen1 = lanes.gen("*", { name = 'auto' }, "return true, dofile('fibonacci.lua')") | 24 | local gen1 = lanes.gen("*", { name = 'auto' }, "return true, error('bob')") |
| 25 | local gen2 = lanes.gen(options, { name = 'auto' }, "return b") | ||
| 26 | 25 | ||
| 27 | fibLane = gen1() | 26 | fibLane = gen1() |
| 28 | lanes.sleep(0.1) | 27 | lanes.sleep(0.1) |
| 29 | print(fibLane, fibLane.status) | 28 | print(fibLane, fibLane.status) |
| 30 | local _status, _err = fibLane:join() | 29 | local _r, _err, _stk = fibLane:join() |
| 31 | print(_status, _err) | 30 | assert(_r == nil, "got " .. tostring(_r) .. " " .. tostring(_err) .. " " .. tostring(_stk)) |
| 32 | 31 | ||
| 33 | retLane1, retLane2 = gen2(), gen2() | 32 | local gen2 = lanes.gen(options, { name = 'auto' }, "return b") |
| 33 | local retLane1, retLane2 = gen2(), gen2() | ||
| 34 | 34 | ||
| 35 | print( retLane1[1], retLane2[1]) | 35 | print( retLane1[1], retLane2[1]) |
| 36 | print "TEST OK" \ No newline at end of file | 36 | assert(retLane1[1] == 666 and retLane2[1] == 666) |
| 37 | print "TEST OK" | ||
diff --git a/tests/launchtest.lua b/tests/launchtest.lua index 57411e1..cdd6ffc 100644 --- a/tests/launchtest.lua +++ b/tests/launchtest.lua | |||
| @@ -69,8 +69,8 @@ else | |||
| 69 | io.stderr:write( N.." lanes launched.\n" ) | 69 | io.stderr:write( N.." lanes launched.\n" ) |
| 70 | 70 | ||
| 71 | for i=1,N do | 71 | for i=1,N do |
| 72 | local rc= t[i]:join() | 72 | local r,rc = t[i]:join() |
| 73 | assert( rc==i ) | 73 | assert( r == true and rc == i ) |
| 74 | end | 74 | end |
| 75 | 75 | ||
| 76 | io.stderr:write( N.." lanes finished.\n" ) | 76 | io.stderr:write( N.." lanes finished.\n" ) |
diff --git a/tests/linda_perf.lua b/tests/linda_perf.lua index 83b8921..e68d552 100644 --- a/tests/linda_perf.lua +++ b/tests/linda_perf.lua | |||
| @@ -56,7 +56,7 @@ local eater = function( l, loop) | |||
| 56 | -- print "loop is over" | 56 | -- print "loop is over" |
| 57 | key, val = l:receive( "done") | 57 | key, val = l:receive( "done") |
| 58 | print("eater: done ("..val..")") | 58 | print("eater: done ("..val..")") |
| 59 | return true | 59 | return "ate everything" |
| 60 | end | 60 | end |
| 61 | 61 | ||
| 62 | -- ################################################################################################# | 62 | -- ################################################################################################# |
| @@ -74,7 +74,7 @@ local gobbler = function( l, loop, batch) | |||
| 74 | print "loop is over" | 74 | print "loop is over" |
| 75 | key, val = l:receive( "done") | 75 | key, val = l:receive( "done") |
| 76 | print("gobbler: done ("..val..")") | 76 | print("gobbler: done ("..val..")") |
| 77 | return true | 77 | return "gobbled everything" |
| 78 | end | 78 | end |
| 79 | 79 | ||
| 80 | -- ################################################################################################# | 80 | -- ################################################################################################# |
| @@ -123,7 +123,8 @@ local function ziva1( preloop, loop, batch) | |||
| 123 | end | 123 | end |
| 124 | end | 124 | end |
| 125 | l:send( "done" ,"are you happy?") | 125 | l:send( "done" ,"are you happy?") |
| 126 | lane:join() | 126 | local r, ret = lane:join() |
| 127 | assert(r == true and type(ret) == "string", "got " .. tostring(r) .. " " .. tostring(ret)) | ||
| 127 | return lanes.now_secs() - t1 | 128 | return lanes.now_secs() - t1 |
| 128 | end | 129 | end |
| 129 | 130 | ||
diff --git a/tests/perftest.lua b/tests/perftest.lua index fe43cca..35e164d 100644 --- a/tests/perftest.lua +++ b/tests/perftest.lua | |||
| @@ -175,9 +175,9 @@ else | |||
| 175 | -- Make sure all lanes finished | 175 | -- Make sure all lanes finished |
| 176 | -- | 176 | -- |
| 177 | for i=1,N do | 177 | for i=1,N do |
| 178 | local tmp= t[i]:join() | 178 | local r, tmp = t[i]:join() |
| 179 | -- this assert will trigger if you change M to values below 1000 in order to solve C stack overflow | 179 | -- this assert will trigger if you change M to values below 1000 in order to solve C stack overflow |
| 180 | assert( type(tmp)=="table" and tmp[1]==2 and tmp[168]==997 ) | 180 | assert( r == true and type(tmp) == "table" and tmp[1] == 2 and tmp[168] == 997 ) |
| 181 | end | 181 | end |
| 182 | end | 182 | end |
| 183 | 183 | ||
diff --git a/tests/pingpong.lua b/tests/pingpong.lua index 06c0903..1ed5b9a 100644 --- a/tests/pingpong.lua +++ b/tests/pingpong.lua | |||
| @@ -21,13 +21,15 @@ local pingpong = function(name, qr, qs, start) | |||
| 21 | q:send(qs, val) | 21 | q:send(qs, val) |
| 22 | count = count + 1 | 22 | count = count + 1 |
| 23 | end | 23 | end |
| 24 | return true | 24 | return "ping!" |
| 25 | end | 25 | end |
| 26 | 26 | ||
| 27 | -- pingpong("L1", '0', '1', true) | 27 | -- pingpong("L1", '0', '1', true) |
| 28 | local t1, err1 = lanes.gen("*", { name = 'auto' }, pingpong)("L1", 'a', 'b', true) | 28 | local t1, err1 = lanes.gen("*", { name = 'auto' }, pingpong)("L1", 'a', 'b', true) |
| 29 | local t2, err2 = lanes.gen("*", { name = 'auto' }, pingpong)("L2", 'b', 'a', false) | 29 | local t2, err2 = lanes.gen("*", { name = 'auto' }, pingpong)("L2", 'b', 'a', false) |
| 30 | 30 | ||
| 31 | t1:join() | 31 | local r1, ret1 = t1:join() |
| 32 | t2:join() | 32 | assert(r1 == true and ret1 == "ping!") |
| 33 | local r2, ret2 = t2:join() | ||
| 34 | assert(r2 == true and ret2 == "ping!") | ||
| 33 | print "TEST OK" | 35 | print "TEST OK" |
diff --git a/tests/rupval.lua b/tests/rupval.lua index ad5ad9d..c6743b3 100644 --- a/tests/rupval.lua +++ b/tests/rupval.lua | |||
| @@ -26,17 +26,17 @@ end | |||
| 26 | local g = lanes.gen( "base", { name = 'auto' }, a) | 26 | local g = lanes.gen( "base", { name = 'auto' }, a) |
| 27 | 27 | ||
| 28 | local l = g(7) | 28 | local l = g(7) |
| 29 | local r = l:join() | 29 | local _, r = l:join() |
| 30 | assert(r == y) | 30 | assert(r == y) |
| 31 | print(r) | 31 | print(r) |
| 32 | 32 | ||
| 33 | local l = g(8) | 33 | local l = g(8) |
| 34 | local r = l:join() | 34 | local _, r = l:join() |
| 35 | assert(r == z) | 35 | assert(r == z) |
| 36 | print(r) | 36 | print(r) |
| 37 | 37 | ||
| 38 | local l = g(9) | 38 | local l = g(9) |
| 39 | local r = l:join() | 39 | local _, r = l:join() |
| 40 | assert(r == x) | 40 | assert(r == x) |
| 41 | print(r) | 41 | print(r) |
| 42 | 42 | ||
diff --git a/tests/tobeclosed.lua b/tests/tobeclosed.lua index 447b936..fd157e2 100644 --- a/tests/tobeclosed.lua +++ b/tests/tobeclosed.lua | |||
| @@ -106,7 +106,7 @@ do | |||
| 106 | local _count, l_out <close> = l:get("trip") | 106 | local _count, l_out <close> = l:get("trip") |
| 107 | -- linda from arguments | 107 | -- linda from arguments |
| 108 | local l_arg <close> = l_arg_ | 108 | local l_arg <close> = l_arg_ |
| 109 | return true | 109 | return "done" |
| 110 | end | 110 | end |
| 111 | 111 | ||
| 112 | local close_handler_f = function(linda_, err_) | 112 | local close_handler_f = function(linda_, err_) |
| @@ -118,7 +118,8 @@ do | |||
| 118 | l:set("trip", l_in) | 118 | l:set("trip", l_in) |
| 119 | 119 | ||
| 120 | do | 120 | do |
| 121 | lanes.gen("*", { name = 'auto' }, lane_body)(l_in):join() | 121 | local r, ret = lanes.gen("*", { name = 'auto' }, lane_body)(l_in):join() |
| 122 | assert(r == true and ret == "done") | ||
| 122 | end | 123 | end |
| 123 | local _count, _closed = l_in:get("closed") | 124 | local _count, _closed = l_in:get("closed") |
| 124 | assert(_count == 1 and _closed == 2) | 125 | assert(_count == 1 and _closed == 2) |
diff --git a/unit_tests/scripts/coro/basics.lua b/unit_tests/scripts/coro/basics.lua index cd2f410..c0b7a36 100644 --- a/unit_tests/scripts/coro/basics.lua +++ b/unit_tests/scripts/coro/basics.lua | |||
| @@ -85,7 +85,8 @@ if true then | |||
| 85 | assert(h3:resume(1) == nil) | 85 | assert(h3:resume(1) == nil) |
| 86 | 86 | ||
| 87 | -- similarly, we can get them with join() | 87 | -- similarly, we can get them with join() |
| 88 | assert(h3:join() == "world" and h3.status == "suspended") | 88 | local r3, ret3 = h3:join() |
| 89 | assert(r3 == true and ret3 == "world" and h3.status == "suspended") | ||
| 89 | -- since we consumed the returned values, they should not be here when we resume | 90 | -- since we consumed the returned values, they should not be here when we resume |
| 90 | assert(h3:resume(2) == nil) | 91 | assert(h3:resume(2) == nil) |
| 91 | 92 | ||
| @@ -93,5 +94,6 @@ if true then | |||
| 93 | assert(h3:resume(3) == "!") | 94 | assert(h3:resume(3) == "!") |
| 94 | 95 | ||
| 95 | -- the final return value of the lane body remains to be read | 96 | -- the final return value of the lane body remains to be read |
| 96 | assert(h3:join() == "done!" and h3.status == "done") | 97 | local r3, ret3 = h3:join() |
| 98 | assert(r3 == true and ret3 == "done!" and h3.status == "done") | ||
| 97 | end | 99 | end |
diff --git a/unit_tests/scripts/lane/tasking_join_test.lua b/unit_tests/scripts/lane/tasking_join_test.lua index 2fbce6c..495a709 100644 --- a/unit_tests/scripts/lane/tasking_join_test.lua +++ b/unit_tests/scripts/lane/tasking_join_test.lua | |||
| @@ -30,14 +30,19 @@ end | |||
| 30 | 30 | ||
| 31 | PRINT("---=== :join test ===---", "\n\n") | 31 | PRINT("---=== :join test ===---", "\n\n") |
| 32 | 32 | ||
| 33 | -- a lane body that returns nothing is successfully joined with true, nil | ||
| 34 | local r, ret = lanes_gen(function() end)():join() | ||
| 35 | assert(r == true and ret == nil) | ||
| 36 | |||
| 33 | -- NOTE: 'unpack()' cannot be used on the lane handle; it will always return nil | 37 | -- NOTE: 'unpack()' cannot be used on the lane handle; it will always return nil |
| 34 | -- (unless [1..n] has been read earlier, in which case it would seemingly | 38 | -- (unless [1..n] has been read earlier, in which case it would seemingly |
| 35 | -- work). | 39 | -- work). |
| 36 | 40 | ||
| 37 | local S= lanes_gen("table", { name = 'auto', gc_cb = gc_cb }, | 41 | local S = lanes_gen("table", { name = 'auto', gc_cb = gc_cb }, |
| 38 | function(arg) | 42 | function(arg) |
| 39 | lane_threadname "join test lane" | 43 | lane_threadname "join test lane" |
| 40 | set_finalizer(function() end) | 44 | set_finalizer(function() end) |
| 45 | -- take arg table, reverse its contents in aux, then return the unpacked result | ||
| 41 | local aux= {} | 46 | local aux= {} |
| 42 | for i, v in ipairs(arg) do | 47 | for i, v in ipairs(arg) do |
| 43 | table.insert(aux, 1, v) | 48 | table.insert(aux, 1, v) |
| @@ -46,15 +51,16 @@ local S= lanes_gen("table", { name = 'auto', gc_cb = gc_cb }, | |||
| 46 | return (unpack or table.unpack)(aux) | 51 | return (unpack or table.unpack)(aux) |
| 47 | end) | 52 | end) |
| 48 | 53 | ||
| 49 | h= S { 12, 13, 14 } -- execution starts, h[1..3] will get the return values | 54 | local h = S { 12, 13, 14 } -- execution starts, h[1..3] will get the return values |
| 50 | -- wait a bit so that the lane has a chance to set its debug name | 55 | -- wait a bit so that the lane has a chance to set its debug name |
| 51 | SLEEP(0.5) | 56 | SLEEP(0.5) |
| 52 | print("joining with '" .. h:get_threadname() .. "'") | 57 | print("joining with '" .. h:get_threadname() .. "'") |
| 53 | local a,b,c,d= h:join() | 58 | local r, a, b, c, d = h:join() |
| 54 | if h.status == "error" then | 59 | if h.status == "error" then |
| 55 | print(h:get_threadname(), "error: " , a, b, c, d) | 60 | print(h:get_threadname(), "error: " , r, a, b, c, d) |
| 56 | else | 61 | else |
| 57 | print(h:get_threadname(), a,b,c,d) | 62 | print(h:get_threadname(), r, a, b, c, d) |
| 63 | assert(r==true, "r == " .. tostring(r)) | ||
| 58 | assert(a==14, "a == " .. tostring(a)) | 64 | assert(a==14, "a == " .. tostring(a)) |
| 59 | assert(b==13, "b == " .. tostring(b)) | 65 | assert(b==13, "b == " .. tostring(b)) |
| 60 | assert(c==12, "c == " .. tostring(c)) | 66 | assert(c==12, "c == " .. tostring(c)) |
diff --git a/unit_tests/scripts/linda/wake_period.lua b/unit_tests/scripts/linda/wake_period.lua index e4a900d..d2dccc3 100644 --- a/unit_tests/scripts/linda/wake_period.lua +++ b/unit_tests/scripts/linda/wake_period.lua | |||
| @@ -6,7 +6,7 @@ local lanes = require_lanes_result_1 | |||
| 6 | local body = function(linda_) | 6 | local body = function(linda_) |
| 7 | -- a blocking read that lasts longer than the tested wake_period values | 7 | -- a blocking read that lasts longer than the tested wake_period values |
| 8 | linda_:receive(2, "empty_slot") | 8 | linda_:receive(2, "empty_slot") |
| 9 | return true | 9 | return "done" |
| 10 | end | 10 | end |
| 11 | 11 | ||
| 12 | -- if we don't cancel the lane, we should wait the whole duration | 12 | -- if we don't cancel the lane, we should wait the whole duration |
| @@ -22,7 +22,8 @@ local function check_wake_duration(linda_, expected_, do_cancel_) | |||
| 22 | assert(result == false and reason == 'timeout', "unexpected cancel result") | 22 | assert(result == false and reason == 'timeout', "unexpected cancel result") |
| 23 | end | 23 | end |
| 24 | -- this should wait until the linda wakes by itself before the actual receive timeout and sees the cancel request | 24 | -- this should wait until the linda wakes by itself before the actual receive timeout and sees the cancel request |
| 25 | h:join() | 25 | local r, ret = h:join() |
| 26 | assert(r == true and ret == "done") | ||
| 26 | local t1 = lanes.now_secs() | 27 | local t1 = lanes.now_secs() |
| 27 | local delta = t1 - t0 | 28 | local delta = t1 - t0 |
| 28 | -- the linda should check for cancellation at about the expected period, not earlier | 29 | -- the linda should check for cancellation at about the expected period, not earlier |
