зеркало из https://github.com/mozilla/gecko-dev.git
Bug 956899 - Add std::threading work-alike wrapper for posix and windows threads; r=froydnj
This commit is contained in:
Родитель
700d8864c8
Коммит
45aa50999f
|
@ -88,6 +88,7 @@ UNIFIED_SOURCES += [
|
||||||
'testThreadingConditionVariable.cpp',
|
'testThreadingConditionVariable.cpp',
|
||||||
'testThreadingExclusiveData.cpp',
|
'testThreadingExclusiveData.cpp',
|
||||||
'testThreadingMutex.cpp',
|
'testThreadingMutex.cpp',
|
||||||
|
'testThreadingThread.cpp',
|
||||||
'testToIntWidth.cpp',
|
'testToIntWidth.cpp',
|
||||||
'testTypedArrays.cpp',
|
'testTypedArrays.cpp',
|
||||||
'testUbiNode.cpp',
|
'testUbiNode.cpp',
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||||
|
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||||
|
*/
|
||||||
|
/* 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/Atomics.h"
|
||||||
|
#include "mozilla/IntegerRange.h"
|
||||||
|
#include "mozilla/Move.h"
|
||||||
|
#include "mozilla/Vector.h"
|
||||||
|
#include "jsapi-tests/tests.h"
|
||||||
|
#include "threading/Thread.h"
|
||||||
|
|
||||||
|
BEGIN_TEST(testThreadingThreadJoin)
|
||||||
|
{
|
||||||
|
bool flag = false;
|
||||||
|
js::Thread thread([](bool* flagp){*flagp = true;}, &flag);
|
||||||
|
CHECK(thread.joinable());
|
||||||
|
thread.join();
|
||||||
|
CHECK(flag);
|
||||||
|
CHECK(!thread.joinable());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
END_TEST(testThreadingThreadJoin)
|
||||||
|
|
||||||
|
BEGIN_TEST(testThreadingThreadDetach)
|
||||||
|
{
|
||||||
|
// We are going to detach this thread. Unlike join, we can't have it pointing at the stack
|
||||||
|
// because it might do the write after we have returned and pushed a new frame.
|
||||||
|
bool* flag = js_new<bool>(false);
|
||||||
|
js::Thread thread([](bool* flag){*flag = true; js_delete(flag);}, mozilla::Move(flag));
|
||||||
|
CHECK(thread.joinable());
|
||||||
|
thread.detach();
|
||||||
|
CHECK(!thread.joinable());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
END_TEST(testThreadingThreadDetach)
|
||||||
|
|
||||||
|
BEGIN_TEST(testThreadingThreadSetName)
|
||||||
|
{
|
||||||
|
js::Thread thread([](){ThisThread::SetName("JSAPI Test Thread");});
|
||||||
|
thread.detach();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
END_TEST(testThreadingThreadSetName)
|
||||||
|
|
||||||
|
BEGIN_TEST(testThreadingThreadId)
|
||||||
|
{
|
||||||
|
CHECK(Thread::Id() == Thread::Id());
|
||||||
|
Thread::Id fromOther;
|
||||||
|
js::Thread thread([](Thread::Id* idp){*idp = ThisThread::GetId();}, &fromOther);
|
||||||
|
Thread::Id fromMain = thread.get_id();
|
||||||
|
thread.join();
|
||||||
|
CHECK(fromOther == fromMain);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
END_TEST(testThreadingThreadId)
|
||||||
|
|
||||||
|
BEGIN_TEST(testThreadingThreadVectorMoveConstruct)
|
||||||
|
{
|
||||||
|
const static size_t N = 10;
|
||||||
|
mozilla::Atomic<int> count(0);
|
||||||
|
mozilla::Vector<js::Thread> v;
|
||||||
|
for (auto i : mozilla::MakeRange(N)) {
|
||||||
|
CHECK(v.emplaceBack([](mozilla::Atomic<int>* countp){(*countp)++;}, &count));
|
||||||
|
CHECK(v.length() == i + 1);
|
||||||
|
}
|
||||||
|
for (auto& th : v)
|
||||||
|
th.join();
|
||||||
|
CHECK(count == 10);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
END_TEST(testThreadingThreadVectorMoveConstruct)
|
|
@ -559,6 +559,7 @@ if CONFIG['OS_ARCH'] == 'WINNT':
|
||||||
'jit/ExecutableAllocatorWin.cpp',
|
'jit/ExecutableAllocatorWin.cpp',
|
||||||
'threading/windows/ConditionVariable.cpp',
|
'threading/windows/ConditionVariable.cpp',
|
||||||
'threading/windows/Mutex.cpp',
|
'threading/windows/Mutex.cpp',
|
||||||
|
'threading/windows/Thread.cpp',
|
||||||
]
|
]
|
||||||
# _CRT_RAND_S must be #defined before #including stdlib.h to get rand_s()
|
# _CRT_RAND_S must be #defined before #including stdlib.h to get rand_s()
|
||||||
DEFINES['_CRT_RAND_S'] = True
|
DEFINES['_CRT_RAND_S'] = True
|
||||||
|
@ -567,6 +568,7 @@ else:
|
||||||
'jit/ExecutableAllocatorPosix.cpp',
|
'jit/ExecutableAllocatorPosix.cpp',
|
||||||
'threading/posix/ConditionVariable.cpp',
|
'threading/posix/ConditionVariable.cpp',
|
||||||
'threading/posix/Mutex.cpp',
|
'threading/posix/Mutex.cpp',
|
||||||
|
'threading/posix/Thread.cpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
if CONFIG['JS_HAS_CTYPES']:
|
if CONFIG['JS_HAS_CTYPES']:
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
/* -*- 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_Thread_h
|
||||||
|
#define threading_Thread_h
|
||||||
|
|
||||||
|
#include "mozilla/Atomics.h"
|
||||||
|
#include "mozilla/Attributes.h"
|
||||||
|
#include "mozilla/IndexSequence.h"
|
||||||
|
#include "mozilla/TimeStamp.h"
|
||||||
|
#include "mozilla/Tuple.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef XP_WIN
|
||||||
|
# define THREAD_RETURN_TYPE unsigned int
|
||||||
|
# define THREAD_CALL_API __stdcall
|
||||||
|
#else
|
||||||
|
# define THREAD_RETURN_TYPE void*
|
||||||
|
# define THREAD_CALL_API
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace js {
|
||||||
|
namespace detail {
|
||||||
|
template <typename F, typename... Args>
|
||||||
|
class ThreadTrampoline;
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
// Execute the given functor concurrent with the currently executing instruction
|
||||||
|
// stream and within the current address space. Use with care.
|
||||||
|
class Thread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
class Id
|
||||||
|
{
|
||||||
|
class PlatformData;
|
||||||
|
void* platformData_[2];
|
||||||
|
|
||||||
|
public:
|
||||||
|
Id();
|
||||||
|
|
||||||
|
Id(const Id&) = default;
|
||||||
|
Id(Id&&) = default;
|
||||||
|
Id& operator=(const Id&) = default;
|
||||||
|
Id& operator=(Id&&) = default;
|
||||||
|
|
||||||
|
bool operator==(const Id& aOther);
|
||||||
|
bool operator!=(const Id& aOther) { return !operator==(aOther); }
|
||||||
|
|
||||||
|
inline PlatformData* platformData();
|
||||||
|
inline const PlatformData* platformData() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Start a thread of execution at functor |f| with parameters |args|.
|
||||||
|
template <typename F, typename... Args>
|
||||||
|
explicit Thread(F&& f, Args&&... args) {
|
||||||
|
using Trampoline = detail::ThreadTrampoline<F, Args...>;
|
||||||
|
auto trampoline = new Trampoline(mozilla::Forward<F>(f),
|
||||||
|
mozilla::Forward<Args>(args)...);
|
||||||
|
MOZ_RELEASE_ASSERT(trampoline);
|
||||||
|
create(Trampoline::Start, trampoline);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The thread must be joined or detached before destruction.
|
||||||
|
~Thread() {
|
||||||
|
MOZ_RELEASE_ASSERT(!joinable());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the thread into the detached state without blocking. In the detatched
|
||||||
|
// state, the thread continues to run until it exits, but cannot be joined.
|
||||||
|
// After this method returns, this Thread no longer represents a thread of
|
||||||
|
// execution. When the thread exits, its resources will be cleaned up by the
|
||||||
|
// system. At process exit, if the thread is still running, the thread's TLS
|
||||||
|
// storage will be destructed, but the thread stack will *not* be unrolled.
|
||||||
|
void detach();
|
||||||
|
|
||||||
|
// Block the current thread until this Thread returns from the functor it was
|
||||||
|
// created with. The thread's resources will be cleaned up before this
|
||||||
|
// function returns. After this method returns, this Thread no longer
|
||||||
|
// represents a thread of execution.
|
||||||
|
void join();
|
||||||
|
|
||||||
|
// Return true if this thread has not yet been joined or detached. If this
|
||||||
|
// method returns false, this Thread does not have an associated thread of
|
||||||
|
// execution, for example, if it has been previously moved or joined.
|
||||||
|
bool joinable() const {
|
||||||
|
return get_id() != Id();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the id of this thread if this represents a thread of execution or
|
||||||
|
// the default constructed Id() if not. The thread ID is guaranteed to
|
||||||
|
// uniquely identify a thread and can be compared with the == operator.
|
||||||
|
Id get_id() const { return id_; }
|
||||||
|
|
||||||
|
// Allow threads to be moved so that they can be stored in containers.
|
||||||
|
Thread(Thread&& aOther);
|
||||||
|
Thread& operator=(Thread&& aOther);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Disallow copy as that's not sensible for unique resources.
|
||||||
|
Thread(const Thread&) = delete;
|
||||||
|
void operator=(const Thread&) = delete;
|
||||||
|
|
||||||
|
// Provide a process global ID to each thread.
|
||||||
|
Id id_;
|
||||||
|
|
||||||
|
// Dispatch to per-platform implementation of thread creation.
|
||||||
|
void create(THREAD_RETURN_TYPE (THREAD_CALL_API *aMain)(void*), void* aArg);
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace ThisThread {
|
||||||
|
|
||||||
|
// Return the thread id of the calling thread.
|
||||||
|
Thread::Id GetId();
|
||||||
|
|
||||||
|
// Set the current thread name. Returns true if successful. Note that setting
|
||||||
|
// the thread name may not be available on all platforms; on these platforms
|
||||||
|
// setName() will simply do nothing.
|
||||||
|
void SetName(const char* name);
|
||||||
|
|
||||||
|
} // namespace ThisThread
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
// Platform thread APIs allow passing a single void* argument to the target
|
||||||
|
// thread. This class is responsible for safely ferrying the arg pack and
|
||||||
|
// functor across that void* membrane and running it in the other thread.
|
||||||
|
template <typename F, typename... Args>
|
||||||
|
class ThreadTrampoline
|
||||||
|
{
|
||||||
|
F f;
|
||||||
|
mozilla::Tuple<Args...> args;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ThreadTrampoline(F&& aF, Args&&... aArgs)
|
||||||
|
: f(mozilla::Forward<F>(aF)),
|
||||||
|
args(mozilla::Forward<Args>(aArgs)...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static THREAD_RETURN_TYPE THREAD_CALL_API Start(void* aPack) {
|
||||||
|
auto* pack = static_cast<ThreadTrampoline<F, Args...>*>(aPack);
|
||||||
|
pack->callMain(typename mozilla::IndexSequenceFor<Args...>::Type());
|
||||||
|
delete pack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t ...Indices>
|
||||||
|
void callMain(mozilla::IndexSequence<Indices...>) {
|
||||||
|
f(mozilla::Get<Indices>(args)...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace js
|
||||||
|
|
||||||
|
#undef THREAD_RETURN_TYPE
|
||||||
|
|
||||||
|
#endif // threading_Thread_h
|
|
@ -0,0 +1,148 @@
|
||||||
|
/* -*- 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 <new>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if defined(__APPLE__) && defined(__MACH__)
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||||
|
#include <pthread_np.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "threading/Thread.h"
|
||||||
|
|
||||||
|
class js::Thread::Id::PlatformData
|
||||||
|
{
|
||||||
|
friend class js::Thread;
|
||||||
|
friend js::Thread::Id js::ThisThread::GetId();
|
||||||
|
|
||||||
|
pthread_t ptThread;
|
||||||
|
|
||||||
|
// pthread_t does not have a default initializer, so we have to carry a bool
|
||||||
|
// to tell whether it is safe to compare or not.
|
||||||
|
bool hasThread;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline js::Thread::Id::PlatformData*
|
||||||
|
js::Thread::Id::platformData()
|
||||||
|
{
|
||||||
|
static_assert(sizeof platformData_ >= sizeof(PlatformData),
|
||||||
|
"platformData_ is too small");
|
||||||
|
return reinterpret_cast<PlatformData*>(platformData_);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const js::Thread::Id::PlatformData*
|
||||||
|
js::Thread::Id::platformData() const
|
||||||
|
{
|
||||||
|
static_assert(sizeof platformData_ >= sizeof(PlatformData),
|
||||||
|
"platformData_ is too small");
|
||||||
|
return reinterpret_cast<const PlatformData*>(platformData_);
|
||||||
|
}
|
||||||
|
|
||||||
|
js::Thread::Id::Id()
|
||||||
|
{
|
||||||
|
platformData()->hasThread = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
js::Thread::Id::operator==(const Id& aOther)
|
||||||
|
{
|
||||||
|
const PlatformData& self = *platformData();
|
||||||
|
const PlatformData& other = *aOther.platformData();
|
||||||
|
return (!self.hasThread && !other.hasThread) ||
|
||||||
|
(self.hasThread == other.hasThread &&
|
||||||
|
pthread_equal(self.ptThread, other.ptThread));
|
||||||
|
}
|
||||||
|
|
||||||
|
js::Thread::Thread(Thread&& aOther)
|
||||||
|
{
|
||||||
|
id_ = aOther.id_;
|
||||||
|
aOther.id_ = Id();
|
||||||
|
}
|
||||||
|
|
||||||
|
js::Thread&
|
||||||
|
js::Thread::operator=(Thread&& aOther)
|
||||||
|
{
|
||||||
|
MOZ_RELEASE_ASSERT(!joinable());
|
||||||
|
id_ = aOther.id_;
|
||||||
|
aOther.id_ = Id();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
js::Thread::create(void* (*aMain)(void*), void* aArg)
|
||||||
|
{
|
||||||
|
int r = pthread_create(&id_.platformData()->ptThread, nullptr, aMain, aArg);
|
||||||
|
MOZ_RELEASE_ASSERT(!r);
|
||||||
|
id_.platformData()->hasThread = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
js::Thread::join()
|
||||||
|
{
|
||||||
|
MOZ_RELEASE_ASSERT(joinable());
|
||||||
|
int r = pthread_join(id_.platformData()->ptThread, nullptr);
|
||||||
|
MOZ_RELEASE_ASSERT(!r);
|
||||||
|
id_ = Id();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
js::Thread::detach()
|
||||||
|
{
|
||||||
|
MOZ_RELEASE_ASSERT(joinable());
|
||||||
|
int r = pthread_detach(id_.platformData()->ptThread);
|
||||||
|
MOZ_RELEASE_ASSERT(!r);
|
||||||
|
id_ = Id();
|
||||||
|
}
|
||||||
|
|
||||||
|
js::Thread::Id
|
||||||
|
js::ThisThread::GetId()
|
||||||
|
{
|
||||||
|
js::Thread::Id id;
|
||||||
|
id.platformData()->ptThread = pthread_self();
|
||||||
|
id.platformData()->hasThread = true;
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
js::ThisThread::SetName(const char* name)
|
||||||
|
{
|
||||||
|
MOZ_RELEASE_ASSERT(name);
|
||||||
|
|
||||||
|
#if (defined(__APPLE__) && defined(__MACH__)) || defined(__linux__)
|
||||||
|
// On linux and OS X the name may not be longer than 16 bytes, including
|
||||||
|
// the null terminator. Truncate the name to 15 characters.
|
||||||
|
char nameBuf[16];
|
||||||
|
|
||||||
|
strncpy(nameBuf, name, sizeof nameBuf - 1);
|
||||||
|
nameBuf[sizeof nameBuf - 1] = '\0';
|
||||||
|
name = nameBuf;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int rv;
|
||||||
|
#ifdef XP_DARWIN
|
||||||
|
rv = pthread_setname_np(name);
|
||||||
|
#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||||
|
pthread_set_name_np(pthread_self(), name);
|
||||||
|
rv = 0;
|
||||||
|
#elif defined(__NetBSD__)
|
||||||
|
rv = pthread_setname_np(pthread_self(), "%s", (void*)name);
|
||||||
|
#else
|
||||||
|
rv = pthread_setname_np(pthread_self(), name);
|
||||||
|
#endif
|
||||||
|
MOZ_RELEASE_ASSERT(!rv);
|
||||||
|
}
|
|
@ -0,0 +1,143 @@
|
||||||
|
/* -*- 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 <assert.h>
|
||||||
|
#include <new.h>
|
||||||
|
#include <process.h>
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
#include "threading/Thread.h"
|
||||||
|
|
||||||
|
class js::Thread::Id::PlatformData
|
||||||
|
{
|
||||||
|
friend class js::Thread;
|
||||||
|
friend js::Thread::Id js::ThisThread::GetId();
|
||||||
|
|
||||||
|
HANDLE handle;
|
||||||
|
unsigned id;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline js::Thread::Id::PlatformData*
|
||||||
|
js::Thread::Id::platformData()
|
||||||
|
{
|
||||||
|
static_assert(sizeof platformData_ >= sizeof(PlatformData),
|
||||||
|
"platformData_ is too small");
|
||||||
|
return reinterpret_cast<PlatformData*>(platformData_);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const js::Thread::Id::PlatformData*
|
||||||
|
js::Thread::Id::platformData() const
|
||||||
|
{
|
||||||
|
static_assert(sizeof platformData_ >= sizeof(PlatformData),
|
||||||
|
"platformData_ is too small");
|
||||||
|
return reinterpret_cast<const PlatformData*>(platformData_);
|
||||||
|
}
|
||||||
|
|
||||||
|
js::Thread::Id::Id()
|
||||||
|
{
|
||||||
|
platformData()->handle = nullptr;
|
||||||
|
platformData()->id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
js::Thread::Id::operator==(const Id& aOther)
|
||||||
|
{
|
||||||
|
return platformData()->id == aOther.platformData()->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
js::Thread::Thread(Thread&& aOther)
|
||||||
|
{
|
||||||
|
id_ = aOther.id_;
|
||||||
|
aOther.id_ = Id();
|
||||||
|
}
|
||||||
|
|
||||||
|
js::Thread&
|
||||||
|
js::Thread::operator=(Thread&& aOther)
|
||||||
|
{
|
||||||
|
MOZ_RELEASE_ASSERT(!joinable());
|
||||||
|
id_ = aOther.id_;
|
||||||
|
aOther.id_ = Id();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
js::Thread::create(unsigned int (__stdcall* aMain)(void*), void* aArg)
|
||||||
|
{
|
||||||
|
// Use _beginthreadex and not CreateThread, because threads that are
|
||||||
|
// created with the latter leak a small amount of memory when they use
|
||||||
|
// certain msvcrt functions and then exit.
|
||||||
|
uintptr_t handle = _beginthreadex(nullptr, 0, aMain, aArg, 0,
|
||||||
|
&id_.platformData()->id);
|
||||||
|
MOZ_RELEASE_ASSERT(handle != 0);
|
||||||
|
id_.platformData()->handle = reinterpret_cast<HANDLE>(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
js::Thread::join()
|
||||||
|
{
|
||||||
|
MOZ_RELEASE_ASSERT(joinable());
|
||||||
|
DWORD r = WaitForSingleObject(id_.platformData()->handle, INFINITE);
|
||||||
|
MOZ_RELEASE_ASSERT(r == WAIT_OBJECT_0);
|
||||||
|
BOOL success = CloseHandle(id_.platformData()->handle);
|
||||||
|
MOZ_RELEASE_ASSERT(success);
|
||||||
|
id_ = Id();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
js::Thread::detach()
|
||||||
|
{
|
||||||
|
MOZ_RELEASE_ASSERT(joinable());
|
||||||
|
BOOL success = CloseHandle(id_.platformData()->handle);
|
||||||
|
MOZ_RELEASE_ASSERT(success);
|
||||||
|
id_ = Id();
|
||||||
|
}
|
||||||
|
|
||||||
|
js::Thread::Id
|
||||||
|
js::ThisThread::GetId()
|
||||||
|
{
|
||||||
|
js::Thread::Id id;
|
||||||
|
id.platformData()->handle = GetCurrentThread();
|
||||||
|
id.platformData()->id = GetCurrentThreadId();
|
||||||
|
MOZ_RELEASE_ASSERT(id != js::Thread::Id());
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
js::ThisThread::SetName(const char* name)
|
||||||
|
{
|
||||||
|
MOZ_RELEASE_ASSERT(name);
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
// Setting the thread name requires compiler support for structured
|
||||||
|
// exceptions, so this only works when compiled with MSVC.
|
||||||
|
static const DWORD THREAD_NAME_EXCEPTION = 0x406D1388;
|
||||||
|
static const DWORD THREAD_NAME_INFO_TYPE = 0x1000;
|
||||||
|
|
||||||
|
#pragma pack(push, 8)
|
||||||
|
struct THREADNAME_INFO
|
||||||
|
{
|
||||||
|
DWORD dwType;
|
||||||
|
LPCSTR szName;
|
||||||
|
DWORD dwThreadID;
|
||||||
|
DWORD dwFlags;
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
THREADNAME_INFO info;
|
||||||
|
info.dwType = THREAD_NAME_INFO_TYPE;
|
||||||
|
info.szName = name;
|
||||||
|
info.dwThreadID = GetCurrentThreadId();
|
||||||
|
info.dwFlags = 0;
|
||||||
|
|
||||||
|
__try {
|
||||||
|
RaiseException(THREAD_NAME_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR),
|
||||||
|
(ULONG_PTR*)&info);
|
||||||
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче