Line data Source code
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 <new>
10 : #include <pthread.h>
11 : #include <stdlib.h>
12 : #include <string.h>
13 :
14 : #if defined(__APPLE__) && defined(__MACH__)
15 : #include <dlfcn.h>
16 : #endif
17 :
18 : #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
19 : #include <pthread_np.h>
20 : #endif
21 :
22 : #if defined(__linux__)
23 : #include <sys/prctl.h>
24 : #endif
25 :
26 : #include "threading/Thread.h"
27 :
28 : class js::Thread::Id::PlatformData
29 : {
30 : friend class js::Thread;
31 : friend js::Thread::Id js::ThisThread::GetId();
32 :
33 : pthread_t ptThread;
34 :
35 : // pthread_t does not have a default initializer, so we have to carry a bool
36 : // to tell whether it is safe to compare or not.
37 : bool hasThread;
38 : };
39 :
40 : /* static */ js::HashNumber
41 0 : js::Thread::Hasher::hash(const Lookup& l)
42 : {
43 0 : return mozilla::HashBytes(&l.platformData()->ptThread, sizeof(pthread_t));
44 : }
45 :
46 : inline js::Thread::Id::PlatformData*
47 5850580 : js::Thread::Id::platformData()
48 : {
49 : static_assert(sizeof platformData_ >= sizeof(PlatformData),
50 : "platformData_ is too small");
51 5850580 : return reinterpret_cast<PlatformData*>(platformData_);
52 : }
53 :
54 : inline const js::Thread::Id::PlatformData*
55 3895148 : js::Thread::Id::platformData() const
56 : {
57 : static_assert(sizeof platformData_ >= sizeof(PlatformData),
58 : "platformData_ is too small");
59 3895148 : return reinterpret_cast<const PlatformData*>(platformData_);
60 : }
61 :
62 1950412 : js::Thread::Id::Id()
63 : {
64 1950412 : platformData()->hasThread = false;
65 1950409 : }
66 :
67 : bool
68 1947594 : js::Thread::Id::operator==(const Id& aOther) const
69 : {
70 1947594 : const PlatformData& self = *platformData();
71 1947594 : const PlatformData& other = *aOther.platformData();
72 5842458 : return (!self.hasThread && !other.hasThread) ||
73 3894926 : (self.hasThread == other.hasThread &&
74 3895035 : pthread_equal(self.ptThread, other.ptThread));
75 : }
76 :
77 72 : js::Thread::Thread(Thread&& aOther)
78 : {
79 72 : id_ = aOther.id_;
80 72 : aOther.id_ = Id();
81 72 : options_ = aOther.options_;
82 72 : }
83 :
84 : js::Thread&
85 0 : js::Thread::operator=(Thread&& aOther)
86 : {
87 0 : MOZ_RELEASE_ASSERT(!joinable());
88 0 : id_ = aOther.id_;
89 0 : aOther.id_ = Id();
90 0 : options_ = aOther.options_;
91 0 : return *this;
92 : }
93 :
94 : bool
95 36 : js::Thread::create(void* (*aMain)(void*), void* aArg)
96 : {
97 : pthread_attr_t attrs;
98 36 : int r = pthread_attr_init(&attrs);
99 36 : MOZ_RELEASE_ASSERT(!r);
100 36 : if (options_.stackSize()) {
101 36 : r = pthread_attr_setstacksize(&attrs, options_.stackSize());
102 36 : MOZ_RELEASE_ASSERT(!r);
103 : }
104 36 : r = pthread_create(&id_.platformData()->ptThread, &attrs, aMain, aArg);
105 36 : if (r) {
106 : // |pthread_create| may leave id_ in an undefined state.
107 0 : id_ = Id();
108 0 : return false;
109 : }
110 36 : id_.platformData()->hasThread = true;
111 36 : return true;
112 : }
113 :
114 : void
115 0 : js::Thread::join()
116 : {
117 0 : MOZ_RELEASE_ASSERT(joinable());
118 0 : int r = pthread_join(id_.platformData()->ptThread, nullptr);
119 0 : MOZ_RELEASE_ASSERT(!r);
120 0 : id_ = Id();
121 0 : }
122 :
123 : void
124 0 : js::Thread::detach()
125 : {
126 0 : MOZ_RELEASE_ASSERT(joinable());
127 0 : int r = pthread_detach(id_.platformData()->ptThread);
128 0 : MOZ_RELEASE_ASSERT(!r);
129 0 : id_ = Id();
130 0 : }
131 :
132 : js::Thread::Id
133 1950123 : js::ThisThread::GetId()
134 : {
135 1950123 : js::Thread::Id id;
136 1950120 : id.platformData()->ptThread = pthread_self();
137 1950114 : id.platformData()->hasThread = true;
138 1950177 : return id;
139 : }
140 :
141 : void
142 35 : js::ThisThread::SetName(const char* name)
143 : {
144 35 : MOZ_RELEASE_ASSERT(name);
145 :
146 : #if (defined(__APPLE__) && defined(__MACH__)) || defined(__linux__)
147 : // On linux and OS X the name may not be longer than 16 bytes, including
148 : // the null terminator. Truncate the name to 15 characters.
149 : char nameBuf[16];
150 :
151 35 : strncpy(nameBuf, name, sizeof nameBuf - 1);
152 35 : nameBuf[sizeof nameBuf - 1] = '\0';
153 35 : name = nameBuf;
154 : #endif
155 :
156 : int rv;
157 : #ifdef XP_DARWIN
158 : rv = pthread_setname_np(name);
159 : #elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
160 : pthread_set_name_np(pthread_self(), name);
161 : rv = 0;
162 : #elif defined(__NetBSD__)
163 : rv = pthread_setname_np(pthread_self(), "%s", (void*)name);
164 : #else
165 35 : rv = pthread_setname_np(pthread_self(), name);
166 : #endif
167 35 : MOZ_RELEASE_ASSERT(!rv);
168 35 : }
169 :
170 : void
171 0 : js::ThisThread::GetName(char* nameBuffer, size_t len)
172 : {
173 0 : MOZ_RELEASE_ASSERT(len >= 16);
174 :
175 0 : int rv = -1;
176 : #ifdef HAVE_PTHREAD_GETNAME_NP
177 0 : rv = pthread_getname_np(pthread_self(), nameBuffer, len);
178 : #elif defined(__linux__)
179 : rv = prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(nameBuffer));
180 : #endif
181 :
182 0 : if (rv)
183 0 : nameBuffer[0] = '\0';
184 0 : }
|