PosixThread.cpp (4214B)
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 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 24 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 30 ThreadId::ThreadId() { platformData()->hasThread = false; } 31 32 ThreadId::operator bool() const { return platformData()->hasThread; } 33 34 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 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 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 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 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 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 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 142 void ThisThread::SleepMilliseconds(size_t ms) { 143 std::this_thread::sleep_for(std::chrono::milliseconds(ms)); 144 } 145 146 } // namespace js