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 "js/Utility.h"
10 #include "threading/posix/ThreadPlatformData.h"
11 #include "threading/Thread.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() { platformData()->hasThread = false; }
28 
operator ==(const ThreadId & aOther) const29 bool ThreadId::operator==(const ThreadId& aOther) const {
30   const PlatformData& self = *platformData();
31   const PlatformData& other = *aOther.platformData();
32   return (!self.hasThread && !other.hasThread) ||
33          (self.hasThread == other.hasThread &&
34           pthread_equal(self.ptThread, other.ptThread));
35 }
36 
create(void * (* aMain)(void *),void * aArg)37 bool Thread::create(void* (*aMain)(void*), void* aArg) {
38   MOZ_RELEASE_ASSERT(!joinable());
39 
40   if (oom::ShouldFailWithOOM()) {
41     return false;
42   }
43 
44   pthread_attr_t attrs;
45   int r = pthread_attr_init(&attrs);
46   MOZ_RELEASE_ASSERT(!r);
47   if (options_.stackSize()) {
48     r = pthread_attr_setstacksize(&attrs, options_.stackSize());
49     MOZ_RELEASE_ASSERT(!r);
50   }
51 
52   r = pthread_create(&id_.platformData()->ptThread, &attrs, aMain, aArg);
53   if (r) {
54     // On either Windows or POSIX we can't be sure if id_ was initialised. So
55     // reset it manually.
56     id_ = ThreadId();
57     return false;
58   }
59   id_.platformData()->hasThread = true;
60   return true;
61 }
62 
join()63 void Thread::join() {
64   MOZ_RELEASE_ASSERT(joinable());
65   int r = pthread_join(id_.platformData()->ptThread, nullptr);
66   MOZ_RELEASE_ASSERT(!r);
67   id_ = ThreadId();
68 }
69 
detach()70 void Thread::detach() {
71   MOZ_RELEASE_ASSERT(joinable());
72   int r = pthread_detach(id_.platformData()->ptThread);
73   MOZ_RELEASE_ASSERT(!r);
74   id_ = ThreadId();
75 }
76 
ThisThreadId()77 ThreadId ThreadId::ThisThreadId() {
78   ThreadId id;
79   id.platformData()->ptThread = pthread_self();
80   id.platformData()->hasThread = true;
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 #if (defined(__APPLE__) && defined(__MACH__)) || defined(__linux__)
89   // On linux and OS X the name may not be longer than 16 bytes, including
90   // the null terminator. Truncate the name to 15 characters.
91   char nameBuf[16];
92 
93   strncpy(nameBuf, name, sizeof nameBuf - 1);
94   nameBuf[sizeof nameBuf - 1] = '\0';
95   name = nameBuf;
96 #endif
97 
98   int rv;
99 #ifdef XP_DARWIN
100   rv = pthread_setname_np(name);
101 #elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
102   pthread_set_name_np(pthread_self(), name);
103   rv = 0;
104 #elif defined(__NetBSD__)
105   rv = pthread_setname_np(pthread_self(), "%s", (void*)name);
106 #else
107   rv = pthread_setname_np(pthread_self(), name);
108 #endif
109   MOZ_RELEASE_ASSERT(!rv);
110 }
111 
GetName(char * nameBuffer,size_t len)112 void ThisThread::GetName(char* nameBuffer, size_t len) {
113   MOZ_RELEASE_ASSERT(len >= 16);
114 
115   int rv = -1;
116 #ifdef HAVE_PTHREAD_GETNAME_NP
117   rv = pthread_getname_np(pthread_self(), nameBuffer, len);
118 #elif defined(HAVE_PTHREAD_GET_NAME_NP)
119   pthread_get_name_np(pthread_self(), nameBuffer, len);
120   rv = 0;
121 #elif defined(__linux__)
122   rv = prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(nameBuffer));
123 #endif
124 
125   if (rv) {
126     nameBuffer[0] = '\0';
127   }
128 }
129 
130 }  // namespace js
131