summaryrefslogtreecommitdiffstats
path: root/js/src/threading/windows/Thread.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/threading/windows/Thread.cpp')
-rw-r--r--js/src/threading/windows/Thread.cpp164
1 files changed, 164 insertions, 0 deletions
diff --git a/js/src/threading/windows/Thread.cpp b/js/src/threading/windows/Thread.cpp
new file mode 100644
index 000000000..29e8b16a1
--- /dev/null
+++ b/js/src/threading/windows/Thread.cpp
@@ -0,0 +1,164 @@
+/* -*- 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;
+};
+
+/* static */ js::HashNumber
+js::Thread::Hasher::hash(const Lookup& l)
+{
+ return mozilla::HashBytes(l.platformData_, sizeof(l.platformData_));
+}
+
+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) const
+{
+ 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;
+}
+
+bool
+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, options_.stackSize(),
+ aMain, aArg,
+ STACK_SIZE_PARAM_IS_A_RESERVATION,
+ &id_.platformData()->id);
+ if (!handle) {
+ // The documentation does not say what state the thread id has if the method
+ // fails, so assume that it is undefined and reset it manually.
+ id_ = Id();
+ return false;
+ }
+ id_.platformData()->handle = reinterpret_cast<HANDLE>(handle);
+ return true;
+}
+
+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
+}
+
+void
+js::ThisThread::GetName(char* nameBuffer, size_t len)
+{
+ MOZ_RELEASE_ASSERT(len > 0);
+ *nameBuffer = '\0';
+}