From acced31bb2f8fb948f25025cae1394ae695ad2bc Mon Sep 17 00:00:00 2001 From: Ilya Matveev Date: Tue, 25 Jan 2022 12:49:04 +0700 Subject: [PATCH] [K/N] Fix CMS GC hanging on Windows Issue #KT-50948 Fixed --- .../runtime/src/gc/cms/cpp/GCState.hpp | 79 +++++++++++++------ 1 file changed, 53 insertions(+), 26 deletions(-) diff --git a/kotlin-native/runtime/src/gc/cms/cpp/GCState.hpp b/kotlin-native/runtime/src/gc/cms/cpp/GCState.hpp index bef136484c4..d061d656916 100644 --- a/kotlin-native/runtime/src/gc/cms/cpp/GCState.hpp +++ b/kotlin-native/runtime/src/gc/cms/cpp/GCState.hpp @@ -14,60 +14,87 @@ class GCStateHolder { public: int64_t schedule() { std::unique_lock lock(mutex_); - if (scheduledEpoch <= startedEpoch) { - scheduledEpoch = startedEpoch + 1; - cond_.notify_all(); + if (*scheduledEpoch <= *startedEpoch) { + scheduledEpoch.set(lock, *startedEpoch + 1); } - return scheduledEpoch; + return *scheduledEpoch; } void shutdown() { std::unique_lock lock(mutex_); shutdownFlag_ = true; - cond_.notify_all(); + startedEpoch.notify(); + finishedEpoch.notify(); + scheduledEpoch.notify(); + finalizedEpoch.notify(); } void start(int64_t epoch) { - std::unique_lock lock(mutex_); - startedEpoch = epoch; - cond_.notify_all(); + startedEpoch.set(epoch); } void finish(int64_t epoch) { - std::unique_lock lock(mutex_); - finishedEpoch = epoch; - cond_.notify_all(); + finishedEpoch.set(epoch); } void finalized(int64_t epoch) { - std::unique_lock lock(mutex_); - finalizedEpoch = epoch; - cond_.notify_all(); + finalizedEpoch.set(epoch); } void waitEpochFinished(int64_t epoch) { - std::unique_lock lock(mutex_); - cond_.wait(lock, [this, epoch] { return finishedEpoch >= epoch || shutdownFlag_; }); + finishedEpoch.wait([this, epoch] { return *finishedEpoch >= epoch || shutdownFlag_; }); } void waitEpochFinalized(int64_t epoch) { - std::unique_lock lock(mutex_); - cond_.wait(lock, [this, epoch] { return finalizedEpoch >= epoch || shutdownFlag_; }); + finalizedEpoch.wait([this, epoch] { return *finalizedEpoch >= epoch || shutdownFlag_; }); } std::optional waitScheduled() { - std::unique_lock lock(mutex_); - cond_.wait(lock, [this] { return scheduledEpoch > finishedEpoch || shutdownFlag_; }); + int64_t result = scheduledEpoch.wait([this] { return *scheduledEpoch > *finishedEpoch || shutdownFlag_; }); if (shutdownFlag_) return std::nullopt; - return scheduledEpoch; + return result; } private: + template + struct ValueWithCondVar : kotlin::Pinned { + explicit ValueWithCondVar(T initializer, std::mutex& mutex) noexcept : value_(initializer), mutex_(mutex) {}; + + const T& operator*() const { return value_; } + + void set(T newValue) { + std::unique_lock lock(mutex_); + set(lock, newValue); + } + + void set(std::unique_lock& lock, T newValue) { + RuntimeAssert(lock.owns_lock() && lock.mutex() == &mutex_, "Required the mutex to be locked"); + value_ = newValue; + cond_.notify_all(); + } + + void notify() { + cond_.notify_all(); + } + + template + const T& wait(Predicate stop_waiting) { + std::unique_lock lock(mutex_); + cond_.wait(lock, stop_waiting); + return value_; + } + + private: + T value_; + std::mutex& mutex_; + std::condition_variable cond_; + }; + std::mutex mutex_; - std::condition_variable cond_; - int64_t startedEpoch = 0; - int64_t finishedEpoch = 0; - int64_t scheduledEpoch = 0; - int64_t finalizedEpoch = 0; + // Use a separate conditional variable for each counter to mitigate a winpthreads bug (see KT-50948 for details). + ValueWithCondVar startedEpoch{0, mutex_}; + ValueWithCondVar finishedEpoch{0, mutex_}; + ValueWithCondVar scheduledEpoch{0, mutex_}; + ValueWithCondVar finalizedEpoch{0, mutex_}; bool shutdownFlag_ = false; }; \ No newline at end of file