platform_thread_posix.cc (4348B)
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 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style license that can be 5 // found in the LICENSE file. 6 7 #include "base/platform_thread.h" 8 9 #include <errno.h> 10 #include <sched.h> 11 12 #if defined(XP_DARWIN) 13 # include <mach/mach.h> 14 #elif defined(XP_NETBSD) 15 # include <lwp.h> 16 #elif defined(XP_LINUX) 17 # include <sys/syscall.h> 18 # include <sys/prctl.h> 19 #endif 20 21 #if !defined(XP_DARWIN) 22 # include <unistd.h> 23 #endif 24 25 #if (defined(__DragonFly__) || defined(XP_FREEBSD) || defined(XP_OPENBSD)) && \ 26 !defined(__GLIBC__) 27 # include <pthread_np.h> 28 #endif 29 30 #include "nsThreadUtils.h" 31 32 #if defined(XP_DARWIN) 33 namespace base { 34 void InitThreading(); 35 } // namespace base 36 #endif 37 38 static void* ThreadFunc(void* closure) { 39 PlatformThread::Delegate* delegate = 40 static_cast<PlatformThread::Delegate*>(closure); 41 delegate->ThreadMain(); 42 return NULL; 43 } 44 45 // static 46 PlatformThreadId PlatformThread::CurrentId() { 47 // Pthreads doesn't have the concept of a thread ID, so we have to reach down 48 // into the kernel. 49 #if defined(XP_DARWIN) 50 mach_port_t port = mach_thread_self(); 51 mach_port_deallocate(mach_task_self(), port); 52 return port; 53 #elif defined(XP_LINUX) 54 return syscall(__NR_gettid); 55 #elif defined(XP_OPENBSD) || defined(XP_SOLARIS) || defined(__GLIBC__) 56 return (intptr_t)(pthread_self()); 57 #elif defined(XP_NETBSD) 58 return _lwp_self(); 59 #elif defined(__DragonFly__) 60 return lwp_gettid(); 61 #elif defined(XP_FREEBSD) 62 return pthread_getthreadid_np(); 63 #endif 64 } 65 66 // static 67 void PlatformThread::YieldCurrentThread() { sched_yield(); } 68 69 // static 70 void PlatformThread::Sleep(int duration_ms) { 71 struct timespec sleep_time, remaining; 72 73 // Contains the portion of duration_ms >= 1 sec. 74 sleep_time.tv_sec = duration_ms / 1000; 75 duration_ms -= sleep_time.tv_sec * 1000; 76 77 // Contains the portion of duration_ms < 1 sec. 78 sleep_time.tv_nsec = duration_ms * 1000 * 1000; // nanoseconds. 79 80 while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR) 81 sleep_time = remaining; 82 } 83 84 #ifndef XP_DARWIN 85 // Mac is implemented in platform_thread_mac.mm. 86 87 // static 88 void PlatformThread::SetName(const char* name) { 89 // On linux we can get the thread names to show up in the debugger by setting 90 // the process name for the LWP. We don't want to do this for the main 91 // thread because that would rename the process, causing tools like killall 92 // to stop working. 93 if (PlatformThread::CurrentId() == getpid()) return; 94 95 // Using NS_SetCurrentThreadName, as opposed to using platform APIs directly, 96 // also sets the thread name on the PRThread wrapper, and allows us to 97 // retrieve it using PR_GetThreadName. 98 NS_SetCurrentThreadName(name); 99 } 100 #endif // !XP_DARWIN 101 102 namespace { 103 104 bool CreateThread(size_t stack_size, bool joinable, 105 PlatformThread::Delegate* delegate, 106 PlatformThreadHandle* thread_handle) { 107 #if defined(XP_DARWIN) 108 base::InitThreading(); 109 #endif // XP_DARWIN 110 111 bool success = false; 112 pthread_attr_t attributes; 113 pthread_attr_init(&attributes); 114 115 // Pthreads are joinable by default, so only specify the detached attribute if 116 // the thread should be non-joinable. 117 if (!joinable) { 118 pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED); 119 } 120 121 if (stack_size == 0) stack_size = nsIThreadManager::DEFAULT_STACK_SIZE; 122 pthread_attr_setstacksize(&attributes, stack_size); 123 124 success = !pthread_create(thread_handle, &attributes, ThreadFunc, delegate); 125 126 pthread_attr_destroy(&attributes); 127 return success; 128 } 129 130 } // anonymous namespace 131 132 // static 133 bool PlatformThread::Create(size_t stack_size, Delegate* delegate, 134 PlatformThreadHandle* thread_handle) { 135 return CreateThread(stack_size, true /* joinable thread */, delegate, 136 thread_handle); 137 } 138 139 // static 140 bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) { 141 PlatformThreadHandle unused; 142 143 bool result = CreateThread(stack_size, false /* non-joinable thread */, 144 delegate, &unused); 145 return result; 146 } 147 148 // static 149 void PlatformThread::Join(PlatformThreadHandle thread_handle) { 150 pthread_join(thread_handle, NULL); 151 }