aboutsummaryrefslogtreecommitdiff
path: root/src/cancel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/cancel.cpp')
-rw-r--r--src/cancel.cpp35
1 files changed, 20 insertions, 15 deletions
diff --git a/src/cancel.cpp b/src/cancel.cpp
index dd848a7..fe1623b 100644
--- a/src/cancel.cpp
+++ b/src/cancel.cpp
@@ -107,7 +107,7 @@ LUAG_FUNC(cancel_test)
107 107
108// ################################################################################################# 108// #################################################################################################
109 109
110[[nodiscard]] static CancelResult thread_cancel_soft(Lane* lane_, lua_Duration duration_, bool wakeLane_) 110[[nodiscard]] static CancelResult thread_cancel_soft(Lane* lane_, std::chrono::time_point<std::chrono::steady_clock> until_, bool wakeLane_)
111{ 111{
112 lane_->cancelRequest = CancelRequest::Soft; // it's now signaled to stop 112 lane_->cancelRequest = CancelRequest::Soft; // it's now signaled to stop
113 // negative timeout: we don't want to truly abort the lane, we just want it to react to cancel_test() on its own 113 // negative timeout: we don't want to truly abort the lane, we just want it to react to cancel_test() on its own
@@ -118,12 +118,12 @@ LUAG_FUNC(cancel_test)
118 } 118 }
119 } 119 }
120 120
121 return lane_->waitForCompletion(duration_) ? CancelResult::Cancelled : CancelResult::Timeout; 121 return lane_->waitForCompletion(until_) ? CancelResult::Cancelled : CancelResult::Timeout;
122} 122}
123 123
124// ################################################################################################# 124// #################################################################################################
125 125
126[[nodiscard]] static CancelResult thread_cancel_hard(Lane* lane_, lua_Duration duration_, bool wakeLane_) 126[[nodiscard]] static CancelResult thread_cancel_hard(Lane* lane_, std::chrono::time_point<std::chrono::steady_clock> until_, bool wakeLane_)
127{ 127{
128 lane_->cancelRequest = CancelRequest::Hard; // it's now signaled to stop 128 lane_->cancelRequest = CancelRequest::Hard; // it's now signaled to stop
129 // lane_->thread.get_stop_source().request_stop(); 129 // lane_->thread.get_stop_source().request_stop();
@@ -134,13 +134,13 @@ LUAG_FUNC(cancel_test)
134 } 134 }
135 } 135 }
136 136
137 CancelResult result{ lane_->waitForCompletion(duration_) ? CancelResult::Cancelled : CancelResult::Timeout }; 137 CancelResult result{ lane_->waitForCompletion(until_) ? CancelResult::Cancelled : CancelResult::Timeout };
138 return result; 138 return result;
139} 139}
140 140
141// ################################################################################################# 141// #################################################################################################
142 142
143CancelResult thread_cancel(Lane* lane_, CancelOp op_, int hookCount_, lua_Duration duration_, bool wakeLane_) 143CancelResult thread_cancel(Lane* lane_, CancelOp op_, int hookCount_, std::chrono::time_point<std::chrono::steady_clock> until_, bool wakeLane_)
144{ 144{
145 // remember that lanes are not transferable: only one thread can cancel a lane, so no multithreading issue here 145 // remember that lanes are not transferable: only one thread can cancel a lane, so no multithreading issue here
146 // We can read 'lane_->status' without locks, but not wait for it (if Posix no PTHREAD_TIMEDJOIN) 146 // We can read 'lane_->status' without locks, but not wait for it (if Posix no PTHREAD_TIMEDJOIN)
@@ -152,12 +152,12 @@ CancelResult thread_cancel(Lane* lane_, CancelOp op_, int hookCount_, lua_Durati
152 // signal the linda the wake up the thread so that it can react to the cancel query 152 // signal the linda the wake up the thread so that it can react to the cancel query
153 // let us hope we never land here with a pointer on a linda that has been destroyed... 153 // let us hope we never land here with a pointer on a linda that has been destroyed...
154 if (op_ == CancelOp::Soft) { 154 if (op_ == CancelOp::Soft) {
155 return thread_cancel_soft(lane_, duration_, wakeLane_); 155 return thread_cancel_soft(lane_, until_, wakeLane_);
156 } else if (static_cast<int>(op_) > static_cast<int>(CancelOp::Soft)) { 156 } else if (static_cast<int>(op_) > static_cast<int>(CancelOp::Soft)) {
157 lua_sethook(lane_->L, cancel_hook, static_cast<int>(op_), hookCount_); 157 lua_sethook(lane_->L, cancel_hook, static_cast<int>(op_), hookCount_);
158 } 158 }
159 159
160 return thread_cancel_hard(lane_, duration_, wakeLane_); 160 return thread_cancel_hard(lane_, until_, wakeLane_);
161} 161}
162 162
163// ################################################################################################# 163// #################################################################################################
@@ -200,7 +200,7 @@ CancelOp which_cancel_op(char const* opString_)
200 200
201// ################################################################################################# 201// #################################################################################################
202 202
203// bool[,reason] = lane_h:cancel( [mode, hookcount] [, timeout] [, wake_lindas]) 203// bool[,reason] = lane_h:cancel( [mode, hookcount] [, timeout] [, wake_lane])
204LUAG_FUNC(thread_cancel) 204LUAG_FUNC(thread_cancel)
205{ 205{
206 Lane* const lane{ ToLane(L_, 1) }; 206 Lane* const lane{ ToLane(L_, 1) };
@@ -215,14 +215,19 @@ LUAG_FUNC(thread_cancel)
215 } 215 }
216 } 216 }
217 217
218 lua_Duration wait_timeout{ 0.0 }; 218 std::chrono::time_point<std::chrono::steady_clock> until{ std::chrono::time_point<std::chrono::steady_clock>::max() };
219 if (lua_type(L_, 2) == LUA_TNUMBER) { 219 if (lua_type(L_, 2) == LUA_TNUMBER) { // we don't want to use lua_isnumber() because of autocoercion
220 wait_timeout = lua_Duration{ lua_tonumber(L_, 2) }; 220 lua_Duration const duration{ lua_tonumber(L_, 2) };
221 lua_remove(L_, 2); // argument is processed, remove it 221 if (duration.count() >= 0.0) {
222 if (wait_timeout.count() < 0.0) { 222 until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(duration);
223 raise_luaL_error(L_, "cancel timeout cannot be < 0"); 223 } else {
224 raise_luaL_argerror(L_, 2, "duration cannot be < 0");
224 } 225 }
226 lua_remove(L_, 2); // argument is processed, remove it
227 } else if (lua_isnil(L_, 2)) { // alternate explicit "infinite timeout" by passing nil before the key
228 lua_remove(L_, 2); // argument is processed, remove it
225 } 229 }
230
226 // we wake by default in "hard" mode (remember that hook is hard too), but this can be turned off if desired 231 // we wake by default in "hard" mode (remember that hook is hard too), but this can be turned off if desired
227 bool wake_lane{ op != CancelOp::Soft }; 232 bool wake_lane{ op != CancelOp::Soft };
228 if (lua_gettop(L_) >= 2) { 233 if (lua_gettop(L_) >= 2) {
@@ -233,7 +238,7 @@ LUAG_FUNC(thread_cancel)
233 lua_remove(L_, 2); // argument is processed, remove it 238 lua_remove(L_, 2); // argument is processed, remove it
234 } 239 }
235 STACK_CHECK_START_REL(L_, 0); 240 STACK_CHECK_START_REL(L_, 0);
236 switch (thread_cancel(lane, op, hook_count, wait_timeout, wake_lane)) { 241 switch (thread_cancel(lane, op, hook_count, until, wake_lane)) {
237 default: // should never happen unless we added a case and forgot to handle it 242 default: // should never happen unless we added a case and forgot to handle it
238 LUA_ASSERT(L_, false); 243 LUA_ASSERT(L_, false);
239 break; 244 break;