aboutsummaryrefslogtreecommitdiff
path: root/src/cancel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/cancel.cpp')
-rw-r--r--src/cancel.cpp140
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
41namespace {
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
84static 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]]
107static 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_)
133LUAG_FUNC(cancel_test) 120LUAG_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])
143LUAG_FUNC(lane_cancel) 151LUAG_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: