aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lane.cpp65
-rw-r--r--src/lane.h2
-rw-r--r--src/lanes.cpp6
3 files changed, 57 insertions, 16 deletions
diff --git a/src/lane.cpp b/src/lane.cpp
index 8c4062c..d6c9960 100644
--- a/src/lane.cpp
+++ b/src/lane.cpp
@@ -88,11 +88,11 @@ static LUAG_FUNC(lane_threadname)
88 Lane* const _lane{ luaG_tolightuserdata<Lane>(L_, lua_upvalueindex(1)) }; 88 Lane* const _lane{ luaG_tolightuserdata<Lane>(L_, lua_upvalueindex(1)) };
89 LUA_ASSERT(L_, L_ == _lane->L); // this function is exported in a lane's state, therefore it is callable only from inside the Lane's state 89 LUA_ASSERT(L_, L_ == _lane->L); // this function is exported in a lane's state, therefore it is callable only from inside the Lane's state
90 if (lua_gettop(L_) == 1) { 90 if (lua_gettop(L_) == 1) {
91 lua_settop(L_, 1); 91 lua_settop(L_, 1);
92 STACK_CHECK_START_REL(L_, 0); 92 STACK_CHECK_START_REL(L_, 0);
93 _lane->changeDebugName(-1); 93 _lane->changeDebugName(-1);
94 STACK_CHECK(L_, 0); 94 STACK_CHECK(L_, 0);
95 return 0; 95 return 0;
96 } else if (lua_gettop(L_) == 0) { 96 } else if (lua_gettop(L_) == 0) {
97 luaG_pushstring(L_, _lane->getDebugName()); 97 luaG_pushstring(L_, _lane->getDebugName());
98 return 1; 98 return 1;
@@ -138,14 +138,15 @@ static LUAG_FUNC(thread_join)
138 } 138 }
139 139
140 STACK_CHECK_START_REL(L_, 0); // L_: lane 140 STACK_CHECK_START_REL(L_, 0); // L_: lane
141 // Thread is Done/Error/Cancelled; all ours now 141 // Thread is Suspended or Done/Error/Cancelled; the Lane thread isn't working with it, therefore we can.
142 142
143 int _ret{ 0 }; 143 int _ret{ 0 };
144 // debugName is a pointer to string possibly interned in the lane's state, that no longer exists when the state is closed 144 // debugName is a pointer to string possibly interned in the lane's state, that no longer exists when the state is closed
145 // so store it in the userdata uservalue at a key that can't possibly collide 145 // so store it in the userdata uservalue at a key that can't possibly collide
146 _lane->securizeDebugName(L_); 146 _lane->securizeDebugName(L_);
147 switch (_lane->status) { 147 switch (_lane->status) {
148 case Lane::Done: 148 case Lane::Suspended: // got yielded values
149 case Lane::Done: // got regular return values
149 { 150 {
150 bool const _calledFromLua{ lua_toboolean(L_, lua_upvalueindex(1)) ? false : true }; // this upvalue doesn't exist when called from Lua 151 bool const _calledFromLua{ lua_toboolean(L_, lua_upvalueindex(1)) ? false : true }; // this upvalue doesn't exist when called from Lua
151 int const _n{ lua_gettop(_L2) }; // whole L2 stack 152 int const _n{ lua_gettop(_L2) }; // whole L2 stack
@@ -189,7 +190,10 @@ static LUAG_FUNC(thread_join)
189 LUA_ASSERT(L_, false); 190 LUA_ASSERT(L_, false);
190 _ret = 0; 191 _ret = 0;
191 } 192 }
192 _lane->closeState(); 193 // if we are suspended, all we want to do is gather the current yielded values
194 if (_lane->status != Lane::Suspended) {
195 _lane->closeState();
196 }
193 STACK_CHECK(L_, _ret); 197 STACK_CHECK(L_, _ret);
194 return _ret; 198 return _ret;
195} 199}
@@ -220,9 +224,12 @@ LUAG_FUNC(thread_resume)
220 } 224 }
221 int const _nargs{ lua_gettop(L_) - 1 }; 225 int const _nargs{ lua_gettop(L_) - 1 };
222 int const _nresults{ lua_gettop(_L2) }; 226 int const _nresults{ lua_gettop(_L2) };
223 STACK_CHECK_START_ABS(L_, 1 + _nargs); // L_: self args... _L2: results... 227 STACK_CHECK_START_ABS(L_, 1 + _nargs); // L_: self args... _L2: results...
224 STACK_CHECK_START_ABS(_L2, _nresults); 228 STACK_CHECK_START_ABS(_L2, _nresults);
225 229
230 // clear any fetched returned values that we might have stored previously
231 _lane->resetResultsStorage(L_, 1);
232
226 // to retrieve the yielded value of the coroutine on our stack 233 // to retrieve the yielded value of the coroutine on our stack
227 InterCopyContext _cin{ _lane->U, DestState{ L_ }, SourceState{ _L2 }, {}, {}, {}, {}, {} }; 234 InterCopyContext _cin{ _lane->U, DestState{ L_ }, SourceState{ _L2 }, {}, {}, {}, {}, {} };
228 if (_cin.interMove(_nresults) != InterCopyResult::Success) { // L_: self args... results... _L2: 235 if (_cin.interMove(_nresults) != InterCopyResult::Success) { // L_: self args... results... _L2:
@@ -291,6 +298,7 @@ static int thread_index_number(lua_State* L_)
291 lua_concat(L_, 2); // L_: "Unexpected status: <status>" 298 lua_concat(L_, 2); // L_: "Unexpected status: <status>"
292 raise_lua_error(L_); 299 raise_lua_error(L_);
293 300
301 case Lane::Suspended: // got yielded values
294 case Lane::Done: // got regular return values 302 case Lane::Done: // got regular return values
295 { 303 {
296 int const _nvalues{ lua_gettop(L_) - 3 }; // L_: lane n {uv} ... 304 int const _nvalues{ lua_gettop(L_) - 3 }; // L_: lane n {uv} ...
@@ -980,7 +988,7 @@ CancelResult Lane::cancel(CancelOp const op_, int const hookCount_, std::chrono:
980 _waiting_on->notify_all(); 988 _waiting_on->notify_all();
981 } 989 }
982 } 990 }
983 991 // wait until the lane stops working with its state (either Suspended or Done+)
984 CancelResult result{ waitForCompletion(until_) ? CancelResult::Cancelled : CancelResult::Timeout }; 992 CancelResult result{ waitForCompletion(until_) ? CancelResult::Cancelled : CancelResult::Timeout };
985 return result; 993 return result;
986} 994}
@@ -998,6 +1006,7 @@ CancelResult Lane::cancel(CancelOp const op_, int const hookCount_, std::chrono:
998 } 1006 }
999 } 1007 }
1000 1008
1009 // wait until the lane stops working with its state (either Suspended or Done+)
1001 return waitForCompletion(until_) ? CancelResult::Cancelled : CancelResult::Timeout; 1010 return waitForCompletion(until_) ? CancelResult::Cancelled : CancelResult::Timeout;
1002} 1011}
1003 1012
@@ -1013,7 +1022,7 @@ void Lane::changeDebugName(int const nameIdx_)
1013 // keep a direct pointer on the string 1022 // keep a direct pointer on the string
1014 { 1023 {
1015 std::lock_guard<std::mutex> _guard{ debugNameMutex }; 1024 std::lock_guard<std::mutex> _guard{ debugNameMutex };
1016 debugName = luaG_tostring(L, _nameIdx); 1025 debugName = luaG_tostring(L, _nameIdx);
1017 } 1026 }
1018 if constexpr (HAVE_DECODA_SUPPORT()) { 1027 if constexpr (HAVE_DECODA_SUPPORT()) {
1019 // to see VM name in Decoda debugger Virtual Machine window 1028 // to see VM name in Decoda debugger Virtual Machine window
@@ -1120,6 +1129,34 @@ void Lane::pushStatusString(lua_State* L_) const
1120 1129
1121// ################################################################################################# 1130// #################################################################################################
1122 1131
1132// replace the current uservalue (a table holding the returned values of the lane body)
1133// by a new empty one, but transfer the gc_cb that is stored in there so that it is not lost
1134void Lane::resetResultsStorage(lua_State* const L_, int const self_idx_)
1135{
1136 STACK_GROW(L_, 4);
1137 STACK_CHECK_START_REL(L_, 0);
1138 int const _self_idx{ luaG_absindex(L_, self_idx_) };
1139 LUA_ASSERT(L_, ToLane(L_, _self_idx) == this); // L_: ... self ...
1140 // create the new table
1141 lua_newtable(L_); // L_: ... self ... {}
1142 // get the current table
1143 lua_getiuservalue(L_, _self_idx, 1); // L_: ... self ... {} {uv}
1144 LUA_ASSERT(L_, lua_istable(L_, -1));
1145 // read gc_cb from the current table
1146 kLaneGC.pushKey(L_); // L_: ... self ... {} {uv} kLaneGC
1147 kLaneGC.pushKey(L_); // L_: ... self ... {} {uv} kLaneGC kLaneGC
1148 lua_rawget(L_, -3); // L_: ... self ... {} {uv} kLaneGC gc_cb|nil
1149 // store it in the new table
1150 lua_rawset(L_, -4); // L_: ... self ... {} {uv}
1151 // we can forget the old table
1152 lua_pop(L_, 1); // L_: ... self ... {}
1153 // and store the new one
1154 lua_setiuservalue(L_, _self_idx, 1); // L_: ... self ...
1155 STACK_CHECK(L_, 0);
1156}
1157
1158// #################################################################################################
1159
1123// intern the debug name in the caller lua state so that the pointer remains valid after the lane's state is closed 1160// intern the debug name in the caller lua state so that the pointer remains valid after the lane's state is closed
1124void Lane::securizeDebugName(lua_State* L_) 1161void Lane::securizeDebugName(lua_State* L_)
1125{ 1162{
@@ -1132,7 +1169,7 @@ void Lane::securizeDebugName(lua_State* L_)
1132 lua_newtable(L_); // L_: lane ... {uv} {} 1169 lua_newtable(L_); // L_: lane ... {uv} {}
1133 { 1170 {
1134 std::lock_guard<std::mutex> _guard{ debugNameMutex }; 1171 std::lock_guard<std::mutex> _guard{ debugNameMutex };
1135 debugName = luaG_pushstring(L_, debugName); // L_: lane ... {uv} {} name 1172 debugName = luaG_pushstring(L_, debugName); // L_: lane ... {uv} {} name
1136 } 1173 }
1137 lua_rawset(L_, -3); // L_: lane ... {uv} 1174 lua_rawset(L_, -3); // L_: lane ... {uv}
1138 lua_pop(L_, 1); // L_: lane 1175 lua_pop(L_, 1); // L_: lane
@@ -1195,5 +1232,7 @@ bool Lane::waitForCompletion(std::chrono::time_point<std::chrono::steady_clock>
1195 std::unique_lock _guard{ doneMutex }; 1232 std::unique_lock _guard{ doneMutex };
1196 // std::stop_token token{ thread.get_stop_token() }; 1233 // std::stop_token token{ thread.get_stop_token() };
1197 // return doneCondVar.wait_until(lock, token, secs_, [this](){ return status >= Lane::Done; }); 1234 // return doneCondVar.wait_until(lock, token, secs_, [this](){ return status >= Lane::Done; });
1198 return doneCondVar.wait_until(_guard, until_, [this]() { return status >= Lane::Done; }); 1235
1236 // wait until the lane stops working with its state (either Suspended or Done+)
1237 return doneCondVar.wait_until(_guard, until_, [this]() { return status == Lane::Suspended || status >= Lane::Done; });
1199} 1238}
diff --git a/src/lane.h b/src/lane.h
index 964c3c0..6dccd3a 100644
--- a/src/lane.h
+++ b/src/lane.h
@@ -167,9 +167,11 @@ class Lane
167 [[nodiscard]] std::string_view pushErrorTraceLevel(lua_State* L_) const; 167 [[nodiscard]] std::string_view pushErrorTraceLevel(lua_State* L_) const;
168 static void PushMetatable(lua_State* L_); 168 static void PushMetatable(lua_State* L_);
169 void pushStatusString(lua_State* L_) const; 169 void pushStatusString(lua_State* L_) const;
170 void resetResultsStorage(lua_State* const L_, int gc_cb_idx_);
170 void securizeDebugName(lua_State* L_); 171 void securizeDebugName(lua_State* L_);
171 void startThread(int priority_); 172 void startThread(int priority_);
172 [[nodiscard]] std::string_view threadStatusString() const; 173 [[nodiscard]] std::string_view threadStatusString() const;
174 // wait until the lane stops working with its state (either Suspended or Done+)
173 [[nodiscard]] bool waitForCompletion(std::chrono::time_point<std::chrono::steady_clock> until_); 175 [[nodiscard]] bool waitForCompletion(std::chrono::time_point<std::chrono::steady_clock> until_);
174}; 176};
175 177
diff --git a/src/lanes.cpp b/src/lanes.cpp
index c11dd6a..f1b5884 100644
--- a/src/lanes.cpp
+++ b/src/lanes.cpp
@@ -333,12 +333,11 @@ LUAG_FUNC(lane_new)
333 *_ud = lane; // don't forget to store the pointer in the userdata! 333 *_ud = lane; // don't forget to store the pointer in the userdata!
334 334
335 // Set metatable for the userdata 335 // Set metatable for the userdata
336 //
337 lua_pushvalue(L, lua_upvalueindex(1)); // L: ... lane mt 336 lua_pushvalue(L, lua_upvalueindex(1)); // L: ... lane mt
338 lua_setmetatable(L, -2); // L: ... lane 337 lua_setmetatable(L, -2); // L: ... lane
339 STACK_CHECK(L, 1); 338 STACK_CHECK(L, 1);
340 339
341 // Create uservalue for the userdata 340 // Create uservalue for the userdata. There can be only one that must be a table, due to Lua 5.1 compatibility.
342 // (this is where lane body return values will be stored when the handle is indexed by a numeric key) 341 // (this is where lane body return values will be stored when the handle is indexed by a numeric key)
343 lua_newtable(L); // L: ... lane {uv} 342 lua_newtable(L); // L: ... lane {uv}
344 343
@@ -349,7 +348,8 @@ LUAG_FUNC(lane_new)
349 lua_pushvalue(L, _gc_cb_idx); // L: ... lane {uv} k gc_cb 348 lua_pushvalue(L, _gc_cb_idx); // L: ... lane {uv} k gc_cb
350 lua_rawset(L, -3); // L: ... lane {uv} 349 lua_rawset(L, -3); // L: ... lane {uv}
351 } 350 }
352 351 STACK_CHECK(L, 2);
352 // store the uservalue in the Lane full userdata
353 lua_setiuservalue(L, -2, 1); // L: ... lane 353 lua_setiuservalue(L, -2, 1); // L: ... lane
354 354
355 lua_State* const _L2{ lane->L }; 355 lua_State* const _L2{ lane->L };