WindowsThread.cpp (3776B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include <chrono> 8 #include <thread> 9 10 #include "threading/Thread.h" 11 #include "threading/windows/ThreadPlatformData.h" 12 13 namespace js { 14 15 inline ThreadId::PlatformData* ThreadId::platformData() { 16 static_assert(sizeof platformData_ >= sizeof(PlatformData), 17 "platformData_ is too small"); 18 return reinterpret_cast<PlatformData*>(platformData_); 19 } 20 21 inline const ThreadId::PlatformData* ThreadId::platformData() const { 22 static_assert(sizeof platformData_ >= sizeof(PlatformData), 23 "platformData_ is too small"); 24 return reinterpret_cast<const PlatformData*>(platformData_); 25 } 26 27 ThreadId::ThreadId() { 28 platformData()->handle = nullptr; 29 platformData()->id = 0; 30 } 31 32 ThreadId::operator bool() const { return platformData()->handle; } 33 34 bool ThreadId::operator==(const ThreadId& aOther) const { 35 return platformData()->id == aOther.platformData()->id; 36 } 37 38 bool Thread::create(unsigned int(__stdcall* aMain)(void*), void* aArg) { 39 MOZ_RELEASE_ASSERT(!joinable()); 40 41 if (oom::ShouldFailWithOOM()) { 42 return false; 43 } 44 45 // Use _beginthreadex and not CreateThread, because threads that are 46 // created with the latter leak a small amount of memory when they use 47 // certain msvcrt functions and then exit. 48 uintptr_t handle = _beginthreadex(nullptr, options_.stackSize(), aMain, aArg, 49 STACK_SIZE_PARAM_IS_A_RESERVATION, 50 &id_.platformData()->id); 51 if (!handle) { 52 // On either Windows or POSIX we can't be sure if id_ was initalisad. So 53 // reset it manually. 54 id_ = ThreadId(); 55 return false; 56 } 57 id_.platformData()->handle = reinterpret_cast<HANDLE>(handle); 58 return true; 59 } 60 61 void Thread::join() { 62 MOZ_RELEASE_ASSERT(joinable()); 63 DWORD r = WaitForSingleObject(id_.platformData()->handle, INFINITE); 64 MOZ_RELEASE_ASSERT(r == WAIT_OBJECT_0); 65 BOOL success = CloseHandle(id_.platformData()->handle); 66 MOZ_RELEASE_ASSERT(success); 67 id_ = ThreadId(); 68 } 69 70 void Thread::detach() { 71 MOZ_RELEASE_ASSERT(joinable()); 72 BOOL success = CloseHandle(id_.platformData()->handle); 73 MOZ_RELEASE_ASSERT(success); 74 id_ = ThreadId(); 75 } 76 77 ThreadId ThreadId::ThisThreadId() { 78 ThreadId id; 79 id.platformData()->handle = GetCurrentThread(); 80 id.platformData()->id = GetCurrentThreadId(); 81 MOZ_RELEASE_ASSERT(id != ThreadId()); 82 return id; 83 } 84 85 void ThisThread::SetName(const char* name) { 86 MOZ_RELEASE_ASSERT(name); 87 88 #ifdef _MSC_VER 89 // Setting the thread name requires compiler support for structured 90 // exceptions, so this only works when compiled with MSVC. 91 static const DWORD THREAD_NAME_EXCEPTION = 0x406D1388; 92 static const DWORD THREAD_NAME_INFO_TYPE = 0x1000; 93 94 # pragma pack(push, 8) 95 struct THREADNAME_INFO { 96 DWORD dwType; 97 LPCSTR szName; 98 DWORD dwThreadID; 99 DWORD dwFlags; 100 }; 101 # pragma pack(pop) 102 103 THREADNAME_INFO info; 104 info.dwType = THREAD_NAME_INFO_TYPE; 105 info.szName = name; 106 info.dwThreadID = GetCurrentThreadId(); 107 info.dwFlags = 0; 108 109 __try { 110 RaiseException(THREAD_NAME_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), 111 (ULONG_PTR*)&info); 112 } __except (EXCEPTION_EXECUTE_HANDLER) { 113 // Do nothing. 114 } 115 #endif // _MSC_VER 116 } 117 118 void ThisThread::GetName(char* nameBuffer, size_t len) { 119 MOZ_RELEASE_ASSERT(len > 0); 120 *nameBuffer = '\0'; 121 } 122 123 void ThisThread::SleepMilliseconds(size_t ms) { 124 std::this_thread::sleep_for(std::chrono::milliseconds(ms)); 125 } 126 127 } // namespace js