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 "mozilla/Assertions.h"
8 
9 #include <chrono>
10 #include <thread>
11 
12 #include "js/Utility.h"
13 #include "threading/posix/ThreadPlatformData.h"
14 #include "threading/Thread.h"
15 
16 namespace js {
17 
platformData()18 inline ThreadId::PlatformData* ThreadId::platformData() {
19   static_assert(sizeof platformData_ >= sizeof(PlatformData),
20                 "platformData_ is too small");
21   return reinterpret_cast<PlatformData*>(platformData_);
22 }
23 
platformData() const24 inline const ThreadId::PlatformData* ThreadId::platformData() const {
25   static_assert(sizeof platformData_ >= sizeof(PlatformData),
26                 "platformData_ is too small");
27   return reinterpret_cast<const PlatformData*>(platformData_);
28 }
29 
ThreadId()30 ThreadId::ThreadId() { platformData()->hasThread = false; }
31 
operator bool() const32 ThreadId::operator bool() const { return platformData()->hasThread; }
33 
operator ==(const ThreadId & aOther) const34 bool ThreadId::operator==(const ThreadId& aOther) const {
35   const PlatformData& self = *platformData();
36   const PlatformData& other = *aOther.platformData();
37   return (!self.hasThread && !other.hasThread) ||
38          (self.hasThread == other.hasThread &&
39           pthread_equal(self.ptThread, other.ptThread));
40 }
41 
create(void * (* aMain)(void *),void * aArg)42 bool Thread::create(void* (*aMain)(void*), void* aArg) {
43   MOZ_RELEASE_ASSERT(!joinable());
44 
45   if (oom::ShouldFailWithOOM()) {
46     return false;
47   }
48 
49   pthread_attr_t attrs;
50   int r = pthread_attr_init(&attrs);
51   MOZ_RELEASE_ASSERT(!r);
52   if (options_.stackSize()) {
53     r = pthread_attr_setstacksize(&attrs, options_.stackSize());
54     MOZ_RELEASE_ASSERT(!r);
55   }
56 
57   r = pthread_create(&id_.platformData()->ptThread, &attrs, aMain, aArg);
58   if (r) {
59     // On either Windows or POSIX we can't be sure if id_ was initialised. So
60     // reset it manually.
61     id_ = ThreadId();
62     return false;
63   }
64   id_.platformData()->hasThread = true;
65   return true;
66 }
67 
join()68 void Thread::join() {
69   MOZ_RELEASE_ASSERT(joinable());
70   int r = pthread_join(id_.platformData()->ptThread, nullptr);
71   MOZ_RELEASE_ASSERT(!r);
72   id_ = ThreadId();
73 }
74 
detach()75 void Thread::detach() {
76   MOZ_RELEASE_ASSERT(joinable());
77   int r = pthread_detach(id_.platformData()->ptThread);
78   MOZ_RELEASE_ASSERT(!r);
79   id_ = ThreadId();
80 }
81 
ThisThreadId()82 ThreadId ThreadId::ThisThreadId() {
83   ThreadId id;
84   id.platformData()->ptThread = pthread_self();
85   id.platformData()->hasThread = true;
86   MOZ_RELEASE_ASSERT(id != ThreadId());
87   return id;
88 }
89 
SetName(const char * name)90 void ThisThread::SetName(const char* name) {
91   MOZ_RELEASE_ASSERT(name);
92 
93 #if (defined(__APPLE__) && defined(__MACH__)) || defined(__linux__)
94 #  if defined(XP_DARWIN)
95   // Mac OS X has a length limit of 63 characters, but there is no API
96   // exposing it.
97 #    define SETNAME_LENGTH_CONSTRAINT 63
98 #  else
99   // On linux the name may not be longer than 16 bytes, including
100   // the null terminator. Truncate the name to 15 characters.
101 #    define SETNAME_LENGTH_CONSTRAINT 15
102 #  endif
103   char nameBuf[SETNAME_LENGTH_CONSTRAINT + 1];
104 
105   strncpy(nameBuf, name, sizeof nameBuf - 1);
106   nameBuf[sizeof nameBuf - 1] = '\0';
107   name = nameBuf;
108 #endif
109 
110   int rv;
111 #ifdef XP_DARWIN
112   rv = pthread_setname_np(name);
113 #elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
114   pthread_set_name_np(pthread_self(), name);
115   rv = 0;
116 #elif defined(__NetBSD__)
117   rv = pthread_setname_np(pthread_self(), "%s", (void*)name);
118 #else
119   rv = pthread_setname_np(pthread_self(), name);
120 #endif
121   MOZ_RELEASE_ASSERT(!rv);
122 }
123 
GetName(char * nameBuffer,size_t len)124 void ThisThread::GetName(char* nameBuffer, size_t len) {
125   MOZ_RELEASE_ASSERT(len >= 16);
126 
127   int rv = -1;
128 #ifdef HAVE_PTHREAD_GETNAME_NP
129   rv = pthread_getname_np(pthread_self(), nameBuffer, len);
130 #elif defined(HAVE_PTHREAD_GET_NAME_NP)
131   pthread_get_name_np(pthread_self(), nameBuffer, len);
132   rv = 0;
133 #elif defined(__linux__)
134   rv = prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(nameBuffer));
135 #endif
136 
137   if (rv) {
138     nameBuffer[0] = '\0';
139   }
140 }
141 
SleepMilliseconds(size_t ms)142 void ThisThread::SleepMilliseconds(size_t ms) {
143   std::this_thread::sleep_for(std::chrono::milliseconds(ms));
144 }
145 
146 }  // namespace js
147