[K/N] Put FinalizerProcessor CFRunLoop usage under a flag ^KT-64313

This commit is contained in:
Alexander Shabalin
2024-01-04 11:37:26 +01:00
committed by Space Team
parent 8ff869a08c
commit 5208b3c024
6 changed files with 54 additions and 21 deletions
@@ -65,6 +65,8 @@ object BinaryOptions : BinaryOptionRegistry() {
val objcDisposeOnMain by booleanOption()
val objcDisposeWithRunLoop by booleanOption()
val disableMmap by booleanOption()
val disableAllocatorOverheadEstimate by booleanOption()
@@ -245,6 +245,10 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
configuration.get(BinaryOptions.objcDisposeOnMain) ?: true
}
val objcDisposeWithRunLoop: Boolean by lazy {
configuration.get(BinaryOptions.objcDisposeWithRunLoop) ?: true
}
val enableSafepointSignposts: Boolean = configuration.get(BinaryOptions.enableSafepointSignposts)?.also {
if (it && !target.supportsSignposts) {
configuration.report(CompilerMessageSeverity.STRONG_WARNING, "Signposts are not available on $target. The setting will have no effect.")
@@ -2817,6 +2817,7 @@ internal class CodeGeneratorVisitor(
overrideRuntimeGlobal("Kotlin_mimallocUseDefaultOptions", llvm.constInt32(if (context.config.mimallocUseDefaultOptions) 1 else 0))
overrideRuntimeGlobal("Kotlin_mimallocUseCompaction", llvm.constInt32(if (context.config.mimallocUseCompaction) 1 else 0))
overrideRuntimeGlobal("Kotlin_objcDisposeOnMain", llvm.constInt32(if (context.config.objcDisposeOnMain) 1 else 0))
overrideRuntimeGlobal("Kotlin_objcDisposeWithRunLoop", llvm.constInt32(if (context.config.objcDisposeWithRunLoop) 1 else 0))
overrideRuntimeGlobal("Kotlin_enableSafepointSignposts", llvm.constInt32(if (context.config.enableSafepointSignposts) 1 else 0))
}
@@ -32,7 +32,7 @@ public:
// epochDoneCallback could be called on any subset of them.
// If no new tasks are set, epochDoneCallback will be eventually called on last epoch
explicit FinalizerProcessor(std::function<void(int64_t)> epochDoneCallback) noexcept :
epochDoneCallback_(std::move(epochDoneCallback)), processingLoop_(*this) {}
epochDoneCallback_(std::move(epochDoneCallback)), processingLoop_(makeProcessingLoop(*this)) {}
~FinalizerProcessor() { StopFinalizerThread(); }
@@ -46,7 +46,7 @@ public:
StartFinalizerThreadIfNone();
FinalizerQueueTraits::add(finalizerQueue_, std::move(tasks));
finalizerQueueEpoch_ = epoch;
processingLoop_.notify();
processingLoop_->notify();
}
void StopFinalizerThread() noexcept {
@@ -54,7 +54,7 @@ public:
std::unique_lock guard(finalizerQueueMutex_);
if (!finalizerThread_.joinable()) return;
shutdownFlag_ = true;
processingLoop_.notify();
processingLoop_->notify();
}
finalizerThread_.join();
shutdownFlag_ = false;
@@ -71,14 +71,14 @@ public:
if (finalizerThread_.joinable()) return;
finalizerThread_ = ScopedThread(ScopedThread::attributes().name("GC finalizer processor"), [this] {
processingLoop_.initThreadData();
processingLoop_->initThreadData();
Kotlin_initRuntimeIfNeeded();
{
std::unique_lock guard(initializedMutex_);
initialized_ = true;
}
initializedCondVar_.notify_all();
processingLoop_.body();
processingLoop_->body();
{
std::unique_lock guard(initializedMutex_);
initialized_ = false;
@@ -109,24 +109,33 @@ private:
epochDoneCallback_(currentEpoch);
}
#if KONAN_OBJC_INTEROP
class ProcessingLoop {
class ProcessingLoop : private Pinned {
public:
explicit ProcessingLoop(FinalizerProcessor& owner) :
virtual ~ProcessingLoop() = default;
virtual void notify() = 0;
virtual void initThreadData() = 0;
virtual void body() = 0;
};
#if KONAN_OBJC_INTEROP
class ProcessingLoopWithCFImpl final : public ProcessingLoop {
public:
explicit ProcessingLoopWithCFImpl(FinalizerProcessor& owner) :
owner_(owner),
sourceContext_{
0, this, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
[](void* info) {
auto& self = *reinterpret_cast<ProcessingLoop*>(info);
auto& self = *static_cast<ProcessingLoopWithCFImpl*>(info);
self.handleNewFinalizers();
}},
runLoopSource_(CFRunLoopSourceCreate(nullptr, 0, &sourceContext_)) {}
~ProcessingLoop() {
~ProcessingLoopWithCFImpl() override {
CFRelease(runLoopSource_);
}
void notify() {
void notify() override {
// wait until runLoop_ ptr is published
while (runLoop_.load(std::memory_order_acquire) == nullptr) {
std::this_thread::yield();
@@ -136,11 +145,11 @@ private:
CFRunLoopWakeUp(runLoop_);
}
void initThreadData() {
void initThreadData() override {
runLoop_.store(CFRunLoopGetCurrent(), std::memory_order_release);
}
void body() {
void body() override {
konan::AutoreleasePool autoreleasePool;
auto mode = kCFRunLoopDefaultMode;
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource_, mode);
@@ -150,6 +159,7 @@ private:
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runLoopSource_, mode);
runLoop_.store(nullptr, std::memory_order_release);
}
private:
void handleNewFinalizers() {
std::unique_lock lock(owner_.finalizerQueueMutex_);
@@ -172,18 +182,19 @@ private:
std::atomic<CFRunLoopRef> runLoop_ = nullptr;
CFRunLoopSourceRef runLoopSource_;
};
#else
class ProcessingLoop {
public:
explicit ProcessingLoop(FinalizerProcessor& owner) : owner_(owner) {}
#endif
void notify() {
class ProcessingLoopImpl final : public ProcessingLoop {
public:
explicit ProcessingLoopImpl(FinalizerProcessor& owner) : owner_(owner) {}
void notify() override {
owner_.finalizerQueueCondVar_.notify_all();
}
void initThreadData() { /* noop */ }
void initThreadData() override { /* noop */ }
void body() {
void body() override {
int64_t finishedEpoch = 0;
while (true) {
std::unique_lock lock(owner_.finalizerQueueMutex_);
@@ -202,10 +213,19 @@ private:
finishedEpoch = currentEpoch;
}
}
private:
FinalizerProcessor& owner_;
};
static std::unique_ptr<ProcessingLoop> makeProcessingLoop(FinalizerProcessor& owner) noexcept {
#if KONAN_OBJC_INTEROP
if (compiler::objcDisposeWithRunLoop()) {
return std::make_unique<ProcessingLoopWithCFImpl>(owner);
}
#endif
return std::make_unique<ProcessingLoopImpl>(owner);
}
ScopedThread finalizerThread_;
FinalizerQueue finalizerQueue_;
@@ -216,7 +236,7 @@ private:
bool shutdownFlag_ = false;
bool newTasksAllowed_ = true;
ProcessingLoop processingLoop_;
std::unique_ptr<ProcessingLoop> processingLoop_;
std::mutex initializedMutex_;
std::condition_variable initializedCondVar_;
@@ -32,6 +32,7 @@ RUNTIME_WEAK int32_t Kotlin_appStateTracking = 0;
RUNTIME_WEAK int32_t Kotlin_mimallocUseDefaultOptions = 1;
RUNTIME_WEAK int32_t Kotlin_mimallocUseCompaction = 0;
RUNTIME_WEAK int32_t Kotlin_objcDisposeOnMain = 0;
RUNTIME_WEAK int32_t Kotlin_objcDisposeWithRunLoop = 1;
RUNTIME_WEAK int32_t Kotlin_enableSafepointSignposts = 0;
ALWAYS_INLINE compiler::DestroyRuntimeMode compiler::destroyRuntimeMode() noexcept {
@@ -85,6 +86,10 @@ ALWAYS_INLINE bool compiler::objcDisposeOnMain() noexcept {
return Kotlin_objcDisposeOnMain != 0;
}
ALWAYS_INLINE bool compiler::objcDisposeWithRunLoop() noexcept {
return Kotlin_objcDisposeWithRunLoop != 0;
}
ALWAYS_INLINE bool compiler::enableSafepointSignposts() noexcept {
return Kotlin_enableSafepointSignposts != 0;
}
@@ -113,6 +113,7 @@ int getSourceInfo(void* addr, SourceInfo *result, int result_size) noexcept;
bool mimallocUseDefaultOptions() noexcept;
bool mimallocUseCompaction() noexcept;
bool objcDisposeOnMain() noexcept;
bool objcDisposeWithRunLoop() noexcept;
bool enableSafepointSignposts() noexcept;
#ifdef KONAN_ANDROID