diff options
-rw-r--r-- | src/keeper.cpp | 8 | ||||
-rw-r--r-- | src/keeper.h | 2 | ||||
-rw-r--r-- | src/linda.cpp | 82 | ||||
-rw-r--r-- | src/lindafactory.cpp | 13 |
4 files changed, 53 insertions, 52 deletions
diff --git a/src/keeper.cpp b/src/keeper.cpp index 3e806f9..b8f2bd0 100644 --- a/src/keeper.cpp +++ b/src/keeper.cpp | |||
@@ -276,7 +276,7 @@ static void PushKeysDB(KeeperState const K_, int const idx_) | |||
276 | int keeper_push_linda_storage(Linda& linda_, DestState L_) | 276 | int keeper_push_linda_storage(Linda& linda_, DestState L_) |
277 | { | 277 | { |
278 | Keeper* const _keeper{ linda_.whichKeeper() }; | 278 | Keeper* const _keeper{ linda_.whichKeeper() }; |
279 | KeeperState const _K{ _keeper ? _keeper->L : nullptr }; | 279 | KeeperState const _K{ _keeper ? _keeper->K : nullptr }; |
280 | if (_K == nullptr) { | 280 | if (_K == nullptr) { |
281 | return 0; | 281 | return 0; |
282 | } | 282 | } |
@@ -710,7 +710,7 @@ void Keeper::operator delete[](void* p_, Universe* U_) | |||
710 | // ################################################################################################# | 710 | // ################################################################################################# |
711 | // ################################################################################################# | 711 | // ################################################################################################# |
712 | 712 | ||
713 | void Keepers::DeleteKV::operator()(Keeper* k_) const | 713 | void Keepers::DeleteKV::operator()(Keeper* const k_) const |
714 | { | 714 | { |
715 | for (Keeper& _k : std::views::counted(k_, count)) { | 715 | for (Keeper& _k : std::views::counted(k_, count)) { |
716 | _k.~Keeper(); | 716 | _k.~Keeper(); |
@@ -733,7 +733,7 @@ void Keepers::close() | |||
733 | } | 733 | } |
734 | 734 | ||
735 | auto _closeOneKeeper = [](Keeper& keeper_) { | 735 | auto _closeOneKeeper = [](Keeper& keeper_) { |
736 | lua_State* const _K{ std::exchange(keeper_.L, KeeperState{ nullptr }) }; | 736 | lua_State* const _K{ std::exchange(keeper_.K, KeeperState{ nullptr }) }; |
737 | if (_K) { | 737 | if (_K) { |
738 | lua_close(_K); | 738 | lua_close(_K); |
739 | } | 739 | } |
@@ -824,7 +824,7 @@ void Keepers::initialize(Universe& U_, lua_State* L_, int const nbKeepers_, int | |||
824 | raise_luaL_error(L, "out of memory while creating keeper states"); | 824 | raise_luaL_error(L, "out of memory while creating keeper states"); |
825 | } | 825 | } |
826 | 826 | ||
827 | keeper_.L = _K; | 827 | keeper_.K = _K; |
828 | 828 | ||
829 | // Give a name to the state | 829 | // Give a name to the state |
830 | std::ignore = luaG_pushstringview(_K, "Keeper #%d", i_ + 1); // L_: settings _K: "Keeper #n" | 830 | std::ignore = luaG_pushstringview(_K, "Keeper #%d", i_ + 1); // L_: settings _K: "Keeper #n" |
diff --git a/src/keeper.h b/src/keeper.h index 1425a3b..5cc7422 100644 --- a/src/keeper.h +++ b/src/keeper.h | |||
@@ -28,7 +28,7 @@ using KeeperState = Unique<lua_State*>; | |||
28 | struct Keeper | 28 | struct Keeper |
29 | { | 29 | { |
30 | std::mutex mutex; | 30 | std::mutex mutex; |
31 | KeeperState L{ nullptr }; | 31 | KeeperState K{ nullptr }; |
32 | 32 | ||
33 | [[nodiscard]] static void* operator new[](size_t size_, Universe* U_) noexcept; | 33 | [[nodiscard]] static void* operator new[](size_t size_, Universe* U_) noexcept; |
34 | // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception | 34 | // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception |
diff --git a/src/linda.cpp b/src/linda.cpp index 3449f89..a7d7ee9 100644 --- a/src/linda.cpp +++ b/src/linda.cpp | |||
@@ -136,11 +136,11 @@ Linda::~Linda() | |||
136 | Keeper* Linda::acquireKeeper() const | 136 | Keeper* Linda::acquireKeeper() const |
137 | { | 137 | { |
138 | // can be nullptr if this happens during main state shutdown (lanes is being GC'ed -> no keepers) | 138 | // can be nullptr if this happens during main state shutdown (lanes is being GC'ed -> no keepers) |
139 | Keeper* const _K{ whichKeeper() }; | 139 | Keeper* const _keeper{ whichKeeper() }; |
140 | if (_K) { | 140 | if (_keeper) { |
141 | _K->mutex.lock(); | 141 | _keeper->mutex.lock(); |
142 | } | 142 | } |
143 | return _K; | 143 | return _keeper; |
144 | } | 144 | } |
145 | 145 | ||
146 | // ################################################################################################# | 146 | // ################################################################################################# |
@@ -177,14 +177,14 @@ int Linda::ProtectedCall(lua_State* L_, lua_CFunction f_) | |||
177 | Linda* const _linda{ ToLinda<false>(L_, 1) }; | 177 | Linda* const _linda{ ToLinda<false>(L_, 1) }; |
178 | 178 | ||
179 | // acquire the keeper | 179 | // acquire the keeper |
180 | Keeper* const _K{ _linda->acquireKeeper() }; | 180 | Keeper* const _keeper{ _linda->acquireKeeper() }; |
181 | lua_State* const _KL{ _K ? _K->L : nullptr }; | 181 | KeeperState const _K{ _keeper ? _keeper->K : nullptr }; |
182 | if (_KL == nullptr) | 182 | if (_K == nullptr) |
183 | return 0; | 183 | return 0; |
184 | 184 | ||
185 | LUA_ASSERT_CODE(auto const _koip{ _linda->startKeeperOperation(L_) }); | 185 | LUA_ASSERT_CODE(auto const _koip{ _linda->startKeeperOperation(L_) }); |
186 | // if we didn't do anything wrong, the keeper stack should be clean | 186 | // if we didn't do anything wrong, the keeper stack should be clean |
187 | LUA_ASSERT(L_, lua_gettop(_KL) == 0); | 187 | LUA_ASSERT(L_, lua_gettop(_K) == 0); |
188 | 188 | ||
189 | // push the function to be called and move it before the arguments | 189 | // push the function to be called and move it before the arguments |
190 | lua_pushcfunction(L_, f_); | 190 | lua_pushcfunction(L_, f_); |
@@ -192,10 +192,10 @@ int Linda::ProtectedCall(lua_State* L_, lua_CFunction f_) | |||
192 | // do a protected call | 192 | // do a protected call |
193 | LuaError const _rc{ lua_pcall(L_, lua_gettop(L_) - 1, LUA_MULTRET, 0) }; | 193 | LuaError const _rc{ lua_pcall(L_, lua_gettop(L_) - 1, LUA_MULTRET, 0) }; |
194 | // whatever happens, the keeper state stack must be empty when we are done | 194 | // whatever happens, the keeper state stack must be empty when we are done |
195 | lua_settop(_KL, 0); | 195 | lua_settop(_K, 0); |
196 | 196 | ||
197 | // release the keeper | 197 | // release the keeper |
198 | _linda->releaseKeeper(_K); | 198 | _linda->releaseKeeper(_keeper); |
199 | 199 | ||
200 | // if there was an error, forward it | 200 | // if there was an error, forward it |
201 | if (_rc != LuaError::OK) { | 201 | if (_rc != LuaError::OK) { |
@@ -207,11 +207,11 @@ int Linda::ProtectedCall(lua_State* L_, lua_CFunction f_) | |||
207 | 207 | ||
208 | // ################################################################################################# | 208 | // ################################################################################################# |
209 | 209 | ||
210 | void Linda::releaseKeeper(Keeper* const K_) const | 210 | void Linda::releaseKeeper(Keeper* const keeper_) const |
211 | { | 211 | { |
212 | if (K_) { // can be nullptr if we tried to acquire during shutdown | 212 | if (keeper_) { // can be nullptr if we tried to acquire during shutdown |
213 | assert(K_ == whichKeeper()); | 213 | assert(keeper_ == whichKeeper()); |
214 | K_->mutex.unlock(); | 214 | keeper_->mutex.unlock(); |
215 | } | 215 | } |
216 | } | 216 | } |
217 | 217 | ||
@@ -316,8 +316,8 @@ LUAG_FUNC(linda_count) | |||
316 | // make sure the keys are of a valid type | 316 | // make sure the keys are of a valid type |
317 | check_key_types(L_, 2, lua_gettop(L_)); | 317 | check_key_types(L_, 2, lua_gettop(L_)); |
318 | 318 | ||
319 | Keeper* const _K{ _linda->whichKeeper() }; | 319 | Keeper* const _keeper{ _linda->whichKeeper() }; |
320 | KeeperCallResult const _pushed{ keeper_call(_K->L, KEEPER_API(count), L_, _linda, 2) }; | 320 | KeeperCallResult const _pushed{ keeper_call(_keeper->K, KEEPER_API(count), L_, _linda, 2) }; |
321 | return OptionalValue(_pushed, L_, "tried to count an invalid key"); | 321 | return OptionalValue(_pushed, L_, "tried to count an invalid key"); |
322 | }; | 322 | }; |
323 | return Linda::ProtectedCall(L_, _count); | 323 | return Linda::ProtectedCall(L_, _count); |
@@ -376,8 +376,8 @@ LUAG_FUNC(linda_get) | |||
376 | 376 | ||
377 | KeeperCallResult _pushed; | 377 | KeeperCallResult _pushed; |
378 | if (_linda->cancelRequest == CancelRequest::None) { | 378 | if (_linda->cancelRequest == CancelRequest::None) { |
379 | Keeper* const _K{ _linda->whichKeeper() }; | 379 | Keeper* const _keeper{ _linda->whichKeeper() }; |
380 | _pushed = keeper_call(_K->L, KEEPER_API(get), L_, _linda, 2); | 380 | _pushed = keeper_call(_keeper->K, KEEPER_API(get), L_, _linda, 2); |
381 | } else { // linda is cancelled | 381 | } else { // linda is cancelled |
382 | // do nothing and return lanes.cancel_error | 382 | // do nothing and return lanes.cancel_error |
383 | kCancelError.pushKey(L_); | 383 | kCancelError.pushKey(L_); |
@@ -415,8 +415,8 @@ LUAG_FUNC(linda_limit) | |||
415 | 415 | ||
416 | KeeperCallResult _pushed; | 416 | KeeperCallResult _pushed; |
417 | if (_linda->cancelRequest == CancelRequest::None) { | 417 | if (_linda->cancelRequest == CancelRequest::None) { |
418 | Keeper* const _K{ _linda->whichKeeper() }; | 418 | Keeper* const _keeper{ _linda->whichKeeper() }; |
419 | _pushed = keeper_call(_K->L, KEEPER_API(limit), L_, _linda, 2); | 419 | _pushed = keeper_call(_keeper->K, KEEPER_API(limit), L_, _linda, 2); |
420 | LUA_ASSERT(L_, _pushed.has_value() && (_pushed.value() == 0 || _pushed.value() == 1)); // no error, optional boolean value saying if we should wake blocked writer threads | 420 | LUA_ASSERT(L_, _pushed.has_value() && (_pushed.value() == 0 || _pushed.value() == 1)); // no error, optional boolean value saying if we should wake blocked writer threads |
421 | if (_pushed.value() == 1) { | 421 | if (_pushed.value() == 1) { |
422 | LUA_ASSERT(L_, luaG_type(L_, -1) == LuaType::BOOLEAN && lua_toboolean(L_, -1) == 1); | 422 | LUA_ASSERT(L_, luaG_type(L_, -1) == LuaType::BOOLEAN && lua_toboolean(L_, -1) == 1); |
@@ -497,14 +497,14 @@ LUAG_FUNC(linda_receive) | |||
497 | } | 497 | } |
498 | 498 | ||
499 | Lane* const _lane{ kLanePointerRegKey.readLightUserDataValue<Lane>(L_) }; | 499 | Lane* const _lane{ kLanePointerRegKey.readLightUserDataValue<Lane>(L_) }; |
500 | Keeper* const _K{ _linda->whichKeeper() }; | 500 | Keeper* const _keeper{ _linda->whichKeeper() }; |
501 | KeeperState const _KL{ _K ? _K->L : nullptr }; | 501 | KeeperState const _K{ _keeper ? _keeper->K : nullptr }; |
502 | if (_KL == nullptr) | 502 | if (_K == nullptr) |
503 | return 0; | 503 | return 0; |
504 | 504 | ||
505 | CancelRequest _cancel{ CancelRequest::None }; | 505 | CancelRequest _cancel{ CancelRequest::None }; |
506 | KeeperCallResult _pushed{}; | 506 | KeeperCallResult _pushed{}; |
507 | STACK_CHECK_START_REL(_KL, 0); | 507 | STACK_CHECK_START_REL(_K, 0); |
508 | for (bool _try_again{ true };;) { | 508 | for (bool _try_again{ true };;) { |
509 | if (_lane != nullptr) { | 509 | if (_lane != nullptr) { |
510 | _cancel = _lane->cancelRequest; | 510 | _cancel = _lane->cancelRequest; |
@@ -517,7 +517,7 @@ LUAG_FUNC(linda_receive) | |||
517 | } | 517 | } |
518 | 518 | ||
519 | // all arguments of receive() but the first are passed to the keeper's receive function | 519 | // all arguments of receive() but the first are passed to the keeper's receive function |
520 | _pushed = keeper_call(_KL, _selected_keeper_receive, L_, _linda, _key_i); | 520 | _pushed = keeper_call(_K, _selected_keeper_receive, L_, _linda, _key_i); |
521 | if (!_pushed.has_value()) { | 521 | if (!_pushed.has_value()) { |
522 | break; | 522 | break; |
523 | } | 523 | } |
@@ -543,9 +543,9 @@ LUAG_FUNC(linda_receive) | |||
543 | _lane->waiting_on = &_linda->writeHappened; | 543 | _lane->waiting_on = &_linda->writeHappened; |
544 | } | 544 | } |
545 | // not enough data to read: wakeup when data was sent, or when timeout is reached | 545 | // not enough data to read: wakeup when data was sent, or when timeout is reached |
546 | std::unique_lock<std::mutex> _keeper_lock{ _K->mutex, std::adopt_lock }; | 546 | std::unique_lock<std::mutex> _guard{ _keeper->mutex, std::adopt_lock }; |
547 | std::cv_status const _status{ _linda->writeHappened.wait_until(_keeper_lock, _until) }; | 547 | std::cv_status const _status{ _linda->writeHappened.wait_until(_guard, _until) }; |
548 | _keeper_lock.release(); // we don't want to release the lock! | 548 | _guard.release(); // we don't want to unlock the mutex on exit! |
549 | _try_again = (_status == std::cv_status::no_timeout); // detect spurious wakeups | 549 | _try_again = (_status == std::cv_status::no_timeout); // detect spurious wakeups |
550 | if (_lane != nullptr) { | 550 | if (_lane != nullptr) { |
551 | _lane->waiting_on = nullptr; | 551 | _lane->waiting_on = nullptr; |
@@ -553,7 +553,7 @@ LUAG_FUNC(linda_receive) | |||
553 | } | 553 | } |
554 | } | 554 | } |
555 | } | 555 | } |
556 | STACK_CHECK(_KL, 0); | 556 | STACK_CHECK(_K, 0); |
557 | 557 | ||
558 | if (!_pushed.has_value()) { | 558 | if (!_pushed.has_value()) { |
559 | raise_luaL_error(L_, "tried to copy unsupported types"); | 559 | raise_luaL_error(L_, "tried to copy unsupported types"); |
@@ -634,12 +634,12 @@ LUAG_FUNC(linda_send) | |||
634 | KeeperCallResult _pushed; | 634 | KeeperCallResult _pushed; |
635 | { | 635 | { |
636 | Lane* const _lane{ kLanePointerRegKey.readLightUserDataValue<Lane>(L_) }; | 636 | Lane* const _lane{ kLanePointerRegKey.readLightUserDataValue<Lane>(L_) }; |
637 | Keeper* const _K{ _linda->whichKeeper() }; | 637 | Keeper* const _keeper{ _linda->whichKeeper() }; |
638 | KeeperState const _KL{ _K ? _K->L : nullptr }; | 638 | KeeperState const _K{ _keeper ? _keeper->K : nullptr }; |
639 | if (_KL == nullptr) | 639 | if (_K == nullptr) |
640 | return 0; | 640 | return 0; |
641 | 641 | ||
642 | STACK_CHECK_START_REL(_KL, 0); | 642 | STACK_CHECK_START_REL(_K, 0); |
643 | for (bool _try_again{ true };;) { | 643 | for (bool _try_again{ true };;) { |
644 | if (_lane != nullptr) { | 644 | if (_lane != nullptr) { |
645 | _cancel = _lane->cancelRequest; | 645 | _cancel = _lane->cancelRequest; |
@@ -651,8 +651,8 @@ LUAG_FUNC(linda_send) | |||
651 | break; | 651 | break; |
652 | } | 652 | } |
653 | 653 | ||
654 | STACK_CHECK(_KL, 0); | 654 | STACK_CHECK(_K, 0); |
655 | _pushed = keeper_call(_KL, KEEPER_API(send), L_, _linda, _key_i); | 655 | _pushed = keeper_call(_K, KEEPER_API(send), L_, _linda, _key_i); |
656 | if (!_pushed.has_value()) { | 656 | if (!_pushed.has_value()) { |
657 | break; | 657 | break; |
658 | } | 658 | } |
@@ -684,9 +684,9 @@ LUAG_FUNC(linda_send) | |||
684 | _lane->waiting_on = &_linda->readHappened; | 684 | _lane->waiting_on = &_linda->readHappened; |
685 | } | 685 | } |
686 | // could not send because no room: wait until some data was read before trying again, or until timeout is reached | 686 | // could not send because no room: wait until some data was read before trying again, or until timeout is reached |
687 | std::unique_lock<std::mutex> _keeper_lock{ _K->mutex, std::adopt_lock }; | 687 | std::unique_lock<std::mutex> _guard{ _keeper->mutex, std::adopt_lock }; |
688 | std::cv_status const status{ _linda->readHappened.wait_until(_keeper_lock, _until) }; | 688 | std::cv_status const status{ _linda->readHappened.wait_until(_guard, _until) }; |
689 | _keeper_lock.release(); // we don't want to release the lock! | 689 | _guard.release(); // we don't want to unlock the mutex on exit! |
690 | _try_again = (status == std::cv_status::no_timeout); // detect spurious wakeups | 690 | _try_again = (status == std::cv_status::no_timeout); // detect spurious wakeups |
691 | if (_lane != nullptr) { | 691 | if (_lane != nullptr) { |
692 | _lane->waiting_on = nullptr; | 692 | _lane->waiting_on = nullptr; |
@@ -694,7 +694,7 @@ LUAG_FUNC(linda_send) | |||
694 | } | 694 | } |
695 | } | 695 | } |
696 | } | 696 | } |
697 | STACK_CHECK(_KL, 0); | 697 | STACK_CHECK(_K, 0); |
698 | } | 698 | } |
699 | 699 | ||
700 | if (!_pushed.has_value()) { | 700 | if (!_pushed.has_value()) { |
@@ -736,10 +736,10 @@ LUAG_FUNC(linda_set) | |||
736 | // make sure the key is of a valid type (throws an error if not the case) | 736 | // make sure the key is of a valid type (throws an error if not the case) |
737 | check_key_types(L_, 2, 2); | 737 | check_key_types(L_, 2, 2); |
738 | 738 | ||
739 | Keeper* const _K{ _linda->whichKeeper() }; | 739 | Keeper* const _keeper{ _linda->whichKeeper() }; |
740 | KeeperCallResult _pushed; | 740 | KeeperCallResult _pushed; |
741 | if (_linda->cancelRequest == CancelRequest::None) { | 741 | if (_linda->cancelRequest == CancelRequest::None) { |
742 | _pushed = keeper_call(_K->L, KEEPER_API(set), L_, _linda, 2); | 742 | _pushed = keeper_call(_keeper->K, KEEPER_API(set), L_, _linda, 2); |
743 | if (_pushed.has_value()) { // no error? | 743 | if (_pushed.has_value()) { // no error? |
744 | LUA_ASSERT(L_, _pushed.value() == 0 || _pushed.value() == 1); | 744 | LUA_ASSERT(L_, _pushed.value() == 0 || _pushed.value() == 1); |
745 | 745 | ||
diff --git a/src/lindafactory.cpp b/src/lindafactory.cpp index 6a2b000..9a75b4f 100644 --- a/src/lindafactory.cpp +++ b/src/lindafactory.cpp | |||
@@ -70,19 +70,20 @@ void LindaFactory::deleteDeepObjectInternal(lua_State* L_, DeepPrelude* o_) cons | |||
70 | { | 70 | { |
71 | Linda* const _linda{ static_cast<Linda*>(o_) }; | 71 | Linda* const _linda{ static_cast<Linda*>(o_) }; |
72 | LUA_ASSERT(L_, _linda && !_linda->inKeeperOperation()); | 72 | LUA_ASSERT(L_, _linda && !_linda->inKeeperOperation()); |
73 | Keeper* const _myK{ _linda->whichKeeper() }; | 73 | Keeper* const _myKeeper{ _linda->whichKeeper() }; |
74 | // if collected after the universe, keepers are already destroyed, and there is nothing to clear | 74 | // if collected after the universe, keepers are already destroyed, and there is nothing to clear |
75 | if (_myK) { | 75 | if (_myKeeper) { |
76 | // if collected from my own keeper, we can't acquire/release it | 76 | // if collected from my own keeper, we can't acquire/release it |
77 | // because we are already inside a protected area, and trying to do so would deadlock! | 77 | // because we are already inside a protected area, and trying to do so would deadlock! |
78 | bool const _need_acquire_release{ _myK->L != L_ }; | 78 | bool const _need_acquire_release{ _myKeeper->K != L_ }; |
79 | // Clean associated structures in the keeper state. | 79 | // Clean associated structures in the keeper state. |
80 | Keeper* const _K{ _need_acquire_release ? _linda->acquireKeeper() : _myK }; | 80 | Keeper* const _keeper{ _need_acquire_release ? _linda->acquireKeeper() : _myKeeper }; |
81 | LUA_ASSERT(L_, _keeper == _myKeeper); // should always be the same | ||
81 | // hopefully this won't ever raise an error as we would jump to the closest pcall site while forgetting to release the keeper mutex... | 82 | // hopefully this won't ever raise an error as we would jump to the closest pcall site while forgetting to release the keeper mutex... |
82 | [[maybe_unused]] KeeperCallResult const result{ keeper_call(_K->L, KEEPER_API(destruct), L_, _linda, 0) }; | 83 | [[maybe_unused]] KeeperCallResult const result{ keeper_call(_keeper->K, KEEPER_API(destruct), L_, _linda, 0) }; |
83 | LUA_ASSERT(L_, result.has_value() && result.value() == 0); | 84 | LUA_ASSERT(L_, result.has_value() && result.value() == 0); |
84 | if (_need_acquire_release) { | 85 | if (_need_acquire_release) { |
85 | _linda->releaseKeeper(_K); | 86 | _linda->releaseKeeper(_keeper); |
86 | } | 87 | } |
87 | } | 88 | } |
88 | 89 | ||