1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
/* -*- 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 <chrono>
#include <thread>
#include "threading/Thread.h"
#include "threading/windows/ThreadPlatformData.h"
namespace js {
inline ThreadId::PlatformData* ThreadId::platformData() {
static_assert(sizeof platformData_ >= sizeof(PlatformData),
"platformData_ is too small");
return reinterpret_cast<PlatformData*>(platformData_);
}
inline const ThreadId::PlatformData* ThreadId::platformData() const {
static_assert(sizeof platformData_ >= sizeof(PlatformData),
"platformData_ is too small");
return reinterpret_cast<const PlatformData*>(platformData_);
}
ThreadId::ThreadId() {
platformData()->handle = nullptr;
platformData()->id = 0;
}
ThreadId::operator bool() const { return platformData()->handle; }
bool ThreadId::operator==(const ThreadId& aOther) const {
return platformData()->id == aOther.platformData()->id;
}
bool Thread::create(unsigned int(__stdcall* aMain)(void*), void* aArg) {
MOZ_RELEASE_ASSERT(!joinable());
if (oom::ShouldFailWithOOM()) {
return false;
}
// 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) {
// On either Windows or POSIX we can't be sure if id_ was initalisad. So
// reset it manually.
id_ = ThreadId();
return false;
}
id_.platformData()->handle = reinterpret_cast<HANDLE>(handle);
return true;
}
void 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_ = ThreadId();
}
void Thread::detach() {
MOZ_RELEASE_ASSERT(joinable());
BOOL success = CloseHandle(id_.platformData()->handle);
MOZ_RELEASE_ASSERT(success);
id_ = ThreadId();
}
ThreadId ThreadId::ThisThreadId() {
ThreadId id;
id.platformData()->handle = GetCurrentThread();
id.platformData()->id = GetCurrentThreadId();
MOZ_RELEASE_ASSERT(id != ThreadId());
return id;
}
void 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 // _MSC_VER
}
void ThisThread::GetName(char* nameBuffer, size_t len) {
MOZ_RELEASE_ASSERT(len > 0);
*nameBuffer = '\0';
}
void ThisThread::SleepMilliseconds(size_t ms) {
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
}
} // namespace js
|