blob: 497acb5efdf7787ea03cace75b0c398931029a0e [file] [log] [blame]
levin@chromium.org5c528682011-03-28 10:54:15 +09001// Copyright (c) 2011 The Chromium Authors. All rights reserved.
license.botf003cfe2008-08-24 09:55:55 +09002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit3f4a7322008-07-27 06:49:38 +09004
brettw@chromium.org61391822011-01-01 05:02:16 +09005#include "base/threading/platform_thread.h"
brettw@google.come3c034a2008-08-08 03:31:40 +09006
paulg@google.comc8eeb752008-08-13 10:20:26 +09007#include <errno.h>
deanm@google.comc1c5cf52008-08-06 19:06:59 +09008#include <sched.h>
deanm@google.comc1c5cf52008-08-06 19:06:59 +09009
willchan@chromium.org25726ef2010-11-20 05:34:18 +090010#include "base/logging.h"
levin@chromium.org5c528682011-03-28 10:54:15 +090011#include "base/memory/scoped_ptr.h"
willchan@chromium.org25726ef2010-11-20 05:34:18 +090012#include "base/safe_strerror_posix.h"
brettw@chromium.org5b5f5e02011-01-01 10:01:06 +090013#include "base/threading/thread_restrictions.h"
willchan@chromium.org25726ef2010-11-20 05:34:18 +090014
pinkerton@google.com44159e42008-08-14 08:20:03 +090015#if defined(OS_MACOSX)
16#include <mach/mach.h>
mark@chromium.org74c06442010-05-08 03:30:01 +090017#include <sys/resource.h>
18#include <algorithm>
evan@chromium.orgb1fe13a2010-06-11 07:55:17 +090019#endif
20
21#if defined(OS_LINUX)
abarth@chromium.orga6ffcf42010-11-13 02:59:41 +090022#include <dlfcn.h>
evan@chromium.orgb1fe13a2010-06-11 07:55:17 +090023#include <sys/prctl.h>
tc@google.com0e5744d2008-08-14 08:55:02 +090024#include <sys/syscall.h>
pinkerton@google.com9d2fd8a2008-08-14 08:34:26 +090025#include <unistd.h>
pinkerton@google.com44159e42008-08-14 08:20:03 +090026#endif
27
abarth@chromium.orga6ffcf42010-11-13 02:59:41 +090028#if defined(OS_NACL)
29#include <sys/nacl_syscalls.h>
30#endif
31
mmentovai@google.com4304cf92008-08-28 10:17:02 +090032namespace base {
brettw@chromium.org61391822011-01-01 05:02:16 +090033
34#if defined(OS_MACOSX)
mmentovai@google.com4304cf92008-08-28 10:17:02 +090035void InitThreading();
mmentovai@google.com4304cf92008-08-28 10:17:02 +090036#endif
37
willchan@chromium.org25726ef2010-11-20 05:34:18 +090038namespace {
39
40struct ThreadParams {
41 PlatformThread::Delegate* delegate;
42 bool joinable;
43};
44
brettw@chromium.org61391822011-01-01 05:02:16 +090045void* ThreadFunc(void* params) {
willchan@chromium.org25726ef2010-11-20 05:34:18 +090046 ThreadParams* thread_params = static_cast<ThreadParams*>(params);
47 PlatformThread::Delegate* delegate = thread_params->delegate;
48 if (!thread_params->joinable)
49 base::ThreadRestrictions::SetSingletonAllowed(false);
50 delete thread_params;
maruel@chromium.org8fe7adc2009-03-04 00:01:12 +090051 delegate->ThreadMain();
darin@google.comc18d7ae2008-08-21 18:46:32 +090052 return NULL;
paulg@google.comc8eeb752008-08-13 10:20:26 +090053}
54
brettw@chromium.org61391822011-01-01 05:02:16 +090055bool CreateThread(size_t stack_size, bool joinable,
56 PlatformThread::Delegate* delegate,
57 PlatformThreadHandle* thread_handle) {
58#if defined(OS_MACOSX)
59 base::InitThreading();
60#endif // OS_MACOSX
61
62 bool success = false;
63 pthread_attr_t attributes;
64 pthread_attr_init(&attributes);
65
66 // Pthreads are joinable by default, so only specify the detached attribute if
67 // the thread should be non-joinable.
68 if (!joinable) {
69 pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
70 }
71
72#if defined(OS_MACOSX)
73 // The Mac OS X default for a pthread stack size is 512kB.
74 // Libc-594.1.4/pthreads/pthread.c's pthread_attr_init uses
75 // DEFAULT_STACK_SIZE for this purpose.
76 //
77 // 512kB isn't quite generous enough for some deeply recursive threads that
78 // otherwise request the default stack size by specifying 0. Here, adopt
79 // glibc's behavior as on Linux, which is to use the current stack size
80 // limit (ulimit -s) as the default stack size. See
81 // glibc-2.11.1/nptl/nptl-init.c's __pthread_initialize_minimal_internal. To
82 // avoid setting the limit below the Mac OS X default or the minimum usable
83 // stack size, these values are also considered. If any of these values
84 // can't be determined, or if stack size is unlimited (ulimit -s unlimited),
85 // stack_size is left at 0 to get the system default.
86 //
87 // Mac OS X normally only applies ulimit -s to the main thread stack. On
88 // contemporary OS X and Linux systems alike, this value is generally 8MB
89 // or in that neighborhood.
90 if (stack_size == 0) {
91 size_t default_stack_size;
92 struct rlimit stack_rlimit;
93 if (pthread_attr_getstacksize(&attributes, &default_stack_size) == 0 &&
94 getrlimit(RLIMIT_STACK, &stack_rlimit) == 0 &&
95 stack_rlimit.rlim_cur != RLIM_INFINITY) {
96 stack_size = std::max(std::max(default_stack_size,
97 static_cast<size_t>(PTHREAD_STACK_MIN)),
98 static_cast<size_t>(stack_rlimit.rlim_cur));
99 }
100 }
101#endif // OS_MACOSX
102
103 if (stack_size > 0)
104 pthread_attr_setstacksize(&attributes, stack_size);
105
106 ThreadParams* params = new ThreadParams;
107 params->delegate = delegate;
108 params->joinable = joinable;
109 success = !pthread_create(thread_handle, &attributes, ThreadFunc, params);
110
111 pthread_attr_destroy(&attributes);
112 if (!success)
113 delete params;
114 return success;
115}
116
117} // namespace
118
pinkerton@google.com44159e42008-08-14 08:20:03 +0900119// static
agl@chromium.org118a98a2009-01-23 09:25:29 +0900120PlatformThreadId PlatformThread::CurrentId() {
darin@google.comc18d7ae2008-08-21 18:46:32 +0900121 // Pthreads doesn't have the concept of a thread ID, so we have to reach down
122 // into the kernel.
123#if defined(OS_MACOSX)
pinkerton@google.com44159e42008-08-14 08:20:03 +0900124 return mach_thread_self();
125#elif defined(OS_LINUX)
tc@google.com0e5744d2008-08-14 08:55:02 +0900126 return syscall(__NR_gettid);
evan@chromium.org875bb6e2009-12-29 09:32:52 +0900127#elif defined(OS_FREEBSD)
128 // TODO(BSD): find a better thread ID
129 return reinterpret_cast<int64>(pthread_self());
chromium@hybridsource.org8f85a6a2011-06-25 13:54:41 +0900130#elif defined(OS_NACL) || defined(OS_SOLARIS)
abarth@chromium.orga6ffcf42010-11-13 02:59:41 +0900131 return pthread_self();
pinkerton@google.com44159e42008-08-14 08:20:03 +0900132#endif
133}
134
darin@google.comc18d7ae2008-08-21 18:46:32 +0900135// static
136void PlatformThread::YieldCurrentThread() {
137 sched_yield();
138}
139
140// static
141void PlatformThread::Sleep(int duration_ms) {
142 struct timespec sleep_time, remaining;
143
144 // Contains the portion of duration_ms >= 1 sec.
145 sleep_time.tv_sec = duration_ms / 1000;
146 duration_ms -= sleep_time.tv_sec * 1000;
147
148 // Contains the portion of duration_ms < 1 sec.
149 sleep_time.tv_nsec = duration_ms * 1000 * 1000; // nanoseconds.
150
151 while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR)
152 sleep_time = remaining;
153}
154
evan@chromium.orgb1fe13a2010-06-11 07:55:17 +0900155// Linux SetName is currently disabled, as we need to distinguish between
156// helper threads (where it's ok to make this call) and the main thread
157// (where making this call renames our process, causing tools like killall
158// to stop working).
159#if 0 && defined(OS_LINUX)
darin@google.comc18d7ae2008-08-21 18:46:32 +0900160// static
deanm@google.com8f4440a2008-08-25 22:54:18 +0900161void PlatformThread::SetName(const char* name) {
evan@chromium.orgb1fe13a2010-06-11 07:55:17 +0900162 // http://0pointer.de/blog/projects/name-your-threads.html
163
164 // glibc recently added support for pthread_setname_np, but it's not
165 // commonly available yet. So test for it at runtime.
166 int (*dynamic_pthread_setname_np)(pthread_t, const char*);
167 *reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
168 dlsym(RTLD_DEFAULT, "pthread_setname_np");
169
170 if (dynamic_pthread_setname_np) {
171 // This limit comes from glibc, which gets it from the kernel
172 // (TASK_COMM_LEN).
173 const int kMaxNameLength = 15;
174 std::string shortened_name = std::string(name).substr(0, kMaxNameLength);
175 int err = dynamic_pthread_setname_np(pthread_self(),
176 shortened_name.c_str());
177 if (err < 0)
178 LOG(ERROR) << "pthread_setname_np: " << safe_strerror(err);
179 } else {
180 // Implementing this function without glibc is simple enough. (We
181 // don't do the name length clipping as above because it will be
182 // truncated by the callee (see TASK_COMM_LEN above).)
183 int err = prctl(PR_SET_NAME, name);
184 if (err < 0)
185 PLOG(ERROR) << "prctl(PR_SET_NAME)";
186 }
darin@google.comc18d7ae2008-08-21 18:46:32 +0900187}
evan@chromium.orgb1fe13a2010-06-11 07:55:17 +0900188#elif defined(OS_MACOSX)
189// Mac is implemented in platform_thread_mac.mm.
190#else
191// static
joi@chromium.org5444bec2011-02-25 11:18:13 +0900192void PlatformThread::SetName(const char* /*name*/) {
evan@chromium.orgb1fe13a2010-06-11 07:55:17 +0900193 // Leave it unimplemented.
194
195 // (This should be relatively simple to implement for the BSDs; I
196 // just don't have one handy to test the code on.)
197}
198#endif // defined(OS_LINUX)
darin@google.comc18d7ae2008-08-21 18:46:32 +0900199
willchan@chromium.orgaf614742009-03-06 08:23:59 +0900200// static
201bool PlatformThread::Create(size_t stack_size, Delegate* delegate,
202 PlatformThreadHandle* thread_handle) {
203 return CreateThread(stack_size, true /* joinable thread */,
204 delegate, thread_handle);
205}
206
207// static
208bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
209 PlatformThreadHandle unused;
210
211 bool result = CreateThread(stack_size, false /* non-joinable thread */,
212 delegate, &unused);
213 return result;
214}
215
darin@google.comc18d7ae2008-08-21 18:46:32 +0900216// static
217void PlatformThread::Join(PlatformThreadHandle thread_handle) {
willchan@chromium.org354a52a2010-12-14 09:40:00 +0900218 // Joining another thread may block the current thread for a long time, since
219 // the thread referred to by |thread_handle| may still be running long-lived /
220 // blocking tasks.
221 base::ThreadRestrictions::AssertIOAllowed();
darin@google.comc18d7ae2008-08-21 18:46:32 +0900222 pthread_join(thread_handle, NULL);
initial.commit3f4a7322008-07-27 06:49:38 +0900223}
brettw@chromium.org61391822011-01-01 05:02:16 +0900224
crogers@google.coma6ec4f82011-05-18 05:01:25 +0900225#if !defined(OS_MACOSX)
226// Mac OS X uses lower-level mach APIs
227
228// static
229void PlatformThread::SetThreadPriority(PlatformThreadHandle, ThreadPriority) {
230 // TODO(crogers): implement
231 NOTIMPLEMENTED();
232}
233#endif
234
brettw@chromium.org61391822011-01-01 05:02:16 +0900235} // namespace base