blob: facc81bf99dd22ef82f76926ca52798db335435c [file]
/*
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#ifndef RUNTIME_MM_THREAD_REGISTRY_H
#define RUNTIME_MM_THREAD_REGISTRY_H
#include <pthread.h>
#include "Common.h"
#include "SingleLockList.hpp"
#include "Utils.hpp"
namespace kotlin {
namespace mm {
class ThreadData;
class ThreadRegistry final : private Pinned {
public:
using Mutex = std::recursive_mutex;
using Node = SingleLockList<ThreadData, Mutex>::Node;
using Iterable = SingleLockList<ThreadData, Mutex>::Iterable;
static ThreadRegistry& Instance() noexcept;
Node* RegisterCurrentThread() noexcept;
// `ThreadData` associated with `threadDataNode` cannot be used after this call.
void Unregister(Node* threadDataNode) noexcept;
// Locks `ThreadRegistry` for safe iteration.
Iterable LockForIter() noexcept;
std::unique_lock<Mutex> Lock() noexcept;
// Try not to use these methods very often, as (1) thread local access can be slow on some platforms,
// (2) TLS gets deallocated before our thread destruction hooks run.
// Using this after `Unregister` for the thread has been called is undefined behaviour.
// Using this by a thread which is not attached to the Kotlin runtime is undefined behaviour.
ThreadData* CurrentThreadData() const noexcept;
Node* CurrentThreadDataNode() const noexcept {
RuntimeAssert(currentThreadDataNode_ != nullptr, "Thread is not attached to the runtime");
return currentThreadDataNode_;
}
Node* CurrentThreadDataNodeOrNull() const noexcept { return currentThreadDataNode_; }
static bool IsCurrentThreadRegistered() noexcept { return currentThreadDataNode_ != nullptr; }
static void ClearCurrentThreadData() { currentThreadDataNode_ = nullptr; }
// TODO(KT-72121): Remove this hack.
static void SetCurrentThreadDataNode(Node* node) noexcept { currentThreadDataNode_ = node; }
template <typename F>
void waitAllThreads(F&& f) noexcept {
// Disable new threads coming and going.
auto iter = LockForIter();
while (!std::all_of(iter.begin(), iter.end(), std::forward<F>(f))) {
std::this_thread::yield();
}
}
void PublishAll() noexcept;
private:
friend class GlobalData;
ThreadRegistry();
~ThreadRegistry();
static THREAD_LOCAL_VARIABLE Node* currentThreadDataNode_ __attribute__((annotate("current_thread_tlv")));
SingleLockList<ThreadData, Mutex> list_;
};
} // namespace mm
} // namespace kotlin
#endif // RUNTIME_MM_THREAD_REGISTRY_H