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
platformData()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
platformData() const21 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
ThreadId()27 ThreadId::ThreadId() {
28 platformData()->handle = nullptr;
29 platformData()->id = 0;
30 }
31
operator bool() const32 ThreadId::operator bool() const { return platformData()->handle; }
33
operator ==(const ThreadId & aOther) const34 bool ThreadId::operator==(const ThreadId& aOther) const {
35 return platformData()->id == aOther.platformData()->id;
36 }
37
create(unsigned int (__stdcall * aMain)(void *),void * aArg)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
join()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
detach()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
ThisThreadId()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
SetName(const char * name)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
GetName(char * nameBuffer,size_t len)118 void ThisThread::GetName(char* nameBuffer, size_t len) {
119 MOZ_RELEASE_ASSERT(len > 0);
120 *nameBuffer = '\0';
121 }
122
SleepMilliseconds(size_t ms)123 void ThisThread::SleepMilliseconds(size_t ms) {
124 std::this_thread::sleep_for(std::chrono::milliseconds(ms));
125 }
126
127 } // namespace js
128