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 : // 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(OS_MACOSX)
13 : #include <mach/mach.h>
14 : #elif defined(OS_NETBSD)
15 : #include <lwp.h>
16 : #elif defined(OS_LINUX)
17 : #include <sys/syscall.h>
18 : #include <sys/prctl.h>
19 : #endif
20 :
21 : #if !defined(OS_MACOSX)
22 : #include <unistd.h>
23 : #endif
24 :
25 : #if defined(OS_BSD) && !defined(OS_NETBSD) && !defined(__GLIBC__)
26 : #include <pthread_np.h>
27 : #endif
28 :
29 : #if defined(OS_MACOSX)
30 : namespace base {
31 : void InitThreading();
32 : } // namespace
33 : #endif
34 :
35 8 : static void* ThreadFunc(void* closure) {
36 : PlatformThread::Delegate* delegate =
37 8 : static_cast<PlatformThread::Delegate*>(closure);
38 8 : delegate->ThreadMain();
39 0 : return NULL;
40 : }
41 :
42 : // static
43 10867 : PlatformThreadId PlatformThread::CurrentId() {
44 : // Pthreads doesn't have the concept of a thread ID, so we have to reach down
45 : // into the kernel.
46 : #if defined(OS_MACOSX)
47 : mach_port_t port = mach_thread_self();
48 : mach_port_deallocate(mach_task_self(), port);
49 : return port;
50 : #elif defined(OS_LINUX)
51 : #ifdef MOZ_WIDGET_GONK
52 : return (intptr_t) (pthread_self());
53 : #else
54 10867 : return syscall(__NR_gettid);
55 : #endif
56 : #elif defined(OS_OPENBSD) || defined(OS_SOLARIS) || defined(__GLIBC__)
57 : return (intptr_t) (pthread_self());
58 : #elif defined(OS_NETBSD)
59 : return _lwp_self();
60 : #elif defined(OS_DRAGONFLY)
61 : return lwp_gettid();
62 : #elif defined(OS_FREEBSD)
63 : return pthread_getthreadid_np();
64 : #endif
65 : }
66 :
67 : // static
68 0 : void PlatformThread::YieldCurrentThread() {
69 0 : sched_yield();
70 0 : }
71 :
72 : // static
73 0 : void PlatformThread::Sleep(int duration_ms) {
74 : struct timespec sleep_time, remaining;
75 :
76 : // Contains the portion of duration_ms >= 1 sec.
77 0 : sleep_time.tv_sec = duration_ms / 1000;
78 0 : duration_ms -= sleep_time.tv_sec * 1000;
79 :
80 : // Contains the portion of duration_ms < 1 sec.
81 0 : sleep_time.tv_nsec = duration_ms * 1000 * 1000; // nanoseconds.
82 :
83 0 : while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR)
84 0 : sleep_time = remaining;
85 0 : }
86 :
87 : #ifndef OS_MACOSX
88 : // Mac is implemented in platform_thread_mac.mm.
89 :
90 : // static
91 8 : void PlatformThread::SetName(const char* name) {
92 : // On linux we can get the thread names to show up in the debugger by setting
93 : // the process name for the LWP. We don't want to do this for the main
94 : // thread because that would rename the process, causing tools like killall
95 : // to stop working.
96 8 : if (PlatformThread::CurrentId() == getpid())
97 0 : return;
98 :
99 : // http://0pointer.de/blog/projects/name-your-threads.html
100 : // Set the name for the LWP (which gets truncated to 15 characters).
101 : // Note that glibc also has a 'pthread_setname_np' api, but it may not be
102 : // available everywhere and it's only benefit over using prctl directly is
103 : // that it can set the name of threads other than the current thread.
104 : #if defined(OS_LINUX)
105 8 : prctl(PR_SET_NAME, reinterpret_cast<uintptr_t>(name), 0, 0, 0);
106 : #elif defined(OS_NETBSD)
107 : pthread_setname_np(pthread_self(), "%s", (void *)name);
108 : #elif defined(OS_BSD) && !defined(__GLIBC__)
109 : pthread_set_name_np(pthread_self(), name);
110 : #elif defined(OS_SOLARIS)
111 : pthread_setname_np(pthread_self(), name);
112 : #else
113 : #endif
114 : }
115 : #endif // !OS_MACOSX
116 :
117 : namespace {
118 :
119 8 : bool CreateThread(size_t stack_size, bool joinable,
120 : PlatformThread::Delegate* delegate,
121 : PlatformThreadHandle* thread_handle) {
122 : #if defined(OS_MACOSX)
123 : base::InitThreading();
124 : #endif // OS_MACOSX
125 :
126 8 : bool success = false;
127 : pthread_attr_t attributes;
128 8 : pthread_attr_init(&attributes);
129 :
130 : // Pthreads are joinable by default, so only specify the detached attribute if
131 : // the thread should be non-joinable.
132 8 : if (!joinable) {
133 0 : pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
134 : }
135 :
136 8 : if (stack_size > 0)
137 0 : pthread_attr_setstacksize(&attributes, stack_size);
138 :
139 8 : success = !pthread_create(thread_handle, &attributes, ThreadFunc, delegate);
140 :
141 8 : pthread_attr_destroy(&attributes);
142 8 : return success;
143 : }
144 :
145 : } // anonymous namespace
146 :
147 : // static
148 8 : bool PlatformThread::Create(size_t stack_size, Delegate* delegate,
149 : PlatformThreadHandle* thread_handle) {
150 : return CreateThread(stack_size, true /* joinable thread */,
151 8 : delegate, thread_handle);
152 : }
153 :
154 : // static
155 0 : bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
156 : PlatformThreadHandle unused;
157 :
158 : bool result = CreateThread(stack_size, false /* non-joinable thread */,
159 0 : delegate, &unused);
160 0 : return result;
161 : }
162 :
163 : // static
164 0 : void PlatformThread::Join(PlatformThreadHandle thread_handle) {
165 0 : pthread_join(thread_handle, NULL);
166 0 : }
|