diff options
Diffstat (limited to 'src/cancel.cpp')
-rw-r--r-- | src/cancel.cpp | 140 |
1 files changed, 74 insertions, 66 deletions
diff --git a/src/cancel.cpp b/src/cancel.cpp index 5bba9fc..6812b0d 100644 --- a/src/cancel.cpp +++ b/src/cancel.cpp | |||
@@ -38,6 +38,53 @@ THE SOFTWARE. | |||
38 | #include "debugspew.hpp" | 38 | #include "debugspew.hpp" |
39 | #include "lane.hpp" | 39 | #include "lane.hpp" |
40 | 40 | ||
41 | namespace { | ||
42 | namespace local { | ||
43 | |||
44 | // ######################################################################################### | ||
45 | // ######################################################################################### | ||
46 | |||
47 | [[nodiscard]] | ||
48 | static std::optional<CancelOp> WhichCancelOp(std::string_view const& opString_) | ||
49 | { | ||
50 | if (opString_ == "soft") { | ||
51 | return std::make_optional<CancelOp>(CancelRequest::Soft, LuaHookMask::None); | ||
52 | } else if (opString_ == "hard") { | ||
53 | return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::None); | ||
54 | } else if (opString_ == "call") { | ||
55 | return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::Call); | ||
56 | } else if (opString_ == "ret") { | ||
57 | return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::Ret); | ||
58 | } else if (opString_ == "line") { | ||
59 | return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::Line); | ||
60 | } else if (opString_ == "count") { | ||
61 | return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::Count); | ||
62 | } else if (opString_ == "all") { | ||
63 | return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::All); | ||
64 | } | ||
65 | return std::nullopt; | ||
66 | } | ||
67 | |||
68 | // ######################################################################################### | ||
69 | |||
70 | [[nodiscard]] | ||
71 | static CancelOp WhichCancelOp(lua_State* const L_, StackIndex const idx_) | ||
72 | { | ||
73 | if (luaW_type(L_, idx_) == LuaType::STRING) { | ||
74 | std::string_view const _str{ luaW_tostring(L_, idx_) }; | ||
75 | auto const _op{ WhichCancelOp(_str) }; | ||
76 | lua_remove(L_, idx_); // argument is processed, remove it | ||
77 | if (!_op.has_value()) { | ||
78 | raise_luaL_error(L_, "Invalid cancel operation '%s'", _str.data()); | ||
79 | } | ||
80 | return _op.value(); | ||
81 | } | ||
82 | return CancelOp{ CancelRequest::Hard, LuaHookMask::None }; | ||
83 | } | ||
84 | |||
85 | } // namespace local | ||
86 | } // namespace | ||
87 | |||
41 | // ################################################################################################# | 88 | // ################################################################################################# |
42 | // ################################################################################################# | 89 | // ################################################################################################# |
43 | 90 | ||
@@ -60,66 +107,6 @@ CancelRequest CheckCancelRequest(lua_State* const L_) | |||
60 | 107 | ||
61 | // ################################################################################################# | 108 | // ################################################################################################# |
62 | // ################################################################################################# | 109 | // ################################################################################################# |
63 | |||
64 | //--- | ||
65 | // = lane_cancel( lane_ud [,timeout_secs=0.0] [,wake_lindas_bool=false] ) | ||
66 | // | ||
67 | // The originator thread asking us specifically to cancel the other thread. | ||
68 | // | ||
69 | // 'timeout': <0: wait forever, until the lane is finished | ||
70 | // 0.0: just signal it to cancel, no time waited | ||
71 | // >0: time to wait for the lane to detect cancellation | ||
72 | // | ||
73 | // 'wake_lindas_bool': if true, signal any linda the thread is waiting on | ||
74 | // instead of waiting for its timeout (if any) | ||
75 | // | ||
76 | // Returns: true if the lane was already finished (Done/Error/Cancelled) or if we | ||
77 | // managed to cancel it. | ||
78 | // false if the cancellation timed out, or a kill was needed. | ||
79 | // | ||
80 | |||
81 | // ################################################################################################# | ||
82 | // ################################################################################################# | ||
83 | |||
84 | static std::optional<CancelOp> WhichCancelOp(std::string_view const& opString_) | ||
85 | { | ||
86 | if (opString_ == "soft") { | ||
87 | return std::make_optional<CancelOp>(CancelRequest::Soft, LuaHookMask::None); | ||
88 | } else if (opString_ == "hard") { | ||
89 | return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::None); | ||
90 | } else if (opString_== "call") { | ||
91 | return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::Call); | ||
92 | } else if (opString_ == "ret") { | ||
93 | return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::Ret); | ||
94 | } else if (opString_ == "line") { | ||
95 | return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::Line); | ||
96 | } else if (opString_ == "count") { | ||
97 | return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::Count); | ||
98 | } else if (opString_ == "all") { | ||
99 | return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::All); | ||
100 | } | ||
101 | return std::nullopt; | ||
102 | } | ||
103 | |||
104 | // ################################################################################################# | ||
105 | |||
106 | [[nodiscard]] | ||
107 | static CancelOp WhichCancelOp(lua_State* const L_, StackIndex const idx_) | ||
108 | { | ||
109 | if (luaG_type(L_, idx_) == LuaType::STRING) { | ||
110 | std::string_view const _str{ luaG_tostring(L_, idx_) }; | ||
111 | auto const _op{ WhichCancelOp(_str) }; | ||
112 | lua_remove(L_, idx_); // argument is processed, remove it | ||
113 | if (!_op.has_value()) { | ||
114 | raise_luaL_error(L_, "Invalid cancel operation '%s'", _str.data()); | ||
115 | } | ||
116 | return _op.value(); | ||
117 | } | ||
118 | return CancelOp{ CancelRequest::Hard, LuaHookMask::None }; | ||
119 | } | ||
120 | |||
121 | // ################################################################################################# | ||
122 | // ################################################################################################# | ||
123 | // ######################################### Lua API ############################################### | 110 | // ######################################### Lua API ############################################### |
124 | // ################################################################################################# | 111 | // ################################################################################################# |
125 | // ################################################################################################# | 112 | // ################################################################################################# |
@@ -133,24 +120,45 @@ static CancelOp WhichCancelOp(lua_State* const L_, StackIndex const idx_) | |||
133 | LUAG_FUNC(cancel_test) | 120 | LUAG_FUNC(cancel_test) |
134 | { | 121 | { |
135 | CancelRequest const _test{ CheckCancelRequest(L_) }; | 122 | CancelRequest const _test{ CheckCancelRequest(L_) }; |
136 | lua_pushboolean(L_, _test != CancelRequest::None); | 123 | if (_test == CancelRequest::None) { |
124 | lua_pushboolean(L_, 0); | ||
125 | } else { | ||
126 | luaW_pushstring(L_, (_test == CancelRequest::Soft) ? "soft" : "hard"); | ||
127 | } | ||
137 | return 1; | 128 | return 1; |
138 | } | 129 | } |
139 | 130 | ||
140 | // ################################################################################################# | 131 | // ################################################################################################# |
141 | 132 | ||
133 | //--- | ||
134 | // = lane_cancel( lane_ud [,timeout_secs=0.0] [,wake_lindas_bool=false] ) | ||
135 | // | ||
136 | // The originator thread asking us specifically to cancel the other thread. | ||
137 | // | ||
138 | // 'timeout': <0: wait forever, until the lane is finished | ||
139 | // 0.0: just signal it to cancel, no time waited | ||
140 | // >0: time to wait for the lane to detect cancellation | ||
141 | // | ||
142 | // 'wake_lindas_bool': if true, signal any linda the thread is waiting on | ||
143 | // instead of waiting for its timeout (if any) | ||
144 | // | ||
145 | // Returns: true if the lane was already finished (Done/Error/Cancelled) or if we | ||
146 | // managed to cancel it. | ||
147 | // false if the cancellation timed out, or a kill was needed. | ||
148 | // | ||
149 | |||
142 | // bool[,reason] = lane_h:cancel( [cancel_op, hookcount] [, timeout] [, wake_lane]) | 150 | // bool[,reason] = lane_h:cancel( [cancel_op, hookcount] [, timeout] [, wake_lane]) |
143 | LUAG_FUNC(lane_cancel) | 151 | LUAG_FUNC(lane_cancel) |
144 | { | 152 | { |
145 | Lane* const _lane{ ToLane(L_, StackIndex{ 1 }) }; // L_: lane [cancel_op, hookcount] [, timeout] [, wake_lane] | 153 | Lane* const _lane{ ToLane(L_, StackIndex{ 1 }) }; // L_: lane [cancel_op, hookcount] [, timeout] [, wake_lane] |
146 | CancelOp const _op{ WhichCancelOp(L_, StackIndex{ 2 }) }; // L_: lane [hookcount] [, timeout] [, wake_lane] | 154 | CancelOp const _op{ local::WhichCancelOp(L_, StackIndex{ 2 }) }; // L_: lane [hookcount] [, timeout] [, wake_lane] |
147 | 155 | ||
148 | int const _hook_count{ std::invoke([_op, L_]() { | 156 | int const _hook_count{ std::invoke([_op, L_]() { |
149 | if (_op.hookMask == LuaHookMask::None) { | 157 | if (_op.hookMask == LuaHookMask::None) { |
150 | // the caller shouldn't have provided a hook count in that case | 158 | // the caller shouldn't have provided a hook count in that case |
151 | return 0; | 159 | return 0; |
152 | } | 160 | } |
153 | if (luaG_type(L_, StackIndex{ 2 }) != LuaType::NUMBER) { | 161 | if (luaW_type(L_, StackIndex{ 2 }) != LuaType::NUMBER) { |
154 | raise_luaL_error(L_, "Hook count expected"); | 162 | raise_luaL_error(L_, "Hook count expected"); |
155 | } | 163 | } |
156 | auto const _hook_count{ static_cast<int>(lua_tointeger(L_, 2)) }; | 164 | auto const _hook_count{ static_cast<int>(lua_tointeger(L_, 2)) }; |
@@ -162,7 +170,7 @@ LUAG_FUNC(lane_cancel) | |||
162 | }) }; | 170 | }) }; |
163 | 171 | ||
164 | std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; | 172 | std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; |
165 | if (luaG_type(L_, StackIndex{ 2 }) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion | 173 | if (luaW_type(L_, StackIndex{ 2 }) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion |
166 | lua_Duration const duration{ lua_tonumber(L_, 2) }; | 174 | lua_Duration const duration{ lua_tonumber(L_, 2) }; |
167 | if (duration.count() >= 0.0) { | 175 | if (duration.count() >= 0.0) { |
168 | _until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(duration); | 176 | _until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(duration); |
@@ -178,7 +186,7 @@ LUAG_FUNC(lane_cancel) | |||
178 | WakeLane _wake_lane{ (_op.mode == CancelRequest::Hard) ? WakeLane::Yes : WakeLane::No }; | 186 | WakeLane _wake_lane{ (_op.mode == CancelRequest::Hard) ? WakeLane::Yes : WakeLane::No }; |
179 | if (lua_gettop(L_) >= 2) { | 187 | if (lua_gettop(L_) >= 2) { |
180 | if (!lua_isboolean(L_, 2)) { | 188 | if (!lua_isboolean(L_, 2)) { |
181 | raise_luaL_error(L_, "Boolean expected for wake_lane argument, got %s", luaG_typename(L_, StackIndex{ 2 }).data()); | 189 | raise_luaL_error(L_, "Boolean expected for wake_lane argument, got %s", luaW_typename(L_, StackIndex{ 2 }).data()); |
182 | } | 190 | } |
183 | _wake_lane = lua_toboolean(L_, 2) ? WakeLane::Yes : WakeLane::No; | 191 | _wake_lane = lua_toboolean(L_, 2) ? WakeLane::Yes : WakeLane::No; |
184 | lua_remove(L_, 2); // argument is processed, remove it // L_: lane | 192 | lua_remove(L_, 2); // argument is processed, remove it // L_: lane |
@@ -198,7 +206,7 @@ LUAG_FUNC(lane_cancel) | |||
198 | 206 | ||
199 | case CancelResult::Timeout: | 207 | case CancelResult::Timeout: |
200 | lua_pushboolean(L_, 0); // L_: false | 208 | lua_pushboolean(L_, 0); // L_: false |
201 | luaG_pushstring(L_, "timeout"); // L_: false "timeout" | 209 | luaW_pushstring(L_, "timeout"); // L_: false "timeout" |
202 | break; | 210 | break; |
203 | 211 | ||
204 | case CancelResult::Cancelled: | 212 | case CancelResult::Cancelled: |