#ifndef Threading_h
#define Threading_h
#include <mutex>
#include <stdint.h>
#include <wtf/Atomics.h>
#include <wtf/Expected.h>
#include <wtf/FastTLS.h>
#include <wtf/Function.h>
#include <wtf/PlatformRegisters.h>
#include <wtf/Ref.h>
#include <wtf/RefPtr.h>
#include <wtf/StackBounds.h>
#include <wtf/StackStats.h>
#include <wtf/ThreadSafeRefCounted.h>
#include <wtf/ThreadSpecific.h>
#include <wtf/Vector.h>
#include <wtf/WordLock.h>
#include <wtf/text/AtomicStringTable.h>
#if USE(PTHREADS) && !OS(DARWIN)
#include <signal.h>
#endif
namespace WTF {
class AbstractLocker;
class ThreadMessageData;
enum class ThreadGroupAddResult;
class ThreadGroup;
class PrintStream;
WTF_EXPORT_PRIVATE void initializeThreading();
#if OS(WINDOWS)
WTF_EXPORT_PRIVATE ThreadIdentifier createThread(ThreadFunction, void*, const char* threadName);
WTF_EXPORT_PRIVATE int waitForThreadCompletion(ThreadIdentifier);
#endif
class Thread : public ThreadSafeRefCounted<Thread> {
public:
friend class ThreadGroup;
friend WTF_EXPORT_PRIVATE void initializeThreading();
#if OS(WINDOWS)
friend WTF_EXPORT_PRIVATE int waitForThreadCompletion(ThreadIdentifier);
#endif
WTF_EXPORT_PRIVATE ~Thread();
WTF_EXPORT_PRIVATE static Ref<Thread> create(const char* threadName, Function<void()>&&);
static Thread& current();
#if OS(WINDOWS)
WTF_EXPORT_PRIVATE static ThreadIdentifier currentID();
ThreadIdentifier id() const { return m_id; }
#endif
WTF_EXPORT_PRIVATE void changePriority(int);
WTF_EXPORT_PRIVATE int waitForCompletion();
WTF_EXPORT_PRIVATE void detach();
#if OS(DARWIN)
using PlatformSuspendError = kern_return_t;
#elif USE(PTHREADS)
using PlatformSuspendError = int;
#elif OS(WINDOWS)
using PlatformSuspendError = DWORD;
#endif
WTF_EXPORT_PRIVATE Expected<void, PlatformSuspendError> suspend();
WTF_EXPORT_PRIVATE void resume();
WTF_EXPORT_PRIVATE size_t getRegisters(PlatformRegisters&);
#if USE(PTHREADS)
WTF_EXPORT_PRIVATE bool signal(int signalNumber);
#endif
WTF_EXPORT_PRIVATE static void setCurrentThreadIsUserInteractive(int relativePriority = 0);
WTF_EXPORT_PRIVATE static void setCurrentThreadIsUserInitiated(int relativePriority = 0);
#if HAVE(QOS_CLASSES)
WTF_EXPORT_PRIVATE static void setGlobalMaxQOSClass(qos_class_t);
WTF_EXPORT_PRIVATE static qos_class_t adjustedQOSClass(qos_class_t);
#endif
static void initializeCurrentThreadInternal(const char* threadName);
static void initializeCurrentThreadEvenIfNonWTFCreated();
WTF_EXPORT_PRIVATE static const unsigned lockSpinLimit;
WTF_EXPORT_PRIVATE static void yield();
WTF_EXPORT_PRIVATE void dump(PrintStream& out) const;
static void initializePlatformThreading();
const StackBounds& stack() const
{
return m_stack;
}
AtomicStringTable* atomicStringTable()
{
return m_currentAtomicStringTable;
}
AtomicStringTable* setCurrentAtomicStringTable(AtomicStringTable* atomicStringTable)
{
AtomicStringTable* oldAtomicStringTable = m_currentAtomicStringTable;
m_currentAtomicStringTable = atomicStringTable;
return oldAtomicStringTable;
}
#if ENABLE(STACK_STATS)
StackStats::PerThreadStats& stackStats()
{
return m_stackStats;
}
#endif
void* savedStackPointerAtVMEntry()
{
return m_savedStackPointerAtVMEntry;
}
void setSavedStackPointerAtVMEntry(void* stackPointerAtVMEntry)
{
m_savedStackPointerAtVMEntry = stackPointerAtVMEntry;
}
void* savedLastStackTop()
{
return m_savedLastStackTop;
}
void setSavedLastStackTop(void* lastStackTop)
{
m_savedLastStackTop = lastStackTop;
}
#if OS(DARWIN)
mach_port_t machThread() { return m_platformThread; }
#endif
struct NewThreadContext;
static void entryPoint(NewThreadContext*);
protected:
Thread() = default;
void initializeInThread();
bool establishHandle(NewThreadContext*);
#if USE(PTHREADS)
void establishPlatformSpecificHandle(PlatformThreadHandle);
#else
void establishPlatformSpecificHandle(PlatformThreadHandle, ThreadIdentifier);
#endif
#if USE(PTHREADS) && !OS(DARWIN)
static void signalHandlerSuspendResume(int, siginfo_t*, void* ucontext);
#endif
static const char* normalizeThreadName(const char* threadName);
enum JoinableState : uint8_t {
Joinable,
Joined,
Detached,
};
JoinableState joinableState() { return m_joinableState; }
void didBecomeDetached() { m_joinableState = Detached; }
void didExit();
void didJoin() { m_joinableState = Joined; }
bool hasExited() { return m_didExit; }
ThreadGroupAddResult addToThreadGroup(const AbstractLocker& threadGroupLocker, ThreadGroup&);
void removeFromThreadGroup(const AbstractLocker& threadGroupLocker, ThreadGroup&);
#if !HAVE(FAST_TLS)
static WTF_EXPORT_PRIVATE ThreadSpecificKey s_key;
static void initializeTLSKey();
#endif
static Thread& initializeTLS(Ref<Thread>&&);
WTF_EXPORT_PRIVATE static Thread& initializeCurrentTLS();
static Thread* currentMayBeNull();
#if OS(WINDOWS)
WTF_EXPORT_PRIVATE static Thread* currentDying();
static RefPtr<Thread> get(ThreadIdentifier);
#endif
static void THREAD_SPECIFIC_CALL destructTLS(void* data);
JoinableState m_joinableState { Joinable };
bool m_isShuttingDown { false };
bool m_didExit { false };
bool m_isDestroyedOnce { false };
WordLock m_mutex;
StackBounds m_stack { StackBounds::emptyBounds() };
Vector<std::weak_ptr<ThreadGroup>> m_threadGroups;
PlatformThreadHandle m_handle;
#if OS(WINDOWS)
ThreadIdentifier m_id { 0 };
#elif OS(DARWIN)
mach_port_t m_platformThread { MACH_PORT_NULL };
#elif USE(PTHREADS)
PlatformRegisters* m_platformRegisters { nullptr };
unsigned m_suspendCount { 0 };
#endif
AtomicStringTable* m_currentAtomicStringTable { nullptr };
AtomicStringTable m_defaultAtomicStringTable;
#if ENABLE(STACK_STATS)
StackStats::PerThreadStats m_stackStats;
#endif
void* m_savedStackPointerAtVMEntry { nullptr };
void* m_savedLastStackTop;
public:
void* m_apiData { nullptr };
};
inline Thread* Thread::currentMayBeNull()
{
#if !HAVE(FAST_TLS)
ASSERT(s_key != InvalidThreadSpecificKey);
return static_cast<Thread*>(threadSpecificGet(s_key));
#else
return static_cast<Thread*>(_pthread_getspecific_direct(WTF_THREAD_DATA_KEY));
#endif
}
inline Thread& Thread::current()
{
#if !HAVE(FAST_TLS)
if (UNLIKELY(Thread::s_key == InvalidThreadSpecificKey))
WTF::initializeThreading();
#endif
if (auto* thread = currentMayBeNull())
return *thread;
#if OS(WINDOWS)
if (auto* thread = currentDying())
return *thread;
#endif
return initializeCurrentTLS();
}
}
using WTF::Thread;
#if OS(WINDOWS)
using WTF::ThreadIdentifier;
using WTF::createThread;
using WTF::waitForThreadCompletion;
#endif
#endif // Threading_h