From f062cdc9babf0a0a0773b6f9b447c5a48921d838 Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Thu, 8 Apr 2021 08:02:16 +0000 Subject: [PATCH] Bug 1701613 part 3 - Add stub thread implementation for WASI. r=jandem,wingo WASI lacks thread support so the stub implementation for threads has been added. Differential Revision: https://phabricator.services.mozilla.com/D110073 --- js/src/moz.build | 6 ++++ js/src/shell/js.cpp | 3 +- js/src/threading/ConditionVariable.h | 2 +- js/src/threading/Thread.h | 4 +++ js/src/threading/noop/CpuCount.cpp | 9 +++++ js/src/threading/noop/NoopThread.cpp | 34 ++++++++++++++++++ js/src/threading/noop/ThreadPlatformData.h | 24 +++++++++++++ js/src/threading/posix/PosixThread.cpp | 7 ++++ js/src/threading/windows/WindowsThread.cpp | 7 ++++ js/src/vm/Runtime.cpp | 4 +++ js/src/wasm/WasmGenerator.cpp | 3 +- js/src/wasm/WasmModule.cpp | 3 +- mfbt/ThreadLocal.h | 24 ++++++++++++- mozglue/misc/ConditionVariable_noop.cpp | 40 ++++++++++++++++++++++ mozglue/misc/MutexPlatformData_noop.h | 18 ++++++++++ mozglue/misc/Mutex_noop.cpp | 34 ++++++++++++++++++ mozglue/misc/PlatformConditionVariable.h | 4 +-- mozglue/misc/PlatformMutex.h | 4 +-- mozglue/misc/TimeStamp_posix.cpp | 5 ++- mozglue/misc/moz.build | 6 ++++ 20 files changed, 228 insertions(+), 13 deletions(-) create mode 100644 js/src/threading/noop/CpuCount.cpp create mode 100644 js/src/threading/noop/NoopThread.cpp create mode 100644 js/src/threading/noop/ThreadPlatformData.h create mode 100644 mozglue/misc/ConditionVariable_noop.cpp create mode 100644 mozglue/misc/MutexPlatformData_noop.h create mode 100644 mozglue/misc/Mutex_noop.cpp diff --git a/js/src/moz.build b/js/src/moz.build index 12bc9f55d78e..870a80adf9ca 100755 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -493,6 +493,12 @@ if CONFIG["OS_ARCH"] == "WINNT": "threading/windows/CpuCount.cpp", "threading/windows/WindowsThread.cpp", ] +# WASI hasn't supported thread yet so noop implementation is used. +elif CONFIG["OS_ARCH"] == "WASI": + UNIFIED_SOURCES += [ + "threading/noop/CpuCount.cpp", + "threading/noop/NoopThread.cpp", + ] else: UNIFIED_SOURCES += [ "threading/posix/CpuCount.cpp", diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 9fe4d76d068d..e8e316a7da76 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -45,7 +45,6 @@ #include #include #include -#include #include #ifdef XP_UNIX # include @@ -8064,7 +8063,7 @@ static void BufferStreamMain(BufferStreamJob* job) { break; } - std::this_thread::sleep_for(std::chrono::milliseconds(delayMillis)); + ThisThread::SleepMilliseconds(delayMillis); chunkSize = std::min(chunkSize, byteLength - byteOffset); diff --git a/js/src/threading/ConditionVariable.h b/js/src/threading/ConditionVariable.h index 9d2731a81007..e2b8865cbf60 100644 --- a/js/src/threading/ConditionVariable.h +++ b/js/src/threading/ConditionVariable.h @@ -12,7 +12,7 @@ #include #include -#ifndef XP_WIN +#if !defined(XP_WIN) && !defined(__wasi__) # include #endif diff --git a/js/src/threading/Thread.h b/js/src/threading/Thread.h index ad9cb16ff3dc..628fe5d75da9 100644 --- a/js/src/threading/Thread.h +++ b/js/src/threading/Thread.h @@ -157,6 +157,10 @@ void SetName(const char* name); // 'nameBuffer', including the terminating NUL. void GetName(char* nameBuffer, size_t len); +// Causes the current thread to sleep until the +// number of real-time milliseconds specified have elapsed. +void SleepMilliseconds(size_t ms); + } // namespace ThisThread namespace detail { diff --git a/js/src/threading/noop/CpuCount.cpp b/js/src/threading/noop/CpuCount.cpp new file mode 100644 index 000000000000..9be4d404152a --- /dev/null +++ b/js/src/threading/noop/CpuCount.cpp @@ -0,0 +1,9 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include +#include "threading/CpuCount.h" + +uint32_t js::GetCPUCount() { return 1; } diff --git a/js/src/threading/noop/NoopThread.cpp b/js/src/threading/noop/NoopThread.cpp new file mode 100644 index 000000000000..5cab9cb5b42e --- /dev/null +++ b/js/src/threading/noop/NoopThread.cpp @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/Assertions.h" + +#include "threading/noop/ThreadPlatformData.h" + +namespace js { + +inline ThreadId::PlatformData* ThreadId::platformData() { + return reinterpret_cast(platformData_); +} + +inline const ThreadId::PlatformData* ThreadId::platformData() const { + return reinterpret_cast(platformData_); +} + +ThreadId::ThreadId() {} +ThreadId::operator bool() const { return false; } +bool ThreadId::operator==(const ThreadId& aOther) const { return true; } +bool Thread::create(void* (*aMain)(void*), void* aArg) { return false; } +void Thread::join() {} +void Thread::detach() {} +ThreadId ThreadId::ThisThreadId() { return ThreadId(); } +void ThisThread::SetName(const char*) {} +void ThisThread::GetName(char*, size_t) {} +void ThisThread::SleepMilliseconds(size_t) { + MOZ_CRASH("There is no any implementation for sleep."); +} + +} // namespace js diff --git a/js/src/threading/noop/ThreadPlatformData.h b/js/src/threading/noop/ThreadPlatformData.h new file mode 100644 index 000000000000..18159e718cf0 --- /dev/null +++ b/js/src/threading/noop/ThreadPlatformData.h @@ -0,0 +1,24 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef threading_noop_ThreadPlatformData_h +#define threading_noop_ThreadPlatformData_h + +#include +#include + +#include "threading/Thread.h" + +namespace js { + +class ThreadId::PlatformData { + friend class Thread; + friend class ThreadId; +}; + +} // namespace js + +#endif // threading_noop_ThreadPlatformData_h diff --git a/js/src/threading/posix/PosixThread.cpp b/js/src/threading/posix/PosixThread.cpp index 31834b286839..35532e375b63 100644 --- a/js/src/threading/posix/PosixThread.cpp +++ b/js/src/threading/posix/PosixThread.cpp @@ -6,6 +6,9 @@ #include "mozilla/Assertions.h" +#include +#include + #include "js/Utility.h" #include "threading/posix/ThreadPlatformData.h" #include "threading/Thread.h" @@ -136,4 +139,8 @@ void ThisThread::GetName(char* nameBuffer, size_t len) { } } +void ThisThread::SleepMilliseconds(size_t ms) { + std::this_thread::sleep_for(std::chrono::milliseconds(ms)); +} + } // namespace js diff --git a/js/src/threading/windows/WindowsThread.cpp b/js/src/threading/windows/WindowsThread.cpp index ee5f9428aaf4..68d4808ebd37 100644 --- a/js/src/threading/windows/WindowsThread.cpp +++ b/js/src/threading/windows/WindowsThread.cpp @@ -4,6 +4,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include +#include + #include "threading/Thread.h" #include "threading/windows/ThreadPlatformData.h" @@ -117,4 +120,8 @@ void ThisThread::GetName(char* nameBuffer, size_t len) { *nameBuffer = '\0'; } +void ThisThread::SleepMilliseconds(size_t ms) { + std::this_thread::sleep_for(std::chrono::milliseconds(ms)); +} + } // namespace js diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index c6cc828eaa6f..ea7bc446afff 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -71,7 +71,11 @@ JS::FilenameValidationCallback js::gFilenameValidationCallback = nullptr; namespace js { bool (*HelperThreadTaskCallback)(js::UniquePtr); +#ifndef __wasi__ bool gCanUseExtraThreads = true; +#else +bool gCanUseExtraThreads = false; +#endif } // namespace js void js::DisableExtraThreads() { gCanUseExtraThreads = false; } diff --git a/js/src/wasm/WasmGenerator.cpp b/js/src/wasm/WasmGenerator.cpp index dde212e2ca1b..27ba410cdc68 100644 --- a/js/src/wasm/WasmGenerator.cpp +++ b/js/src/wasm/WasmGenerator.cpp @@ -24,7 +24,6 @@ #include "mozilla/Unused.h" #include -#include #include "util/Memory.h" #include "util/Text.h" @@ -1340,7 +1339,7 @@ bool ModuleGenerator::finishTier2(const Module& module) { if (MOZ_UNLIKELY(JitOptions.wasmDelayTier2)) { // Introduce an artificial delay when testing wasmDelayTier2, since we // want to exercise both tier1 and tier2 code in this case. - std::this_thread::sleep_for(std::chrono::milliseconds(500)); + ThisThread::SleepMilliseconds(500); } return module.finishTier2(*linkData_, std::move(codeTier)); diff --git a/js/src/wasm/WasmModule.cpp b/js/src/wasm/WasmModule.cpp index 587162f06d57..74c3f93f7fa5 100644 --- a/js/src/wasm/WasmModule.cpp +++ b/js/src/wasm/WasmModule.cpp @@ -19,7 +19,6 @@ #include "wasm/WasmModule.h" #include -#include #include "jit/JitOptions.h" #include "js/BuildId.h" // JS::BuildIdCharVector @@ -199,7 +198,7 @@ bool Module::finishTier2(const LinkData& linkData2, void Module::testingBlockOnTier2Complete() const { while (testingTier2Active_) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + ThisThread::SleepMilliseconds(1); } } diff --git a/mfbt/ThreadLocal.h b/mfbt/ThreadLocal.h index 0a1a203a3a55..55c9fbcac69c 100644 --- a/mfbt/ThreadLocal.h +++ b/mfbt/ThreadLocal.h @@ -9,7 +9,7 @@ #ifndef mozilla_ThreadLocal_h #define mozilla_ThreadLocal_h -#if !defined(XP_WIN) +#if !defined(XP_WIN) && !defined(__wasi__) # include #endif @@ -120,6 +120,28 @@ class ThreadLocalKeyStorage { unsigned long mKey; }; # endif +#elif defined(__wasi__) +// There are no threads on WASI, so we just use a global variable. +template +class ThreadLocalKeyStorage { + public: + constexpr ThreadLocalKeyStorage() : mInited(false) {} + + inline bool initialized() const { return mInited; } + + inline void init() { mInited = true; } + + inline T get() const { return mVal; } + + inline bool set(const T aValue) { + mVal = aValue; + return true; + } + + private: + bool mInited; + T mVal; +}; #else template class ThreadLocalKeyStorage { diff --git a/mozglue/misc/ConditionVariable_noop.cpp b/mozglue/misc/ConditionVariable_noop.cpp new file mode 100644 index 000000000000..4b2886165021 --- /dev/null +++ b/mozglue/misc/ConditionVariable_noop.cpp @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/Assertions.h" + +#include "mozilla/PlatformConditionVariable.h" +#include "mozilla/PlatformMutex.h" +#include "MutexPlatformData_noop.h" + +using mozilla::TimeDuration; + +struct mozilla::detail::ConditionVariableImpl::PlatformData {}; + +mozilla::detail::ConditionVariableImpl::ConditionVariableImpl() {} + +mozilla::detail::ConditionVariableImpl::~ConditionVariableImpl() {} + +void mozilla::detail::ConditionVariableImpl::notify_one() {} + +void mozilla::detail::ConditionVariableImpl::notify_all() {} + +void mozilla::detail::ConditionVariableImpl::wait(MutexImpl&) { + // On WASI, there are no threads, so we never wait (either the condvar must + // be ready or there is a deadlock). +} + +mozilla::CVStatus mozilla::detail::ConditionVariableImpl::wait_for( + MutexImpl&, const TimeDuration&) { + return CVStatus::NoTimeout; +} + +mozilla::detail::ConditionVariableImpl::PlatformData* +mozilla::detail::ConditionVariableImpl::platformData() { + static_assert(sizeof platformData_ >= sizeof(PlatformData), + "platformData_ is too small"); + return reinterpret_cast(platformData_); +} diff --git a/mozglue/misc/MutexPlatformData_noop.h b/mozglue/misc/MutexPlatformData_noop.h new file mode 100644 index 000000000000..a2c8d060beb7 --- /dev/null +++ b/mozglue/misc/MutexPlatformData_noop.h @@ -0,0 +1,18 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MutexPlatformData_noop_h +#define MutexPlatformData_noop_h + +#if !defined(__wasi__) +# error This code is for WASI only. +#endif + +#include "mozilla/PlatformMutex.h" + +struct mozilla::detail::MutexImpl::PlatformData {}; + +#endif // MutexPlatformData_noop_h diff --git a/mozglue/misc/Mutex_noop.cpp b/mozglue/misc/Mutex_noop.cpp new file mode 100644 index 000000000000..eaa7959cc0fd --- /dev/null +++ b/mozglue/misc/Mutex_noop.cpp @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/Assertions.h" + +#include +#include + +#include "mozilla/PlatformMutex.h" +#include "MutexPlatformData_noop.h" + +mozilla::detail::MutexImpl::MutexImpl() {} + +mozilla::detail::MutexImpl::~MutexImpl() {} + +inline void mozilla::detail::MutexImpl::mutexLock() {} + +bool mozilla::detail::MutexImpl::tryLock() { return mutexTryLock(); } + +bool mozilla::detail::MutexImpl::mutexTryLock() { return true; } + +void mozilla::detail::MutexImpl::lock() { mutexLock(); } + +void mozilla::detail::MutexImpl::unlock() {} + +mozilla::detail::MutexImpl::PlatformData* +mozilla::detail::MutexImpl::platformData() { + static_assert(sizeof(platformData_) >= sizeof(PlatformData), + "platformData_ is too small"); + return reinterpret_cast(platformData_); +} diff --git a/mozglue/misc/PlatformConditionVariable.h b/mozglue/misc/PlatformConditionVariable.h index 2b006918cbf9..61fb06ade1c1 100644 --- a/mozglue/misc/PlatformConditionVariable.h +++ b/mozglue/misc/PlatformConditionVariable.h @@ -14,7 +14,7 @@ #include "mozilla/Attributes.h" #include "mozilla/PlatformMutex.h" #include "mozilla/TimeStamp.h" -#ifndef XP_WIN +#if !defined(XP_WIN) && !defined(__wasi__) # include #endif @@ -54,7 +54,7 @@ class ConditionVariableImpl { PlatformData* platformData(); -#ifndef XP_WIN +#if !defined(XP_WIN) && !defined(__wasi__) void* platformData_[sizeof(pthread_cond_t) / sizeof(void*)]; static_assert(sizeof(pthread_cond_t) / sizeof(void*) != 0 && sizeof(pthread_cond_t) % sizeof(void*) == 0, diff --git a/mozglue/misc/PlatformMutex.h b/mozglue/misc/PlatformMutex.h index 1d135b571142..9792b006ba2b 100644 --- a/mozglue/misc/PlatformMutex.h +++ b/mozglue/misc/PlatformMutex.h @@ -12,7 +12,7 @@ #include "mozilla/Attributes.h" #include "mozilla/Types.h" -#if !defined(XP_WIN) +#if !defined(XP_WIN) && !defined(__wasi__) # include #endif @@ -48,7 +48,7 @@ class MutexImpl { PlatformData* platformData(); -#if !defined(XP_WIN) +#if !defined(XP_WIN) && !defined(__wasi__) void* platformData_[sizeof(pthread_mutex_t) / sizeof(void*)]; static_assert(sizeof(pthread_mutex_t) / sizeof(void*) != 0 && sizeof(pthread_mutex_t) % sizeof(void*) == 0, diff --git a/mozglue/misc/TimeStamp_posix.cpp b/mozglue/misc/TimeStamp_posix.cpp index b07f955505e8..2db68d7e921d 100644 --- a/mozglue/misc/TimeStamp_posix.cpp +++ b/mozglue/misc/TimeStamp_posix.cpp @@ -50,7 +50,10 @@ #include "mozilla/Sprintf.h" #include "mozilla/TimeStamp.h" #include "mozilla/Uptime.h" -#include + +#if !defined(__wasi__) +# include +#endif // Estimate of the smallest duration of time we can measure. static uint64_t sResolution; diff --git a/mozglue/misc/moz.build b/mozglue/misc/moz.build index bc9212c9a336..0d9b694dfc13 100644 --- a/mozglue/misc/moz.build +++ b/mozglue/misc/moz.build @@ -87,6 +87,12 @@ if CONFIG["OS_ARCH"] == "WINNT": "ConditionVariable_windows.cpp", "Mutex_windows.cpp", ] +# WASI hasn't supported cond vars and mutexes yet so noop implementation is used. +elif CONFIG["OS_ARCH"] == "WASI": + SOURCES += [ + "ConditionVariable_noop.cpp", + "Mutex_noop.cpp", + ] else: SOURCES += [ "ConditionVariable_posix.cpp",