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