aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lane.cpp142
-rw-r--r--src/lane.h26
-rw-r--r--src/lanes.cpp28
3 files changed, 160 insertions, 36 deletions
diff --git a/src/lane.cpp b/src/lane.cpp
index ba24af3..dd038a3 100644
--- a/src/lane.cpp
+++ b/src/lane.cpp
@@ -186,6 +186,55 @@ static LUAG_FUNC(thread_join)
186 186
187// ################################################################################################# 187// #################################################################################################
188 188
189LUAG_FUNC(thread_resume)
190{
191 static constexpr int kSelf{ 1 };
192 Lane* const _lane{ ToLane(L_, kSelf) };
193 lua_State* const _L2{ _lane->L };
194
195 // wait until the lane yields
196 std::optional<Lane::Status> _hadToWait{}; // for debugging, if we ever raise the error just below
197 {
198 std::unique_lock _guard{ _lane->doneMutex };
199 if (_lane->status == Lane::Pending || _lane->status == Lane::Running || _lane->status == Lane::Resuming) {
200 _hadToWait = _lane->status;
201 _lane->doneCondVar.wait(_guard, [_lane]() { return _lane->status == Lane::Suspended; });
202 }
203 }
204 if (_lane->status != Lane::Suspended) {
205 if (_hadToWait) {
206 raise_luaL_error(L_, "INTERNAL ERROR: Lane status is %s instead of 'suspended'", _lane->threadStatusString().data());
207 } else {
208 raise_luaL_error(L_, "Can't resume a non-suspended coroutine-type Lane");
209 }
210 }
211 int const _nargs{ lua_gettop(L_) - 1 };
212 int const _nresults{ lua_gettop(_L2) };
213 STACK_CHECK_START_ABS(L_, 1 + _nargs); // L_: self args... _L2: results...
214 STACK_CHECK_START_ABS(_L2, _nresults);
215
216 // to retrieve the yielded value of the coroutine on our stack
217 InterCopyContext _cin{ _lane->U, DestState{ L_ }, SourceState{ _L2 }, {}, {}, {}, {}, {} };
218 if (_cin.interMove(_nresults) != InterCopyResult::Success) { // L_: self args... results... _L2:
219 raise_luaL_error(L_, "Failed to retrieve yielded values");
220 }
221
222 // to send our args on the coroutine stack
223 InterCopyContext _cout{ _lane->U, DestState{ _L2 }, SourceState{ L_ }, {}, SourceIndex{ 2 }, {}, {}, {} };
224 if (_cout.interCopy(_nargs) != InterCopyResult::Success) { // L_: self args... results... _L2: args...
225 raise_luaL_error(L_, "Failed to send resumed values");
226 }
227
228 STACK_CHECK(_L2, _nargs); // we should have removed everything from the lane's stack, and pushed our args
229 STACK_CHECK(L_, 1 + _nargs + _nresults); // and the results of the coroutine are on top here
230 std::unique_lock _guard{ _lane->doneMutex };
231 _lane->status = Lane::Resuming;
232 _lane->doneCondVar.notify_one();
233 return _nresults;
234}
235
236// #################################################################################################
237
189// key is numeric, wait until the thread returns and populate the environment with the return values 238// key is numeric, wait until the thread returns and populate the environment with the return values
190// If the return values signal an error, propagate it 239// If the return values signal an error, propagate it
191// Else If key is found in the environment, return it 240// Else If key is found in the environment, return it
@@ -697,12 +746,37 @@ static void lane_main(Lane* const lane_)
697 if (lane_->status == Lane::Pending) { // nothing wrong happened during preparation, we can work 746 if (lane_->status == Lane::Pending) { // nothing wrong happened during preparation, we can work
698 // At this point, the lane function and arguments are on the stack, possibly preceded by the error handler 747 // At this point, the lane function and arguments are on the stack, possibly preceded by the error handler
699 int const _errorHandlerCount{ lane_->errorTraceLevel == Lane::Minimal ? 0 : 1}; 748 int const _errorHandlerCount{ lane_->errorTraceLevel == Lane::Minimal ? 0 : 1};
700 int const _nargs{ lua_gettop(_L) - 1 - _errorHandlerCount }; 749 int _nargs{ lua_gettop(_L) - 1 - _errorHandlerCount };
701 lane_->status = Lane::Running; // Pending -> Running 750 {
751 std::unique_lock _guard{ lane_->doneMutex };
752 lane_->status = Lane::Running; // Pending -> Running
753 }
702 754
703 PrepareLaneHelpers(lane_); 755 PrepareLaneHelpers(lane_);
704 756 if (lane_->S == lane_->L) { // L: eh? f args...
705 _rc = ToLuaError(lua_pcall(_L, _nargs, LUA_MULTRET, _errorHandlerCount)); // L: eh? retvals|err 757 _rc = ToLuaError(lua_pcall(_L, _nargs, LUA_MULTRET, _errorHandlerCount)); // L: eh? retvals|err
758 } else {
759 // S and L are different: we run as a coroutine in Lua thread L created in state S
760 do {
761 int _nresults{};
762 _rc = luaG_resume(_L, nullptr, _nargs, &_nresults); // L: eh? retvals|err
763 if (_rc == LuaError::YIELD) {
764 // change our status to suspended, and wait until someone wants us to resume
765 std::unique_lock _guard{ lane_->doneMutex };
766 lane_->status = Lane::Suspended; // Running -> Suspended
767 lane_->doneCondVar.notify_one();
768 // wait until the user wants us to resume
769 // TODO: do I update waiting_on or not, so that the lane can be woken by cancellation requests here?
770 // lane_->waiting_on = &lane_->doneCondVar;
771 lane_->doneCondVar.wait(_guard, [lane_]() { return lane_->status == Lane::Resuming; });
772 // here lane_->doneMutex is locked again
773 // lane_->waiting_on = nullptr;
774 lane_->status = Lane::Running; // Resuming -> Running
775 // on the stack we find the values pushed by lane:resume()
776 _nargs = lua_gettop(_L);
777 }
778 } while (_rc == LuaError::YIELD);
779 }
706 780
707 if (_errorHandlerCount) { 781 if (_errorHandlerCount) {
708 lua_remove(_L, 1); // L: retvals|error 782 lua_remove(_L, 1); // L: retvals|error
@@ -713,7 +787,6 @@ static void lane_main(Lane* const lane_)
713 787
714 DEBUGSPEW_CODE(DebugSpew(lane_->U) << "Lane " << _L << " body: " << GetErrcodeName(_rc) << " (" << (kCancelError.equals(_L, 1) ? "cancelled" : luaG_typename(_L, 1)) << ")" << std::endl); 788 DEBUGSPEW_CODE(DebugSpew(lane_->U) << "Lane " << _L << " body: " << GetErrcodeName(_rc) << " (" << (kCancelError.equals(_L, 1) ? "cancelled" : luaG_typename(_L, 1)) << ")" << std::endl);
715 // Call finalizers, if the script has set them up. 789 // Call finalizers, if the script has set them up.
716 //
717 LuaError const _rc2{ run_finalizers(_L, lane_->errorTraceLevel, _rc) }; 790 LuaError const _rc2{ run_finalizers(_L, lane_->errorTraceLevel, _rc) };
718 DEBUGSPEW_CODE(DebugSpew(lane_->U) << "Lane " << _L << " finalizer: " << GetErrcodeName(_rc2) << std::endl); 791 DEBUGSPEW_CODE(DebugSpew(lane_->U) << "Lane " << _L << " finalizer: " << GetErrcodeName(_rc2) << std::endl);
719 if (_rc2 != LuaError::OK) { // Error within a finalizer! 792 if (_rc2 != LuaError::OK) { // Error within a finalizer!
@@ -722,7 +795,7 @@ static void lane_main(Lane* const lane_)
722 } 795 }
723 lane_->waiting_on = nullptr; // just in case 796 lane_->waiting_on = nullptr; // just in case
724 if (selfdestruct_remove(lane_)) { // check and remove (under lock!) 797 if (selfdestruct_remove(lane_)) { // check and remove (under lock!)
725 // We're a free-running thread and no-one's there to clean us up. 798 // We're a free-running thread and no-one is there to clean us up.
726 lane_->closeState(); 799 lane_->closeState();
727 lane_->U->selfdestructMutex.lock(); 800 lane_->U->selfdestructMutex.lock();
728 // done with lua_close(), terminal shutdown sequence may proceed 801 // done with lua_close(), terminal shutdown sequence may proceed
@@ -739,7 +812,7 @@ static void lane_main(Lane* const lane_)
739 812
740 // leave results (1..top) or error message + stack trace (1..2) on the stack - master will copy them 813 // leave results (1..top) or error message + stack trace (1..2) on the stack - master will copy them
741 Lane::Status const _st{ (_rc == LuaError::OK) ? Lane::Done : kCancelError.equals(_L, 1) ? Lane::Cancelled : Lane::Error }; 814 Lane::Status const _st{ (_rc == LuaError::OK) ? Lane::Done : kCancelError.equals(_L, 1) ? Lane::Cancelled : Lane::Error };
742 // 'doneMutex' protects the -> Done|Error|Cancelled state change 815 // 'doneMutex' protects the -> Done|Error|Cancelled state change, and the Running|Suspended|Resuming state change too
743 std::lock_guard _guard{ lane_->doneMutex }; 816 std::lock_guard _guard{ lane_->doneMutex };
744 lane_->status = _st; 817 lane_->status = _st;
745 lane_->doneCondVar.notify_one(); // wake up master (while 'lane_->doneMutex' is on) 818 lane_->doneCondVar.notify_one(); // wake up master (while 'lane_->doneMutex' is on)
@@ -825,14 +898,21 @@ static LUAG_FUNC(lane_gc)
825// #################################### Lane implementation ######################################## 898// #################################### Lane implementation ########################################
826// ################################################################################################# 899// #################################################################################################
827 900
828Lane::Lane(Universe* U_, lua_State* L_, ErrorTraceLevel errorTraceLevel_) 901Lane::Lane(Universe* const U_, lua_State* const L_, ErrorTraceLevel const errorTraceLevel_, bool const asCoroutine_)
829: U{ U_ } 902: U{ U_ }
903, S{ L_ }
830, L{ L_ } 904, L{ L_ }
831, errorTraceLevel{ errorTraceLevel_ } 905, errorTraceLevel{ errorTraceLevel_ }
832{ 906{
907 STACK_CHECK_START_REL(S, 0);
833 assert(errorTraceLevel == ErrorTraceLevel::Minimal || errorTraceLevel == ErrorTraceLevel::Basic || errorTraceLevel == ErrorTraceLevel::Extended); 908 assert(errorTraceLevel == ErrorTraceLevel::Minimal || errorTraceLevel == ErrorTraceLevel::Basic || errorTraceLevel == ErrorTraceLevel::Extended);
834 kExtendedStackTraceRegKey.setValue(L_, [yes = errorTraceLevel == ErrorTraceLevel::Extended ? 1 : 0](lua_State* L_) { lua_pushboolean(L_, yes); }); 909 kExtendedStackTraceRegKey.setValue(S, [yes = errorTraceLevel == ErrorTraceLevel::Extended ? 1 : 0](lua_State* L_) { lua_pushboolean(L_, yes); });
835 U->tracker.tracking_add(this); 910 U->tracker.tracking_add(this);
911 if (asCoroutine_) {
912 L = lua_newthread(S); // S: thread
913 //kCoroutineRegKey.setValue(S, [](lua_State* const L_) { lua_insert(L_, -2); }); // S:
914 }
915 STACK_CHECK(S, asCoroutine_ ? 1 : 0);
836} 916}
837 917
838// ################################################################################################# 918// #################################################################################################
@@ -970,6 +1050,7 @@ namespace {
970 { "cancel", LG_thread_cancel }, 1050 { "cancel", LG_thread_cancel },
971 { "get_debug_threadname", LG_get_debug_threadname }, 1051 { "get_debug_threadname", LG_get_debug_threadname },
972 { "join", LG_thread_join }, 1052 { "join", LG_thread_join },
1053 { "resume", LG_thread_resume },
973 { nullptr, nullptr } 1054 { nullptr, nullptr }
974 }; 1055 };
975 } // namespace local 1056 } // namespace local
@@ -1059,25 +1140,38 @@ void Lane::startThread(int priority_)
1059//--- 1140//---
1060// str= thread_status( lane ) 1141// str= thread_status( lane )
1061// 1142//
1062// Returns: "pending" not started yet 1143// "pending" -> | ("running" <-> "waiting") <-> "suspended" <-> "resuming" | -> "done"/"error"/"cancelled"
1063// -> "running" started, doing its work.. 1144
1064// <-> "waiting" blocked in a receive() 1145// "pending" not started yet
1065// -> "done" finished, results are there 1146// "running" started, doing its work..
1066// / "error" finished at an error, error value is there 1147// "suspended" returned from a lua_resume
1067// / "cancelled" execution cancelled by M (state gone) 1148// "resuming" told by its parent state to resume
1149// "waiting" blocked in a send()/receive()
1150// "done" finished, results are there
1151// "error" finished at an error, error value is there
1152// "cancelled" execution cancelled (state gone)
1068// 1153//
1069[[nodiscard]] std::string_view Lane::threadStatusString() const 1154[[nodiscard]] std::string_view Lane::threadStatusString() const
1070{ 1155{
1071 std::string_view const _str{ 1156 static constexpr std::string_view kStrs[] = {
1072 (status == Lane::Pending) ? "pending" : 1157 "pending",
1073 (status == Lane::Running) ? "running" : // like in 'co.status()' 1158 "running", "suspended", "resuming",
1074 (status == Lane::Waiting) ? "waiting" : 1159 "waiting",
1075 (status == Lane::Done) ? "done" : 1160 "done", "error", "cancelled"
1076 (status == Lane::Error) ? "error" :
1077 (status == Lane::Cancelled) ? "cancelled" :
1078 ""
1079 }; 1161 };
1080 return _str; 1162 static_assert(0 == static_cast<std::underlying_type_t<Lane::Status>>(Pending));
1163 static_assert(1 == static_cast<std::underlying_type_t<Lane::Status>>(Running));
1164 static_assert(2 == static_cast<std::underlying_type_t<Lane::Status>>(Suspended));
1165 static_assert(3 == static_cast<std::underlying_type_t<Lane::Status>>(Resuming));
1166 static_assert(4 == static_cast<std::underlying_type_t<Lane::Status>>(Waiting));
1167 static_assert(5 == static_cast<std::underlying_type_t<Lane::Status>>(Done));
1168 static_assert(6 == static_cast<std::underlying_type_t<Lane::Status>>(Error));
1169 static_assert(7 == static_cast<std::underlying_type_t<Lane::Status>>(Cancelled));
1170 auto const _status{ static_cast<std::underlying_type_t<Lane::Status>>(status) };
1171 if (_status < 0 || _status > 7) { // should never happen, but better safe than sorry
1172 return "";
1173 }
1174 return kStrs[_status];
1081} 1175}
1082 1176
1083// ################################################################################################# 1177// #################################################################################################
diff --git a/src/lane.h b/src/lane.h
index 0426240..753c230 100644
--- a/src/lane.h
+++ b/src/lane.h
@@ -17,6 +17,9 @@ static constexpr RegistryUniqueKey kExtendedStackTraceRegKey{ 0x38147AD48FB426E2
17 * error (and maybe stack trace) arguments to the finalizer functions would 17 * error (and maybe stack trace) arguments to the finalizer functions would
18 * anyways complicate that approach. 18 * anyways complicate that approach.
19 */ 19 */
20// xxh64 of string "kCoroutineRegKey" generated at https://www.pelock.com/products/hash-calculator
21static constexpr RegistryUniqueKey kCoroutineRegKey{ 0x72B049B0D130F009ull };
22
20// xxh64 of string "kFinalizerRegKey" generated at https://www.pelock.com/products/hash-calculator 23// xxh64 of string "kFinalizerRegKey" generated at https://www.pelock.com/products/hash-calculator
21static constexpr RegistryUniqueKey kFinalizerRegKey{ 0xFE936BFAA718FEEAull }; 24static constexpr RegistryUniqueKey kFinalizerRegKey{ 0xFE936BFAA718FEEAull };
22 25
@@ -45,13 +48,17 @@ class Lane
45 public: 48 public:
46 /* 49 /*
47 Pending: The Lua VM hasn't done anything yet. 50 Pending: The Lua VM hasn't done anything yet.
48 Running, Waiting: Thread is inside the Lua VM. If the thread is forcefully stopped, we can't lua_close() the Lua State. 51 Resuming: The user requested the lane to resume execution from Suspended state.
52 Suspended: returned from lua_resume, waiting for the client to request a lua_resume.
53 Running, Suspended, Waiting: Thread is inside the Lua VM.
49 Done, Error, Cancelled: Thread execution is outside the Lua VM. It can be lua_close()d. 54 Done, Error, Cancelled: Thread execution is outside the Lua VM. It can be lua_close()d.
50 */ 55 */
51 enum class Status 56 enum class Status
52 { 57 {
53 Pending, 58 Pending,
54 Running, 59 Running,
60 Suspended,
61 Resuming,
55 Waiting, 62 Waiting,
56 Done, 63 Done,
57 Error, 64 Error,
@@ -84,8 +91,9 @@ class Lane
84 91
85 std::string_view debugName{ "<unnamed>" }; 92 std::string_view debugName{ "<unnamed>" };
86 93
87 Universe* const U; 94 Universe* const U{};
88 lua_State* L; 95 lua_State* S{}; // the master state of the lane
96 lua_State* L{}; // the state we run things in (either S or a lua_newthread() state if we run in coroutine mode)
89 // 97 //
90 // M: prepares the state, and reads results 98 // M: prepares the state, and reads results
91 // S: while S is running, M must keep out of modifying the state 99 // S: while S is running, M must keep out of modifying the state
@@ -93,7 +101,7 @@ class Lane
93 Status volatile status{ Pending }; 101 Status volatile status{ Pending };
94 // 102 //
95 // M: sets to Pending (before launching) 103 // M: sets to Pending (before launching)
96 // S: updates -> Running/Waiting -> Done/Error/Cancelled 104 // S: updates -> Running/Waiting/Suspended -> Done/Error/Cancelled
97 105
98 std::condition_variable* volatile waiting_on{ nullptr }; 106 std::condition_variable* volatile waiting_on{ nullptr };
99 // 107 //
@@ -121,7 +129,7 @@ class Lane
121 // this one is for us, to make sure memory is freed by the correct allocator 129 // this one is for us, to make sure memory is freed by the correct allocator
122 static void operator delete(void* p_) { static_cast<Lane*>(p_)->U->internalAllocator.free(p_, sizeof(Lane)); } 130 static void operator delete(void* p_) { static_cast<Lane*>(p_)->U->internalAllocator.free(p_, sizeof(Lane)); }
123 131
124 Lane(Universe* U_, lua_State* L_, ErrorTraceLevel errorTraceLevel_); 132 Lane(Universe* U_, lua_State* L_, ErrorTraceLevel errorTraceLevel_, bool asCoroutine_);
125 ~Lane(); 133 ~Lane();
126 134
127 private: 135 private:
@@ -133,7 +141,13 @@ class Lane
133 141
134 CancelResult cancel(CancelOp op_, int hookCount_, std::chrono::time_point<std::chrono::steady_clock> until_, bool wakeLane_); 142 CancelResult cancel(CancelOp op_, int hookCount_, std::chrono::time_point<std::chrono::steady_clock> until_, bool wakeLane_);
135 void changeDebugName(int const nameIdx_); 143 void changeDebugName(int const nameIdx_);
136 void closeState() { lua_State* _L{ L }; L = nullptr; lua_close(_L); } 144 void closeState()
145 {
146 lua_State* _L{ S };
147 S = nullptr;
148 L = nullptr;
149 lua_close(_L); // this collects our coroutine thread at the same time
150 }
137 [[nodiscard]] std::string_view errorTraceLevelString() const; 151 [[nodiscard]] std::string_view errorTraceLevelString() const;
138 [[nodiscard]] int pushErrorHandler() const; 152 [[nodiscard]] int pushErrorHandler() const;
139 [[nodiscard]] std::string_view pushErrorTraceLevel(lua_State* L_) const; 153 [[nodiscard]] std::string_view pushErrorTraceLevel(lua_State* L_) const;
diff --git a/src/lanes.cpp b/src/lanes.cpp
index 473e150..c11dd6a 100644
--- a/src/lanes.cpp
+++ b/src/lanes.cpp
@@ -268,11 +268,16 @@ LUAG_FUNC(lane_new)
268 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: setup" << std::endl); 268 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: setup" << std::endl);
269 269
270 std::optional<std::string_view> _libs_str{ lua_isnil(L_, kLibsIdx) ? std::nullopt : std::make_optional(luaG_tostring(L_, kLibsIdx)) }; 270 std::optional<std::string_view> _libs_str{ lua_isnil(L_, kLibsIdx) ? std::nullopt : std::make_optional(luaG_tostring(L_, kLibsIdx)) };
271 lua_State* const _L2{ state::NewLaneState(_U, SourceState{ L_ }, _libs_str) }; // L_: [fixed] ... L2: 271 lua_State* const _S{ state::NewLaneState(_U, SourceState{ L_ }, _libs_str) }; // L_: [fixed] ... L2:
272 STACK_CHECK_START_REL(_L2, 0); 272 STACK_CHECK_START_REL(_S, 0);
273 273
274 // 'lane' is allocated from heap, not Lua, since its life span may surpass the handle's (if free running thread) 274 // 'lane' is allocated from heap, not Lua, since its life span may surpass the handle's (if free running thread)
275 Lane* const _lane{ new (_U) Lane{ _U, _L2, static_cast<Lane::ErrorTraceLevel>(lua_tointeger(L_, kErTlIdx)) } }; 275 Lane::ErrorTraceLevel const _errorTraceLevel{ static_cast<Lane::ErrorTraceLevel>(lua_tointeger(L_, kErTlIdx)) };
276 bool const _asCoroutine{ lua_toboolean(L_, kAsCoro) ? true : false };
277 Lane* const _lane{ new (_U) Lane{ _U, _S, _errorTraceLevel, _asCoroutine } };
278 STACK_CHECK(_S, _asCoroutine ? 1 : 0); // the Lane's thread is on the Lane's state stack
279 lua_State* const _L2{ _lane->L };
280 STACK_CHECK_START_REL(_L2, 0);
276 if (_lane == nullptr) { 281 if (_lane == nullptr) {
277 raise_luaL_error(L_, "could not create lane: out of memory"); 282 raise_luaL_error(L_, "could not create lane: out of memory");
278 } 283 }
@@ -347,7 +352,7 @@ LUAG_FUNC(lane_new)
347 352
348 lua_setiuservalue(L, -2, 1); // L: ... lane 353 lua_setiuservalue(L, -2, 1); // L: ... lane
349 354
350 lua_State* _L2{ lane->L }; 355 lua_State* const _L2{ lane->L };
351 STACK_CHECK_START_REL(_L2, 0); 356 STACK_CHECK_START_REL(_L2, 0);
352 int const _name_idx{ lua_isnoneornil(L, kNameIdx) ? 0 : kNameIdx }; 357 int const _name_idx{ lua_isnoneornil(L, kNameIdx) ? 0 : kNameIdx };
353 std::string_view const _debugName{ (_name_idx > 0) ? luaG_tostring(L, _name_idx) : std::string_view{} }; 358 std::string_view const _debugName{ (_name_idx > 0) ? luaG_tostring(L, _name_idx) : std::string_view{} };
@@ -357,7 +362,7 @@ LUAG_FUNC(lane_new)
357 luaG_pushstring(_L2, _debugName); // L: ... lane L2: "<name>" 362 luaG_pushstring(_L2, _debugName); // L: ... lane L2: "<name>"
358 } else { 363 } else {
359 lua_Debug _ar; 364 lua_Debug _ar;
360 lua_pushvalue(L, 1); // L: ... lane func 365 lua_pushvalue(L, kFuncIdx); // L: ... lane func
361 lua_getinfo(L, ">S", &_ar); // L: ... lane 366 lua_getinfo(L, ">S", &_ar); // L: ... lane
362 luaG_pushstring(_L2, "%s:%d", _ar.short_src, _ar.linedefined); // L: ... lane L2: "<name>" 367 luaG_pushstring(_L2, "%s:%d", _ar.short_src, _ar.linedefined); // L: ... lane L2: "<name>"
363 } 368 }
@@ -415,6 +420,8 @@ LUAG_FUNC(lane_new)
415 [[maybe_unused]] InterCopyResult const _ret{ _c.interCopyPackage() }; 420 [[maybe_unused]] InterCopyResult const _ret{ _c.interCopyPackage() };
416 LUA_ASSERT(L_, _ret == InterCopyResult::Success); // either all went well, or we should not even get here 421 LUA_ASSERT(L_, _ret == InterCopyResult::Success); // either all went well, or we should not even get here
417 } 422 }
423 STACK_CHECK(L_, 0);
424 STACK_CHECK(_L2, 0);
418 425
419 // modules to require in the target lane *before* the function is transfered! 426 // modules to require in the target lane *before* the function is transfered!
420 int const _required_idx{ lua_isnoneornil(L_, kRequIdx) ? 0 : kRequIdx }; 427 int const _required_idx{ lua_isnoneornil(L_, kRequIdx) ? 0 : kRequIdx };
@@ -526,6 +533,7 @@ LUAG_FUNC(lane_new)
526 } 533 }
527 STACK_CHECK(L_, -_nargs); 534 STACK_CHECK(L_, -_nargs);
528 LUA_ASSERT(L_, lua_gettop(L_) == kFixedArgsIdx); 535 LUA_ASSERT(L_, lua_gettop(L_) == kFixedArgsIdx);
536 STACK_CHECK(_L2, _errorHandlerCount + 1 + _nargs);
529 537
530 // Store 'lane' in the lane's registry, for 'cancel_test()' (we do cancel tests at pending send/receive). 538 // Store 'lane' in the lane's registry, for 'cancel_test()' (we do cancel tests at pending send/receive).
531 kLanePointerRegKey.setValue( 539 kLanePointerRegKey.setValue(
@@ -533,6 +541,14 @@ LUAG_FUNC(lane_new)
533 ); 541 );
534 STACK_CHECK(_L2, _errorHandlerCount + 1 + _nargs); 542 STACK_CHECK(_L2, _errorHandlerCount + 1 + _nargs);
535 543
544 // if in coroutine mode, the Lane's master state stack should contain the thread
545 if (_asCoroutine) {
546 LUA_ASSERT(L_, _S != _L2);
547 STACK_CHECK(_S, 1);
548 }
549 // and the thread's stack has whatever is needed to run
550 STACK_CHECK(_L2, _errorHandlerCount + 1 + _nargs);
551
536 STACK_CHECK_RESET_REL(L_, 0); 552 STACK_CHECK_RESET_REL(L_, 0);
537 // all went well, the lane's thread can start working 553 // all went well, the lane's thread can start working
538 _onExit.success(); // L_: [fixed] lane L2: <living its own life> 554 _onExit.success(); // L_: [fixed] lane L2: <living its own life>
@@ -541,7 +557,7 @@ LUAG_FUNC(lane_new)
541 return 1; 557 return 1;
542} 558}
543 559
544// ################################################################################################ 560// #################################################################################################
545 561
546// threads() -> {}|nil 562// threads() -> {}|nil
547// Return a list of all known lanes 563// Return a list of all known lanes