diff --git a/dom/base/ScriptSettings.cpp b/dom/base/ScriptSettings.cpp index cb7d097d671b..16ff96c20a64 100644 --- a/dom/base/ScriptSettings.cpp +++ b/dom/base/ScriptSettings.cpp @@ -26,7 +26,8 @@ namespace mozilla { namespace dom { -static mozilla::ThreadLocal sScriptSettingsTLS; +static MOZ_THREAD_LOCAL(ScriptSettingsStackEntry*) sScriptSettingsTLS; +static bool sScriptSettingsTLSInitialized; class ScriptSettingsStack { public: @@ -94,14 +95,13 @@ UnuseEntryScriptProfiling() void InitScriptSettings() { - if (!sScriptSettingsTLS.initialized()) { - bool success = sScriptSettingsTLS.init(); - if (!success) { - MOZ_CRASH(); - } + bool success = sScriptSettingsTLS.init(); + if (!success) { + MOZ_CRASH(); } sScriptSettingsTLS.set(nullptr); + sScriptSettingsTLSInitialized = true; } void @@ -113,7 +113,7 @@ DestroyScriptSettings() bool ScriptSettingsInitialized() { - return sScriptSettingsTLS.initialized(); + return sScriptSettingsTLSInitialized; } ScriptSettingsStackEntry::ScriptSettingsStackEntry(nsIGlobalObject *aGlobal, diff --git a/dom/promise/PromiseDebugging.cpp b/dom/promise/PromiseDebugging.cpp index 0f99bb9a003f..6706cd1fd735 100644 --- a/dom/promise/PromiseDebugging.cpp +++ b/dom/promise/PromiseDebugging.cpp @@ -60,10 +60,10 @@ public: private: // `true` if an instance of `FlushRejections` is currently dispatched // and has not been executed yet. - static ThreadLocal sDispatched; + static MOZ_THREAD_LOCAL(bool) sDispatched; }; -/* static */ ThreadLocal +/* static */ MOZ_THREAD_LOCAL(bool) FlushRejections::sDispatched; static Promise* diff --git a/gfx/gl/GLLibraryEGL.cpp b/gfx/gl/GLLibraryEGL.cpp index 3b8370b77506..998141d6dfa2 100644 --- a/gfx/gl/GLLibraryEGL.cpp +++ b/gfx/gl/GLLibraryEGL.cpp @@ -29,7 +29,7 @@ namespace gl { StaticMutex GLLibraryEGL::sMutex; GLLibraryEGL sEGLLibrary; #ifdef MOZ_B2G -ThreadLocal GLLibraryEGL::sCurrentContext; +MOZ_THREAD_LOCAL(EGLContext) GLLibraryEGL::sCurrentContext; #endif // should match the order of EGLExtensions, and be null-terminated. diff --git a/gfx/gl/GLLibraryEGL.h b/gfx/gl/GLLibraryEGL.h index 81b94de5f9f1..043a8470abcf 100644 --- a/gfx/gl/GLLibraryEGL.h +++ b/gfx/gl/GLLibraryEGL.h @@ -641,7 +641,7 @@ public: } private: - static ThreadLocal sCurrentContext; + static MOZ_THREAD_LOCAL(EGLContext) sCurrentContext; public: #else diff --git a/gfx/gl/SkiaGLGlue.cpp b/gfx/gl/SkiaGLGlue.cpp index 7ffcab1c73ce..9130db42a81f 100755 --- a/gfx/gl/SkiaGLGlue.cpp +++ b/gfx/gl/SkiaGLGlue.cpp @@ -24,16 +24,14 @@ using mozilla::gl::GLFeature; using mozilla::gl::SkiaGLGlue; using mozilla::gfx::DrawTarget; -static mozilla::ThreadLocal sGLContext; +static MOZ_THREAD_LOCAL(GLContext*) sGLContext; extern "C" { static void SetStaticGLContext(GLContext* context) { - if (!sGLContext.initialized()) { - mozilla::DebugOnly success = sGLContext.init(); - MOZ_ASSERT(success); - } + mozilla::DebugOnly success = sGLContext.init(); + MOZ_ASSERT(success); sGLContext.set(context); } diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index ae90f2e64b3a..e93f0237327b 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -58,17 +58,15 @@ using namespace js; using namespace js::jit; -using mozilla::ThreadLocal; - // Assert that JitCode is gc::Cell aligned. JS_STATIC_ASSERT(sizeof(JitCode) % gc::CellSize == 0); -static ThreadLocal TlsJitContext; +static MOZ_THREAD_LOCAL(JitContext*) TlsJitContext; static JitContext* CurrentJitContext() { - if (!TlsJitContext.initialized()) + if (!TlsJitContext.init()) return nullptr; return TlsJitContext.get(); } @@ -155,7 +153,7 @@ JitContext::~JitContext() bool jit::InitializeIon() { - if (!TlsJitContext.initialized() && !TlsJitContext.init()) + if (!TlsJitContext.init()) return false; CheckLogging(); #if defined(JS_CODEGEN_ARM) diff --git a/js/src/jsutil.cpp b/js/src/jsutil.cpp index 303063fc8565..b9ebfa128fd0 100644 --- a/js/src/jsutil.cpp +++ b/js/src/jsutil.cpp @@ -37,11 +37,11 @@ namespace js { namespace oom { JS_PUBLIC_DATA(uint32_t) targetThread = 0; -JS_PUBLIC_DATA(mozilla::ThreadLocal) threadType; +JS_PUBLIC_DATA(MOZ_THREAD_LOCAL(uint32_t)) threadType; bool InitThreadType(void) { - return threadType.initialized() || threadType.init(); + return threadType.init(); } void diff --git a/js/src/vm/Initialization.cpp b/js/src/vm/Initialization.cpp index 502d640aa008..e5108226621e 100644 --- a/js/src/vm/Initialization.cpp +++ b/js/src/vm/Initialization.cpp @@ -75,7 +75,7 @@ JS_Init(void) #endif using js::TlsPerThreadData; - if (!TlsPerThreadData.initialized() && !TlsPerThreadData.init()) + if (!TlsPerThreadData.init()) return false; #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 0084df3c9c76..dfc813035e62 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -63,11 +63,10 @@ using mozilla::NegativeInfinity; using mozilla::PodZero; using mozilla::PodArrayZero; using mozilla::PositiveInfinity; -using mozilla::ThreadLocal; using JS::GenericNaN; using JS::DoubleNaNValue; -/* static */ ThreadLocal js::TlsPerThreadData; +/* static */ MOZ_THREAD_LOCAL(PerThreadData*) js::TlsPerThreadData; /* static */ Atomic JSRuntime::liveRuntimesCount; namespace js { diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 80df8078fdcf..b35f71320322 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -63,7 +63,7 @@ class TraceLoggerThread; #endif /* Thread Local Storage slot for storing the runtime for a thread. */ -extern mozilla::ThreadLocal TlsPerThreadData; +extern MOZ_THREAD_LOCAL(PerThreadData*) TlsPerThreadData; } // namespace js diff --git a/mfbt/ThreadLocal.h b/mfbt/ThreadLocal.h index eae84a21447c..0ebe2917cb6e 100644 --- a/mfbt/ThreadLocal.h +++ b/mfbt/ThreadLocal.h @@ -42,11 +42,28 @@ typedef unsigned long sig_safe_t; typedef sig_atomic_t sig_safe_t; #endif +namespace detail { + +#if defined(HAVE_THREAD_TLS_KEYWORD) +#define MOZ_HAS_THREAD_LOCAL +#endif + /* * Thread Local Storage helpers. * * Usage: * + * Do not directly instantiate this class. Instead, use the + * MOZ_THREAD_LOCAL macro to declare or define instances. The macro + * takes a type name as its argument. + * + * Declare like this: + * extern MOZ_THREAD_LOCAL(int) tlsInt; + * Define like this: + * MOZ_THREAD_LOCAL(int) tlsInt; + * or: + * static MOZ_THREAD_LOCAL(int) tlsInt; + * * Only static-storage-duration (e.g. global variables, or static class members) * objects of this class should be instantiated. This class relies on * zero-initialization, which is implicit for static-storage-duration objects. @@ -56,9 +73,10 @@ typedef sig_atomic_t sig_safe_t; * * // Create a TLS item. * // - * // Note that init() should be invoked exactly once, before any usage of set() - * // or get(). - * mozilla::ThreadLocal tlsKey; + * // Note that init() should be invoked before the first use of set() + * // or get(). It is ok to call it multiple times. This must be + * // called in a way that avoids possible races with other threads. + * MOZ_THREAD_LOCAL(int) tlsKey; * if (!tlsKey.init()) { * // deal with the error * } @@ -72,6 +90,7 @@ typedef sig_atomic_t sig_safe_t; template class ThreadLocal { +#ifndef MOZ_HAS_THREAD_LOCAL #if defined(XP_WIN) typedef unsigned long key_t; #else @@ -93,11 +112,24 @@ class ThreadLocal { typedef S *Type; }; +#endif + + bool initialized() const { +#ifdef MOZ_HAS_THREAD_LOCAL + return true; +#else + return mInited; +#endif + } public: + // __thread does not allow non-trivial constructors, but we can + // instead rely on zero-initialization. +#ifndef MOZ_HAS_THREAD_LOCAL ThreadLocal() : mKey(0), mInited(false) {} +#endif MOZ_WARN_UNUSED_RESULT inline bool init(); @@ -105,11 +137,13 @@ public: inline void set(const T aValue); - bool initialized() const { return mInited; } - private: +#ifdef MOZ_HAS_THREAD_LOCAL + T mValue; +#else key_t mKey; bool mInited; +#endif }; template @@ -122,20 +156,29 @@ ThreadLocal::init() static_assert(sizeof(T) <= sizeof(void*), "mozilla::ThreadLocal can't be used for types larger than " "a pointer"); - MOZ_ASSERT(!initialized()); -#ifdef XP_WIN - mKey = TlsAlloc(); - mInited = mKey != 0xFFFFFFFFUL; // TLS_OUT_OF_INDEXES + +#ifdef MOZ_HAS_THREAD_LOCAL + return true; #else - mInited = !pthread_key_create(&mKey, nullptr); + if (!initialized()) { +#ifdef XP_WIN + mKey = TlsAlloc(); + mInited = mKey != 0xFFFFFFFFUL; // TLS_OUT_OF_INDEXES +#else + mInited = !pthread_key_create(&mKey, nullptr); #endif + } return mInited; +#endif } template inline T ThreadLocal::get() const { +#ifdef MOZ_HAS_THREAD_LOCAL + return mValue; +#else MOZ_ASSERT(initialized()); void* h; #ifdef XP_WIN @@ -144,12 +187,16 @@ ThreadLocal::get() const h = pthread_getspecific(mKey); #endif return static_cast(reinterpret_cast::Type>(h)); +#endif } template inline void ThreadLocal::set(const T aValue) { +#ifdef MOZ_HAS_THREAD_LOCAL + mValue = aValue; +#else MOZ_ASSERT(initialized()); void* h = reinterpret_cast(static_cast::Type>(aValue)); #ifdef XP_WIN @@ -160,8 +207,16 @@ ThreadLocal::set(const T aValue) if (!succeeded) { MOZ_CRASH(); } +#endif } +#ifdef MOZ_HAS_THREAD_LOCAL +#define MOZ_THREAD_LOCAL(TYPE) __thread mozilla::detail::ThreadLocal +#else +#define MOZ_THREAD_LOCAL(TYPE) mozilla::detail::ThreadLocal +#endif + +} // namespace detail } // namespace mozilla #endif /* mozilla_ThreadLocal_h */ diff --git a/tools/memory-profiler/UncensoredAllocator.cpp b/tools/memory-profiler/UncensoredAllocator.cpp index 8d87c709c88e..9cccf44135c7 100644 --- a/tools/memory-profiler/UncensoredAllocator.cpp +++ b/tools/memory-profiler/UncensoredAllocator.cpp @@ -20,7 +20,7 @@ namespace mozilla { #ifdef MOZ_REPLACE_MALLOC -ThreadLocal MallocHook::mEnabledTLS; +MOZ_THREAD_LOCAL(bool) MallocHook::mEnabledTLS; NativeProfiler* MallocHook::mNativeProfiler; malloc_hook_table_t MallocHook::mMallocHook; #endif @@ -81,12 +81,10 @@ MallocHook::Initialize() if (bridge) { mozilla::Unused << bridge->RegisterHook("memory-profiler", nullptr, nullptr); } - if (!mEnabledTLS.initialized()) { - bool success = mEnabledTLS.init(); - if (NS_WARN_IF(!success)) { - return; - } - mEnabledTLS.set(false); + + bool success = mEnabledTLS.init(); + if (NS_WARN_IF(!success)) { + return; } #endif } @@ -96,9 +94,6 @@ MallocHook::Enable(NativeProfiler* aNativeProfiler) { #ifdef MOZ_REPLACE_MALLOC MOZ_ASSERT(NS_IsMainThread()); - if (NS_WARN_IF(!mEnabledTLS.initialized())) { - return; - } ReplaceMallocBridge* bridge = ReplaceMallocBridge::Get(3); if (bridge) { const malloc_table_t* alloc_funcs = diff --git a/tools/memory-profiler/UncensoredAllocator.h b/tools/memory-profiler/UncensoredAllocator.h index c59a05a568cc..b9074c73865e 100644 --- a/tools/memory-profiler/UncensoredAllocator.h +++ b/tools/memory-profiler/UncensoredAllocator.h @@ -29,7 +29,7 @@ private: static void* SampleNative(void* aAddr, size_t aSize); static void RemoveNative(void* aAddr); #ifdef MOZ_REPLACE_MALLOC - static ThreadLocal mEnabledTLS; + static MOZ_THREAD_LOCAL(bool) mEnabledTLS; static NativeProfiler* mNativeProfiler; static malloc_hook_table_t mMallocHook; #endif diff --git a/tools/profiler/core/platform.cpp b/tools/profiler/core/platform.cpp index 7fb57d6ef8cb..3a9726da306e 100644 --- a/tools/profiler/core/platform.cpp +++ b/tools/profiler/core/platform.cpp @@ -67,9 +67,9 @@ public: }; #endif -mozilla::ThreadLocal tlsPseudoStack; -mozilla::ThreadLocal tlsTicker; -mozilla::ThreadLocal tlsStackTop; +MOZ_THREAD_LOCAL(PseudoStack *) tlsPseudoStack; +MOZ_THREAD_LOCAL(GeckoSampler *) tlsTicker; +MOZ_THREAD_LOCAL(void *) tlsStackTop; // We need to track whether we've been initialized otherwise // we end up using tlsStack without initializing it. // Because tlsStack is totally opaque to us we can't reuse diff --git a/tools/profiler/public/GeckoProfilerImpl.h b/tools/profiler/public/GeckoProfilerImpl.h index 2b8907f54eda..2b565af15c55 100644 --- a/tools/profiler/public/GeckoProfilerImpl.h +++ b/tools/profiler/public/GeckoProfilerImpl.h @@ -40,9 +40,9 @@ namespace mozilla { class TimeStamp; } // namespace mozilla -extern mozilla::ThreadLocal tlsPseudoStack; -extern mozilla::ThreadLocal tlsTicker; -extern mozilla::ThreadLocal tlsStackTop; +extern MOZ_THREAD_LOCAL(PseudoStack *) tlsPseudoStack; +extern MOZ_THREAD_LOCAL(GeckoSampler *) tlsTicker; +extern MOZ_THREAD_LOCAL(void *) tlsStackTop; extern bool stack_key_initialized; #ifndef SAMPLE_FUNCTION_NAME diff --git a/tools/profiler/tasktracer/GeckoTaskTracer.cpp b/tools/profiler/tasktracer/GeckoTaskTracer.cpp index e1a855c1827f..9895626d3196 100644 --- a/tools/profiler/tasktracer/GeckoTaskTracer.cpp +++ b/tools/profiler/tasktracer/GeckoTaskTracer.cpp @@ -59,7 +59,7 @@ pid_t gettid(); namespace mozilla { namespace tasktracer { -static mozilla::ThreadLocal sTraceInfoTLS; +static MOZ_THREAD_LOCAL(TraceInfo*) sTraceInfoTLS; static mozilla::StaticMutex sMutex; // The generation of TraceInfo. It will be > 0 if the Task Tracer is started and diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index 16257500debc..82e0b412b319 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -1409,7 +1409,7 @@ struct CollectorData CycleCollectedJSRuntime* mRuntime; }; -static mozilla::ThreadLocal sCollectorData; +static MOZ_THREAD_LOCAL(CollectorData*) sCollectorData; //////////////////////////////////////////////////////////////////////// // Utility functions @@ -3999,8 +3999,11 @@ nsCycleCollector_suspectedCount() bool nsCycleCollector_init() { + static DebugOnly sInitialized; + MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); - MOZ_ASSERT(!sCollectorData.initialized(), "Called twice!?"); + MOZ_ASSERT(!sInitialized, "Called twice!?"); + sInitialized = true; return sCollectorData.init(); } @@ -4008,8 +4011,6 @@ nsCycleCollector_init() void nsCycleCollector_startup() { - MOZ_ASSERT(sCollectorData.initialized(), - "Forgot to call nsCycleCollector_init!"); if (sCollectorData.get()) { MOZ_CRASH(); } diff --git a/xpcom/build/IOInterposer.cpp b/xpcom/build/IOInterposer.cpp index 26ad0045aeb5..09e6bdc46821 100644 --- a/xpcom/build/IOInterposer.cpp +++ b/xpcom/build/IOInterposer.cpp @@ -359,7 +359,8 @@ public: // List of observers registered static StaticAutoPtr sMasterList; -static ThreadLocal sThreadLocalData; +static MOZ_THREAD_LOCAL(PerThreadData*) sThreadLocalData; +static bool sThreadLocalDataInitialized; } // namespace IOInterposeObserver::Observation::Observation(Operation aOperation, @@ -429,6 +430,7 @@ IOInterposer::Init() if (!sThreadLocalData.init()) { return false; } + sThreadLocalDataInitialized = true; bool isMainThread = true; RegisterCurrentThread(isMainThread); sMasterList = new MasterList(); @@ -448,7 +450,7 @@ IOInterposer::Init() bool IOInterposeObserver::IsMainThread() { - if (!sThreadLocalData.initialized()) { + if (!sThreadLocalDataInitialized) { return false; } PerThreadData* ptd = sThreadLocalData.get(); @@ -538,7 +540,7 @@ IOInterposer::Unregister(IOInterposeObserver::Operation aOp, void IOInterposer::RegisterCurrentThread(bool aIsMainThread) { - if (!sThreadLocalData.initialized()) { + if (!sThreadLocalDataInitialized) { return; } MOZ_ASSERT(!sThreadLocalData.get()); @@ -549,7 +551,7 @@ IOInterposer::RegisterCurrentThread(bool aIsMainThread) void IOInterposer::UnregisterCurrentThread() { - if (!sThreadLocalData.initialized()) { + if (!sThreadLocalDataInitialized) { return; } PerThreadData* curThreadData = sThreadLocalData.get(); diff --git a/xpcom/threads/AbstractThread.cpp b/xpcom/threads/AbstractThread.cpp index 50eb76ea4622..24a29779d852 100644 --- a/xpcom/threads/AbstractThread.cpp +++ b/xpcom/threads/AbstractThread.cpp @@ -26,7 +26,7 @@ LazyLogModule gMozPromiseLog("MozPromise"); LazyLogModule gStateWatchingLog("StateWatching"); StaticRefPtr sMainThread; -ThreadLocal AbstractThread::sCurrentThreadTLS; +MOZ_THREAD_LOCAL(AbstractThread*) AbstractThread::sCurrentThreadTLS; class XPCOMThreadWrapper : public AbstractThread { diff --git a/xpcom/threads/AbstractThread.h b/xpcom/threads/AbstractThread.h index 0f8d915120e4..6242337c3404 100644 --- a/xpcom/threads/AbstractThread.h +++ b/xpcom/threads/AbstractThread.h @@ -85,7 +85,7 @@ public: protected: virtual ~AbstractThread() {} - static ThreadLocal sCurrentThreadTLS; + static MOZ_THREAD_LOCAL(AbstractThread*) sCurrentThreadTLS; // True if we want to require that every task dispatched from tasks running in // this queue go through our queue's tail dispatcher. diff --git a/xpcom/threads/BackgroundHangMonitor.cpp b/xpcom/threads/BackgroundHangMonitor.cpp index 4ea84b0e9763..ba674cbfbe7f 100644 --- a/xpcom/threads/BackgroundHangMonitor.cpp +++ b/xpcom/threads/BackgroundHangMonitor.cpp @@ -138,7 +138,8 @@ BackgroundHangManager::Observe(nsISupports* aSubject, const char* aTopic, const class BackgroundHangThread : public LinkedListElement { private: - static ThreadLocal sTlsKey; + static MOZ_THREAD_LOCAL(BackgroundHangThread*) sTlsKey; + static bool sTlsKeyInitialized; BackgroundHangThread(const BackgroundHangThread&); BackgroundHangThread& operator=(const BackgroundHangThread&); @@ -206,8 +207,8 @@ StaticRefPtr BackgroundHangManager::sInstance; bool BackgroundHangManager::sProhibited = false; bool BackgroundHangManager::sDisabled = false; -ThreadLocal BackgroundHangThread::sTlsKey; - +MOZ_THREAD_LOCAL(BackgroundHangThread*) BackgroundHangThread::sTlsKey; +bool BackgroundHangThread::sTlsKeyInitialized; BackgroundHangManager::BackgroundHangManager() : mShutdown(false) @@ -372,7 +373,7 @@ BackgroundHangThread::BackgroundHangThread(const char* aName, , mWaiting(true) , mStats(aName) { - if (sTlsKey.initialized()) { + if (sTlsKeyInitialized) { sTlsKey.set(this); } // Lock here because LinkedList is not thread-safe @@ -393,7 +394,7 @@ BackgroundHangThread::~BackgroundHangThread() autoLock.Notify(); // We no longer have a thread - if (sTlsKey.initialized()) { + if (sTlsKeyInitialized) { sTlsKey.set(nullptr); } @@ -489,7 +490,7 @@ BackgroundHangThread::FindThread() return nullptr; } - if (sTlsKey.initialized()) { + if (sTlsKeyInitialized) { // Use TLS if available MOZ_ASSERT(!BackgroundHangManager::sProhibited, "BackgroundHandleManager is not initialized"); diff --git a/xpcom/threads/nsThreadManager.cpp b/xpcom/threads/nsThreadManager.cpp index c5741d995db2..8eb763d5134d 100644 --- a/xpcom/threads/nsThreadManager.cpp +++ b/xpcom/threads/nsThreadManager.cpp @@ -18,7 +18,7 @@ using namespace mozilla; -static mozilla::ThreadLocal sTLSIsMainThread; +static MOZ_THREAD_LOCAL(bool) sTLSIsMainThread; bool NS_IsMainThread() @@ -29,12 +29,10 @@ NS_IsMainThread() void NS_SetMainThread() { - if (!sTLSIsMainThread.initialized()) { - if (!sTLSIsMainThread.init()) { - MOZ_CRASH(); - } - sTLSIsMainThread.set(true); + if (!sTLSIsMainThread.init()) { + MOZ_CRASH(); } + sTLSIsMainThread.set(true); MOZ_ASSERT(NS_IsMainThread()); }