[K/N] Eliminate deadlock on finalizer thread initialization

Merge-request: KT-MR-11388
Merged-by: Alexey Glushko <aleksei.glushko@jetbrains.com>
This commit is contained in:
Aleksei.Glushko
2023-07-31 21:38:05 +00:00
committed by Space Team
parent 748eb2f9ee
commit 71b2a22e35
@@ -72,6 +72,7 @@ public:
if (finalizerThread_.joinable()) return; if (finalizerThread_.joinable()) return;
finalizerThread_ = ScopedThread(ScopedThread::attributes().name("GC finalizer processor"), [this] { finalizerThread_ = ScopedThread(ScopedThread::attributes().name("GC finalizer processor"), [this] {
processingLoop_.initThreadData();
Kotlin_initRuntimeIfNeeded(); Kotlin_initRuntimeIfNeeded();
{ {
std::unique_lock guard(initializedMutex_); std::unique_lock guard(initializedMutex_);
@@ -94,12 +95,8 @@ public:
private: private:
// should be called under the finalizerQueueMutex_ // should be called under the finalizerQueueMutex_
bool shouldShutdown(int64_t lastProcessedEpoch) noexcept { bool hasNewTasks(int64_t lastProcessedEpoch) noexcept { // FIXME name
bool shouldShutdown = FinalizerQueueTraits::isEmpty(finalizerQueue_) && finalizerQueueEpoch_ == lastProcessedEpoch; return !FinalizerQueueTraits::isEmpty(finalizerQueue_) || finalizerQueueEpoch_ != lastProcessedEpoch;
if (shouldShutdown) {
RuntimeAssert(shutdownFlag_, "Nothing to do, but no shutdownFlag_ is set on wakeup");
}
return shouldShutdown;
} }
void processSingle(FinalizerQueue&& queue, int64_t currentEpoch) noexcept { void processSingle(FinalizerQueue&& queue, int64_t currentEpoch) noexcept {
@@ -140,22 +137,24 @@ private:
CFRunLoopWakeUp(runLoop_); CFRunLoopWakeUp(runLoop_);
} }
void initThreadData() {
runLoop_.store(CFRunLoopGetCurrent(), std::memory_order_release);
}
void body() { void body() {
konan::AutoreleasePool autoreleasePool; konan::AutoreleasePool autoreleasePool;
auto mode = kCFRunLoopDefaultMode; auto mode = kCFRunLoopDefaultMode;
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource_, mode); CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource_, mode);
runLoop_.store(CFRunLoopGetCurrent(), std::memory_order_release);
CFRunLoopRun(); CFRunLoopRun();
runLoop_.store(nullptr, std::memory_order_release);
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runLoopSource_, mode); CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runLoopSource_, mode);
runLoop_.store(nullptr, std::memory_order_release);
} }
private: private:
void handleNewFinalizers() { void handleNewFinalizers() {
std::unique_lock lock(owner_.finalizerQueueMutex_); std::unique_lock lock(owner_.finalizerQueueMutex_);
if (owner_.shouldShutdown(finishedEpoch_)) { if (owner_.shutdownFlag_) {
owner_.newTasksAllowed_ = false; owner_.newTasksAllowed_ = false;
CFRunLoopStop(runLoop_.load(std::memory_order_acquire)); CFRunLoopStop(runLoop_.load(std::memory_order_acquire));
return; return;
@@ -183,14 +182,17 @@ private:
owner_.finalizerQueueCondVar_.notify_all(); owner_.finalizerQueueCondVar_.notify_all();
} }
void initThreadData() { /* noop */ }
void body() { void body() {
int64_t finishedEpoch = 0; int64_t finishedEpoch = 0;
while (true) { while (true) {
std::unique_lock lock(owner_.finalizerQueueMutex_); std::unique_lock lock(owner_.finalizerQueueMutex_);
owner_.finalizerQueueCondVar_.wait(lock, [this, &finishedEpoch] { owner_.finalizerQueueCondVar_.wait(lock, [this, &finishedEpoch] {
return !FinalizerQueueTraits::isEmpty(owner_.finalizerQueue_) || owner_.finalizerQueueEpoch_ != finishedEpoch || owner_.shutdownFlag_; return owner_.hasNewTasks(finishedEpoch) || owner_.shutdownFlag_;
}); });
if (owner_.shouldShutdown(finishedEpoch)) { if (!owner_.hasNewTasks(finishedEpoch)) {
RuntimeAssert(owner_.shutdownFlag_, "Nothing to do, but no shutdownFlag_ is set on wakeup");
owner_.newTasksAllowed_ = false; owner_.newTasksAllowed_ = false;
break; break;
} }