diff options
author | Benoit Germain <benoit.germain@ubisoft.com> | 2024-12-03 17:13:35 +0100 |
---|---|---|
committer | Benoit Germain <benoit.germain@ubisoft.com> | 2024-12-03 17:13:35 +0100 |
commit | d8580e14fec64dd5bf3dd492a4811b290cbe4aec (patch) | |
tree | 8dcd3117f7427671e34509badd4c08957d8f0914 | |
parent | 307fd830eb168005a3ba3d557343284814757eff (diff) | |
download | lanes-d8580e14fec64dd5bf3dd492a4811b290cbe4aec.tar.gz lanes-d8580e14fec64dd5bf3dd492a4811b290cbe4aec.tar.bz2 lanes-d8580e14fec64dd5bf3dd492a4811b290cbe4aec.zip |
Internal rework of an enum bad practice usage
-rw-r--r-- | src/cancel.cpp | 50 | ||||
-rw-r--r-- | src/cancel.hpp | 27 | ||||
-rw-r--r-- | src/compat.hpp | 10 | ||||
-rw-r--r-- | src/lane.cpp | 6 | ||||
-rw-r--r-- | src/universe.cpp | 6 | ||||
-rw-r--r-- | src/universe.hpp | 2 | ||||
-rw-r--r-- | tests/cancel.lua | 112 |
7 files changed, 106 insertions, 107 deletions
diff --git a/src/cancel.cpp b/src/cancel.cpp index 31656c4..73ee6f3 100644 --- a/src/cancel.cpp +++ b/src/cancel.cpp | |||
@@ -81,25 +81,24 @@ CancelRequest CheckCancelRequest(lua_State* const L_) | |||
81 | // ################################################################################################# | 81 | // ################################################################################################# |
82 | // ################################################################################################# | 82 | // ################################################################################################# |
83 | 83 | ||
84 | CancelOp WhichCancelOp(std::string_view const& opString_) | 84 | static std::optional<CancelOp> WhichCancelOp(std::string_view const& opString_) |
85 | { | 85 | { |
86 | auto _op{ CancelOp::Invalid }; | 86 | if (opString_ == "soft") { |
87 | if (opString_ == "hard") { | 87 | return std::make_optional<CancelOp>(CancelRequest::Soft, LuaHookMask::None); |
88 | _op = CancelOp::Hard; | 88 | } else if (opString_ == "hard") { |
89 | } else if (opString_ == "soft") { | 89 | return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::None); |
90 | _op = CancelOp::Soft; | ||
91 | } else if (opString_== "call") { | 90 | } else if (opString_== "call") { |
92 | _op = CancelOp::MaskCall; | 91 | return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::Call); |
93 | } else if (opString_ == "ret") { | 92 | } else if (opString_ == "ret") { |
94 | _op = CancelOp::MaskRet; | 93 | return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::Ret); |
95 | } else if (opString_ == "line") { | 94 | } else if (opString_ == "line") { |
96 | _op = CancelOp::MaskLine; | 95 | return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::Line); |
97 | } else if (opString_ == "count") { | 96 | } else if (opString_ == "count") { |
98 | _op = CancelOp::MaskCount; | 97 | return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::Count); |
99 | } else if (opString_ == "all") { | 98 | } else if (opString_ == "all") { |
100 | _op = CancelOp::MaskAll; | 99 | return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::All); |
101 | } | 100 | } |
102 | return _op; | 101 | return std::nullopt; |
103 | } | 102 | } |
104 | 103 | ||
105 | // ################################################################################################# | 104 | // ################################################################################################# |
@@ -109,14 +108,14 @@ static CancelOp WhichCancelOp(lua_State* const L_, StackIndex const idx_) | |||
109 | { | 108 | { |
110 | if (luaG_type(L_, idx_) == LuaType::STRING) { | 109 | if (luaG_type(L_, idx_) == LuaType::STRING) { |
111 | std::string_view const _str{ luaG_tostring(L_, idx_) }; | 110 | std::string_view const _str{ luaG_tostring(L_, idx_) }; |
112 | CancelOp _op{ WhichCancelOp(_str) }; | 111 | auto const _op{ WhichCancelOp(_str) }; |
113 | lua_remove(L_, idx_); // argument is processed, remove it | 112 | lua_remove(L_, idx_); // argument is processed, remove it |
114 | if (_op == CancelOp::Invalid) { | 113 | if (!_op.has_value()) { |
115 | raise_luaL_error(L_, "invalid hook option %s", _str.data()); | 114 | raise_luaL_error(L_, "Invalid cancel option %s", _str.data()); |
116 | } | 115 | } |
117 | return _op; | 116 | return _op.value(); |
118 | } | 117 | } |
119 | return CancelOp::Hard; | 118 | return CancelOp{ CancelRequest::Hard, LuaHookMask::None }; |
120 | } | 119 | } |
121 | 120 | ||
122 | // ################################################################################################# | 121 | // ################################################################################################# |
@@ -133,7 +132,7 @@ static CancelOp WhichCancelOp(lua_State* const L_, StackIndex const idx_) | |||
133 | // | 132 | // |
134 | LUAG_FUNC(cancel_test) | 133 | LUAG_FUNC(cancel_test) |
135 | { | 134 | { |
136 | CancelRequest _test{ CheckCancelRequest(L_) }; | 135 | CancelRequest const _test{ CheckCancelRequest(L_) }; |
137 | lua_pushboolean(L_, _test != CancelRequest::None); | 136 | lua_pushboolean(L_, _test != CancelRequest::None); |
138 | return 1; | 137 | return 1; |
139 | } | 138 | } |
@@ -146,14 +145,17 @@ LUAG_FUNC(lane_cancel) | |||
146 | Lane* const _lane{ ToLane(L_, StackIndex{ 1 }) }; | 145 | Lane* const _lane{ ToLane(L_, StackIndex{ 1 }) }; |
147 | CancelOp const _op{ WhichCancelOp(L_, StackIndex{ 2 }) }; // this removes the cancel_op string from the stack | 146 | CancelOp const _op{ WhichCancelOp(L_, StackIndex{ 2 }) }; // this removes the cancel_op string from the stack |
148 | 147 | ||
149 | int _hook_count{ 0 }; | 148 | int const _hook_count = std::invoke([_op, L_]() { |
150 | if (_op > CancelOp::Soft) { // hook is requested | 149 | if (_op.hookMask == LuaHookMask::None) { |
151 | _hook_count = static_cast<int>(luaL_checkinteger(L_, 2)); | 150 | return 0; |
151 | } | ||
152 | auto const _hook_count{ static_cast<int>(luaL_checkinteger(L_, 2)) }; | ||
152 | lua_remove(L_, 2); // argument is processed, remove it | 153 | lua_remove(L_, 2); // argument is processed, remove it |
153 | if (_hook_count < 1) { | 154 | if (_hook_count < 1) { |
154 | raise_luaL_error(L_, "hook count cannot be < 1"); | 155 | raise_luaL_error(L_, "Hook count cannot be < 1"); |
155 | } | 156 | } |
156 | } | 157 | return _hook_count; |
158 | }); | ||
157 | 159 | ||
158 | std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; | 160 | std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; |
159 | if (luaG_type(L_, StackIndex{ 2 }) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion | 161 | if (luaG_type(L_, StackIndex{ 2 }) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion |
@@ -169,7 +171,7 @@ LUAG_FUNC(lane_cancel) | |||
169 | } | 171 | } |
170 | 172 | ||
171 | // we wake by default in "hard" mode (remember that hook is hard too), but this can be turned off if desired | 173 | // we wake by default in "hard" mode (remember that hook is hard too), but this can be turned off if desired |
172 | WakeLane _wake_lane{ _op != CancelOp::Soft ? WakeLane::Yes : WakeLane::No }; | 174 | WakeLane _wake_lane{ (_op.mode == CancelRequest::Hard) ? WakeLane::Yes : WakeLane::No }; |
173 | if (lua_gettop(L_) >= 2) { | 175 | if (lua_gettop(L_) >= 2) { |
174 | if (!lua_isboolean(L_, 2)) { | 176 | if (!lua_isboolean(L_, 2)) { |
175 | raise_luaL_error(L_, "wake_lane argument is not a boolean"); | 177 | raise_luaL_error(L_, "wake_lane argument is not a boolean"); |
diff --git a/src/cancel.hpp b/src/cancel.hpp index 8f4cf07..65ccf8d 100644 --- a/src/cancel.hpp +++ b/src/cancel.hpp | |||
@@ -6,36 +6,25 @@ | |||
6 | // ################################################################################################# | 6 | // ################################################################################################# |
7 | 7 | ||
8 | // Lane cancellation request modes | 8 | // Lane cancellation request modes |
9 | enum class CancelRequest | 9 | enum class CancelRequest : uint8_t |
10 | { | 10 | { |
11 | None, // no pending cancel request | 11 | None, // no pending cancel request |
12 | Soft, // user wants the lane to cancel itself manually on cancel_test() | 12 | Soft, // user wants the lane to cancel itself manually on cancel_test() |
13 | Hard // user wants the lane to be interrupted (meaning code won't return from those functions) from inside linda:send/receive calls | 13 | Hard // user wants the lane to be interrupted (meaning code won't return from those functions) from inside linda:send/receive calls |
14 | }; | 14 | }; |
15 | 15 | ||
16 | enum class CancelResult | 16 | struct CancelOp |
17 | { | 17 | { |
18 | Timeout, | 18 | CancelRequest mode; |
19 | Cancelled | 19 | LuaHookMask hookMask; |
20 | }; | 20 | }; |
21 | 21 | ||
22 | enum class CancelOp | 22 | enum class CancelResult : uint8_t |
23 | { | 23 | { |
24 | Invalid = -2, | 24 | Timeout, |
25 | Hard = -1, | 25 | Cancelled |
26 | Soft = 0, | ||
27 | MaskCall = LUA_MASKCALL, | ||
28 | MaskRet = LUA_MASKRET, | ||
29 | MaskLine = LUA_MASKLINE, | ||
30 | MaskCount = LUA_MASKCOUNT, | ||
31 | MaskAll = LUA_MASKCALL | LUA_MASKRET | LUA_MASKLINE | LUA_MASKCOUNT | ||
32 | }; | 26 | }; |
33 | 27 | ||
34 | inline auto operator<=>(CancelOp const a_, CancelOp const b_) | ||
35 | { | ||
36 | return static_cast<std::underlying_type_t<CancelOp>>(a_) <=> static_cast<std::underlying_type_t<CancelOp>>(b_); | ||
37 | } | ||
38 | |||
39 | // xxh64 of string "kCancelError" generated at https://www.pelock.com/products/hash-calculator | 28 | // xxh64 of string "kCancelError" generated at https://www.pelock.com/products/hash-calculator |
40 | static constexpr UniqueKey kCancelError{ 0x0630345FEF912746ull, "lanes.cancel_error" }; // 'raise_cancel_error' sentinel | 29 | static constexpr UniqueKey kCancelError{ 0x0630345FEF912746ull, "lanes.cancel_error" }; // 'raise_cancel_error' sentinel |
41 | 30 | ||
@@ -43,8 +32,6 @@ static constexpr UniqueKey kCancelError{ 0x0630345FEF912746ull, "lanes.cancel_er | |||
43 | 32 | ||
44 | [[nodiscard]] | 33 | [[nodiscard]] |
45 | CancelRequest CheckCancelRequest(lua_State* L_); | 34 | CancelRequest CheckCancelRequest(lua_State* L_); |
46 | [[nodiscard]] | ||
47 | CancelOp WhichCancelOp(std::string_view const& opString_); | ||
48 | 35 | ||
49 | // ################################################################################################# | 36 | // ################################################################################################# |
50 | 37 | ||
diff --git a/src/compat.hpp b/src/compat.hpp index 81f1665..80bc391 100644 --- a/src/compat.hpp +++ b/src/compat.hpp | |||
@@ -49,6 +49,16 @@ enum class LuaType | |||
49 | CDATA = 10 // LuaJIT CDATA | 49 | CDATA = 10 // LuaJIT CDATA |
50 | }; | 50 | }; |
51 | 51 | ||
52 | enum class LuaHookMask | ||
53 | { | ||
54 | None = 0, | ||
55 | Call = LUA_MASKCALL, | ||
56 | Ret = LUA_MASKRET, | ||
57 | Line = LUA_MASKLINE, | ||
58 | Count = LUA_MASKCOUNT, | ||
59 | All = LUA_MASKCALL | LUA_MASKRET | LUA_MASKLINE | LUA_MASKCOUNT | ||
60 | }; | ||
61 | |||
52 | // ################################################################################################# | 62 | // ################################################################################################# |
53 | 63 | ||
54 | // add some Lua 5.3-style API when building for Lua 5.1 | 64 | // add some Lua 5.3-style API when building for Lua 5.1 |
diff --git a/src/lane.cpp b/src/lane.cpp index 923eabd..9ab574e 100644 --- a/src/lane.cpp +++ b/src/lane.cpp | |||
@@ -930,10 +930,10 @@ CancelResult Lane::cancel(CancelOp const op_, std::chrono::time_point<std::chron | |||
930 | 930 | ||
931 | // signal the linda to wake up the thread so that it can react to the cancel query | 931 | // signal the linda to wake up the thread so that it can react to the cancel query |
932 | // let us hope we never land here with a pointer on a linda that has been destroyed... | 932 | // let us hope we never land here with a pointer on a linda that has been destroyed... |
933 | if (op_ == CancelOp::Soft) { | 933 | if (op_.mode == CancelRequest::Soft) { |
934 | return internalCancel(CancelRequest::Soft, until_, wakeLane_); | 934 | return internalCancel(CancelRequest::Soft, until_, wakeLane_); |
935 | } else if (op_ > CancelOp::Soft) { | 935 | } else if (op_.hookMask != LuaHookMask::None) { |
936 | lua_sethook(L, _cancelHook, static_cast<int>(op_), hookCount_); | 936 | lua_sethook(L, _cancelHook, static_cast<int>(op_.hookMask), hookCount_); |
937 | } | 937 | } |
938 | 938 | ||
939 | return internalCancel(CancelRequest::Hard, until_, wakeLane_); | 939 | return internalCancel(CancelRequest::Hard, until_, wakeLane_); |
diff --git a/src/universe.cpp b/src/universe.cpp index eab5977..ec7d043 100644 --- a/src/universe.cpp +++ b/src/universe.cpp | |||
@@ -417,9 +417,9 @@ LUAG_FUNC(universe_gc) | |||
417 | 417 | ||
418 | // attempt to terminate all lanes with increasingly stronger cancel methods | 418 | // attempt to terminate all lanes with increasingly stronger cancel methods |
419 | bool const _allLanesTerminated{ | 419 | bool const _allLanesTerminated{ |
420 | _U->terminateFreeRunningLanes(_shutdown_timeout, CancelOp::Soft) | 420 | _U->terminateFreeRunningLanes(_shutdown_timeout, { CancelRequest::Soft, LuaHookMask::None }) |
421 | || _U->terminateFreeRunningLanes(_shutdown_timeout, CancelOp::Hard) | 421 | || _U->terminateFreeRunningLanes(_shutdown_timeout, { CancelRequest::Hard, LuaHookMask::None }) |
422 | || _U->terminateFreeRunningLanes(_shutdown_timeout, CancelOp::MaskAll) | 422 | || _U->terminateFreeRunningLanes(_shutdown_timeout, { CancelRequest::Hard, LuaHookMask::All }) |
423 | }; | 423 | }; |
424 | 424 | ||
425 | // invoke the function installed by lanes.finally() | 425 | // invoke the function installed by lanes.finally() |
diff --git a/src/universe.hpp b/src/universe.hpp index fa1e238..639dcdb 100644 --- a/src/universe.hpp +++ b/src/universe.hpp | |||
@@ -1,6 +1,7 @@ | |||
1 | #pragma once | 1 | #pragma once |
2 | 2 | ||
3 | #include "allocator.hpp" | 3 | #include "allocator.hpp" |
4 | #include "cancel.hpp" | ||
4 | #include "keeper.hpp" | 5 | #include "keeper.hpp" |
5 | #include "lanesconf.h" | 6 | #include "lanesconf.h" |
6 | #include "tracker.hpp" | 7 | #include "tracker.hpp" |
@@ -9,7 +10,6 @@ | |||
9 | // ################################################################################################# | 10 | // ################################################################################################# |
10 | 11 | ||
11 | // forwards | 12 | // forwards |
12 | enum class CancelOp; | ||
13 | struct DeepPrelude; | 13 | struct DeepPrelude; |
14 | class Lane; | 14 | class Lane; |
15 | 15 | ||
diff --git a/tests/cancel.lua b/tests/cancel.lua index e65d794..9b65ad3 100644 --- a/tests/cancel.lua +++ b/tests/cancel.lua | |||
@@ -24,7 +24,7 @@ end | |||
24 | 24 | ||
25 | local linda = lanes.linda() | 25 | local linda = lanes.linda() |
26 | -- a numeric value to read | 26 | -- a numeric value to read |
27 | linda:set( "val", 33.0) | 27 | linda:set("val", 33.0) |
28 | 28 | ||
29 | -- so that we can easily swap between lanes.gen and lanes.coro, to try stuff | 29 | -- so that we can easily swap between lanes.gen and lanes.coro, to try stuff |
30 | local generator = lanes.coro | 30 | local generator = lanes.coro |
@@ -36,27 +36,27 @@ if not next(which_tests) or which_tests.genlock then | |||
36 | print "\n\n####################################################################\nbegin genlock & genatomic cancel test\n" | 36 | print "\n\n####################################################################\nbegin genlock & genatomic cancel test\n" |
37 | 37 | ||
38 | -- get a lock and a atomic operator | 38 | -- get a lock and a atomic operator |
39 | local lock = lanes.genlock( linda, "lock", 1) | 39 | local lock = lanes.genlock(linda, "lock", 1) |
40 | local atomic = lanes.genatomic( linda, "atomic") | 40 | local atomic = lanes.genatomic(linda, "atomic") |
41 | 41 | ||
42 | local check_returned_cancel_error = function(_status, _err) | 42 | local check_returned_cancel_error = function(_status, _err) |
43 | assert(_status == nil and _err == lanes.cancel_error) | 43 | assert(_status == nil and _err == lanes.cancel_error) |
44 | end | 44 | end |
45 | -- check that cancelled lindas give cancel_error as they should | 45 | -- check that cancelled lindas give cancel_error as they should |
46 | linda:cancel() | 46 | linda:cancel() |
47 | check_returned_cancel_error(linda:set( "empty", 42)) | 47 | check_returned_cancel_error(linda:set("empty", 42)) |
48 | check_returned_cancel_error(linda:get( "empty")) | 48 | check_returned_cancel_error(linda:get("empty")) |
49 | check_returned_cancel_error(linda:send( "empty", 42)) | 49 | check_returned_cancel_error(linda:send("empty", 42)) |
50 | check_returned_cancel_error(linda:receive( "empty")) | 50 | check_returned_cancel_error(linda:receive("empty")) |
51 | check_returned_cancel_error(linda:limit( "empty", 5)) | 51 | check_returned_cancel_error(linda:limit("empty", 5)) |
52 | check_returned_cancel_error(linda:restrict( "empty", "set/get")) | 52 | check_returned_cancel_error(linda:restrict("empty", "set/get")) |
53 | assert( lanes.genlock( linda, "any", 1) == lanes.cancel_error) | 53 | assert(lanes.genlock(linda, "any", 1) == lanes.cancel_error) |
54 | assert( lanes.genatomic( linda, "any") == lanes.cancel_error) | 54 | assert(lanes.genatomic(linda, "any") == lanes.cancel_error) |
55 | 55 | ||
56 | -- check that lock and atomic functions return cancel_error if the linda was cancelled | 56 | -- check that lock and atomic functions return cancel_error if the linda was cancelled |
57 | assert( lock( 1) == lanes.cancel_error) | 57 | assert(lock(1) == lanes.cancel_error) |
58 | assert( lock( -1) == lanes.cancel_error) | 58 | assert(lock(-1) == lanes.cancel_error) |
59 | assert( atomic( 1) == lanes.cancel_error) | 59 | assert(atomic(1) == lanes.cancel_error) |
60 | 60 | ||
61 | -- reset the linda so that the other tests work | 61 | -- reset the linda so that the other tests work |
62 | linda:cancel("none") | 62 | linda:cancel("none") |
@@ -70,62 +70,62 @@ end | |||
70 | 70 | ||
71 | -- ################################################################################################## | 71 | -- ################################################################################################## |
72 | 72 | ||
73 | local waitCancellation = function( h, expected_status) | 73 | local waitCancellation = function(h, expected_status) |
74 | local l = lanes.linda() | 74 | local l = lanes.linda() |
75 | if expected_status ~= "running" then | 75 | if expected_status ~= "running" then |
76 | repeat | 76 | repeat |
77 | -- print( "lane status:", h.status) | 77 | -- print("lane status:", h.status) |
78 | SLEEP(0.1) -- wait a bit | 78 | SLEEP(0.1) -- wait a bit |
79 | until h.status ~= "running" | 79 | until h.status ~= "running" |
80 | end | 80 | end |
81 | print( "lane status:", h.status) | 81 | print("lane status:", h.status) |
82 | assert( h.status == expected_status, "lane status " .. h.status .. " (actual) ~= " .. expected_status .. " (expected)") | 82 | assert(h.status == expected_status, "lane status " .. h.status .. " (actual) ~= " .. expected_status .. " (expected)") |
83 | print "test OK" | 83 | print "test OK" |
84 | end | 84 | end |
85 | 85 | ||
86 | local laneBody = function( mode_, payload_) | 86 | local laneBody = function(mode_, payload_) |
87 | local name = "laneBody("..tostring(mode_)..","..tostring(payload_)..")" | 87 | local name = "laneBody("..tostring(mode_)..","..tostring(payload_)..")" |
88 | lane_threadname(name) | 88 | lane_threadname(name) |
89 | 89 | ||
90 | set_finalizer( function( err, stk) | 90 | set_finalizer(function(err, stk) |
91 | if err == lanes.cancel_error then | 91 | if err == lanes.cancel_error then |
92 | -- note that we don't get the cancel_error when running wrapped inside a protected call if it doesn't rethrow it | 92 | -- note that we don't get the cancel_error when running wrapped inside a protected call if it doesn't rethrow it |
93 | print( " laneBody after cancel" ) | 93 | print(" laneBody after cancel" ) |
94 | elseif err then | 94 | elseif err then |
95 | print( " laneBody error: "..tostring(err)) | 95 | print(" laneBody error: "..tostring(err)) |
96 | else | 96 | else |
97 | print(" laneBody finalized") | 97 | print(" laneBody finalized") |
98 | end | 98 | end |
99 | end) | 99 | end) |
100 | 100 | ||
101 | print( " entering " , name) | 101 | print(" entering " , name) |
102 | repeat | 102 | repeat |
103 | if mode_ == "receive" then | 103 | if mode_ == "receive" then |
104 | -- linda mode | 104 | -- linda mode |
105 | io.stdout:write( " lane calling receive() ... ") | 105 | io.stdout:write(" lane calling receive() ... ") |
106 | local key, val = linda:receive( payload_, "boob") | 106 | local key, val = linda:receive(payload_, "boob") |
107 | print(tostring(key), val == lanes.cancel_error and "cancel_error" or tostring(val)) | 107 | print(tostring(key), val == lanes.cancel_error and "cancel_error" or tostring(val)) |
108 | if val == lanes.cancel_error then | 108 | if val == lanes.cancel_error then |
109 | break -- gracefully abort loop | 109 | break -- gracefully abort loop |
110 | end | 110 | end |
111 | elseif mode_ == "get" then | 111 | elseif mode_ == "get" then |
112 | -- busy wait mode getting data from the linda | 112 | -- busy wait mode getting data from the linda |
113 | io.stdout:write( " lane busy waiting ... ") | 113 | io.stdout:write(" lane busy waiting ... ") |
114 | for i = 1, payload_ do | 114 | for i = 1, payload_ do |
115 | -- force a non-jitable call | 115 | -- force a non-jitable call |
116 | local _, a = linda:get( "val") | 116 | local _, a = linda:get("val") |
117 | a = a * 2 | 117 | a = a * 2 |
118 | end | 118 | end |
119 | print( "again?") | 119 | print("again?") |
120 | elseif mode_ == "busy" then | 120 | elseif mode_ == "busy" then |
121 | -- busy wait mode in pure Lua code | 121 | -- busy wait mode in pure Lua code |
122 | io.stdout:write( " lane busy waiting ... ") | 122 | io.stdout:write(" lane busy waiting ... ") |
123 | local _, a = linda:get( "val") | 123 | local _, a = linda:get("val") |
124 | for i = 1, payload_ do | 124 | for i = 1, payload_ do |
125 | a = a * 2 | 125 | a = a * 2 |
126 | a = math.sin( a) * math.sin( a) + math.cos( a) * math.cos( a) -- aka 1 | 126 | a = math.sin(a) * math.sin(a) + math.cos(a) * math.cos(a) -- aka 1 |
127 | end | 127 | end |
128 | print( "again?") | 128 | print("again?") |
129 | else | 129 | else |
130 | error "no mode: raise an error" | 130 | error "no mode: raise an error" |
131 | end | 131 | end |
@@ -133,23 +133,23 @@ local laneBody = function( mode_, payload_) | |||
133 | print " lane shutting down after breaking out of loop" | 133 | print " lane shutting down after breaking out of loop" |
134 | end | 134 | end |
135 | 135 | ||
136 | local protectedBody = function( ...) | 136 | local protectedBody = function(...) |
137 | local ce = lanes.cancel_error | 137 | local ce = lanes.cancel_error |
138 | local errorHandler = function( _msg) | 138 | local errorHandler = function(_msg) |
139 | -- forward the message to the main thread that will display it with a popup | 139 | -- forward the message to the main thread that will display it with a popup |
140 | print( " error handler got ", ce == _msg and "cancel_error"or tostring( _msg)) | 140 | print(" error handler got ", ce == _msg and "cancel_error" or tostring(_msg)) |
141 | return _msg | 141 | return _msg |
142 | end | 142 | end |
143 | -- Lua 5.1 doesn't pass additional xpcall arguments to the called function | 143 | -- Lua 5.1 doesn't pass additional xpcall arguments to the called function |
144 | -- therefore we need to create a closure that has no arguments but pulls everything from its upvalue | 144 | -- therefore we need to create a closure that has no arguments but pulls everything from its upvalue |
145 | local params = {...} | 145 | local params = {...} |
146 | local unpack = table.unpack or unpack -- unpack for 5.1, table.unpack for 5.2+ | 146 | local unpack = table.unpack or unpack -- unpack for 5.1, table.unpack for 5.2+ |
147 | local paramLessClosure = function() laneBody(unpack( params)) end | 147 | local paramLessClosure = function() laneBody(unpack(params)) end |
148 | local status, message = xpcall( paramLessClosure, errorHandler) | 148 | local status, message = xpcall(paramLessClosure, errorHandler) |
149 | if status == false then | 149 | if status == false then |
150 | print( " error handler rethrowing '" .. (ce == message and "cancel_error"or tostring( message)) .. "'") | 150 | print(" error handler rethrowing '" .. (ce == message and "cancel_error"or tostring(message)) .. "'") |
151 | -- if the error isn't rethrown, the lane's finalizer won't get it | 151 | -- if the error isn't rethrown, the lane's finalizer won't get it |
152 | error( message) | 152 | error(message) |
153 | end | 153 | end |
154 | end | 154 | end |
155 | 155 | ||
@@ -159,20 +159,20 @@ end | |||
159 | if not next(which_tests) or which_tests.linda then | 159 | if not next(which_tests) or which_tests.linda then |
160 | remaining_tests.linda = nil | 160 | remaining_tests.linda = nil |
161 | print "\n\n####################################################################\nbegin linda cancel test\n" | 161 | print "\n\n####################################################################\nbegin linda cancel test\n" |
162 | h = generator( "*", laneBody)( "receive", nil) -- start an infinite wait on the linda | 162 | h = generator("*", laneBody)("receive", nil) -- start an infinite wait on the linda |
163 | 163 | ||
164 | print "wait 1s" | 164 | print "wait 1s" |
165 | SLEEP(1) | 165 | SLEEP(1) |
166 | 166 | ||
167 | -- linda cancel: linda:receive() returns nil,cancel_error immediately | 167 | -- linda cancel: linda:receive() returns nil,cancel_error immediately |
168 | print "cancelling" | 168 | print "cancelling" |
169 | linda:cancel( "both") | 169 | linda:cancel("both") |
170 | 170 | ||
171 | -- wait until cancellation is effective. | 171 | -- wait until cancellation is effective. |
172 | waitCancellation( h, "done") | 172 | waitCancellation(h, "done") |
173 | 173 | ||
174 | -- reset the linda so that the other tests work | 174 | -- reset the linda so that the other tests work |
175 | linda:cancel( "none") | 175 | linda:cancel("none") |
176 | end | 176 | end |
177 | 177 | ||
178 | -- ################################################################################################## | 178 | -- ################################################################################################## |
@@ -180,23 +180,23 @@ end | |||
180 | if not next(which_tests) or which_tests.soft then | 180 | if not next(which_tests) or which_tests.soft then |
181 | remaining_tests.soft = nil | 181 | remaining_tests.soft = nil |
182 | print "\n\n####################################################################\nbegin soft cancel test\n" | 182 | print "\n\n####################################################################\nbegin soft cancel test\n" |
183 | h = generator( "*", protectedBody)( "receive") -- start an infinite wait on the linda | 183 | h = generator("*", protectedBody)("receive") -- start an infinite wait on the linda |
184 | 184 | ||
185 | print "wait 1s" | 185 | print "wait 1s" |
186 | SLEEP(1) | 186 | SLEEP(1) |
187 | 187 | ||
188 | -- soft cancel, no awakening of waiting linda operations, should timeout | 188 | -- soft cancel, no awakening of waiting linda operations, should timeout |
189 | local a, b = h:cancel( "soft", 1, false) | 189 | local a, b = h:cancel("soft", 1, false) |
190 | -- cancellation should fail as the lane is still waiting on its linda | 190 | -- cancellation should fail as the lane is still waiting on its linda |
191 | assert( a == false and b == "timeout") | 191 | assert(a == false and b == "timeout") |
192 | waitCancellation( h, "waiting") | 192 | waitCancellation(h, "waiting") |
193 | 193 | ||
194 | -- soft cancel, this time awakens waiting linda operations, which returns cancel_error immediately, no timeout. | 194 | -- soft cancel, this time awakens waiting linda operations, which returns cancel_error immediately, no timeout. |
195 | print "cancelling" | 195 | print "cancelling" |
196 | h:cancel( "soft", true) | 196 | h:cancel("soft", true) |
197 | 197 | ||
198 | -- wait until cancellation is effective. the lane will interrupt its loop and print the exit message | 198 | -- wait until cancellation is effective. the lane will interrupt its loop and print the exit message |
199 | waitCancellation( h, "done") | 199 | waitCancellation(h, "done") |
200 | end | 200 | end |
201 | 201 | ||
202 | -- ################################################################################################## | 202 | -- ################################################################################################## |
@@ -204,16 +204,16 @@ end | |||
204 | if not next(which_tests) or which_tests.hook then | 204 | if not next(which_tests) or which_tests.hook then |
205 | remaining_tests.hook = nil | 205 | remaining_tests.hook = nil |
206 | print "\n\n####################################################################\nbegin hook cancel test\n" | 206 | print "\n\n####################################################################\nbegin hook cancel test\n" |
207 | h = generator( "*", protectedBody)( "get", 300000) | 207 | h = generator("*", protectedBody)("get", 300000) |
208 | print "wait 2s" | 208 | print "wait 2s" |
209 | SLEEP(2) | 209 | SLEEP(2) |
210 | 210 | ||
211 | -- count hook cancel after some instruction instructions | 211 | -- count hook cancel after some instruction instructions |
212 | print "cancelling" | 212 | print "cancelling" |
213 | h:cancel( "line", 300, 5.0) | 213 | h:cancel("line", 300, 5.0) |
214 | 214 | ||
215 | -- wait until cancellation is effective. the lane will interrupt its loop and print the exit message | 215 | -- wait until cancellation is effective. the lane will interrupt its loop and print the exit message |
216 | waitCancellation( h, "cancelled") | 216 | waitCancellation(h, "cancelled") |
217 | end | 217 | end |
218 | 218 | ||
219 | -- ################################################################################################## | 219 | -- ################################################################################################## |
@@ -221,7 +221,7 @@ end | |||
221 | if not next(which_tests) or which_tests.hard then | 221 | if not next(which_tests) or which_tests.hard then |
222 | remaining_tests.hard = nil | 222 | remaining_tests.hard = nil |
223 | print "\n\n####################################################################\nbegin hard cancel test\n" | 223 | print "\n\n####################################################################\nbegin hard cancel test\n" |
224 | h = lanes.gen( "*", protectedBody)( "receive", nil) -- infinite timeout | 224 | h = lanes.gen("*", protectedBody)("receive", nil) -- infinite timeout |
225 | 225 | ||
226 | -- wait 2s before cancelling the lane | 226 | -- wait 2s before cancelling the lane |
227 | print "wait 2s" | 227 | print "wait 2s" |
@@ -232,7 +232,7 @@ if not next(which_tests) or which_tests.hard then | |||
232 | h:cancel() | 232 | h:cancel() |
233 | 233 | ||
234 | -- wait until cancellation is effective. the lane will be stopped by the linda operation throwing an error | 234 | -- wait until cancellation is effective. the lane will be stopped by the linda operation throwing an error |
235 | waitCancellation( h, "cancelled") | 235 | waitCancellation(h, "cancelled") |
236 | end | 236 | end |
237 | 237 | ||
238 | -- ################################################################################################## | 238 | -- ################################################################################################## |
@@ -240,7 +240,7 @@ end | |||
240 | if not next(which_tests) or which_tests.hard_unprotected then | 240 | if not next(which_tests) or which_tests.hard_unprotected then |
241 | remaining_tests.hard_unprotected = nil | 241 | remaining_tests.hard_unprotected = nil |
242 | print "\n\n####################################################################\nbegin hard cancel test with unprotected lane body\n" | 242 | print "\n\n####################################################################\nbegin hard cancel test with unprotected lane body\n" |
243 | h = generator( "*", laneBody)( "receive", nil) | 243 | h = generator("*", laneBody)("receive", nil) |
244 | 244 | ||
245 | -- wait 2s before cancelling the lane | 245 | -- wait 2s before cancelling the lane |
246 | print "wait 2s" | 246 | print "wait 2s" |
@@ -251,7 +251,7 @@ if not next(which_tests) or which_tests.hard_unprotected then | |||
251 | h:cancel() | 251 | h:cancel() |
252 | 252 | ||
253 | -- wait until cancellation is effective. the lane will be stopped by the linda operation throwing an error | 253 | -- wait until cancellation is effective. the lane will be stopped by the linda operation throwing an error |
254 | waitCancellation( h, "cancelled") | 254 | waitCancellation(h, "cancelled") |
255 | end | 255 | end |
256 | 256 | ||
257 | -- ################################################################################################## | 257 | -- ################################################################################################## |