platform_thread_posix.cc revision 3f50c38dc070f4bb515c1b64450dae14f316474e
1// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/threading/platform_thread.h"
6
7#include <errno.h>
8#include <sched.h>
9
10#include "base/logging.h"
11#include "base/safe_strerror_posix.h"
12#include "base/scoped_ptr.h"
13#include "base/threading/thread_restrictions.h"
14
15#if defined(OS_MACOSX)
16#include <mach/mach.h>
17#include <sys/resource.h>
18#include <algorithm>
19#endif
20
21#if defined(OS_LINUX)
22#include <dlfcn.h>
23#include <sys/prctl.h>
24#include <sys/syscall.h>
25#include <unistd.h>
26#endif
27
28#if defined(OS_NACL)
29#include <sys/nacl_syscalls.h>
30#endif
31
32namespace base {
33
34#if defined(OS_MACOSX)
35void InitThreading();
36#endif
37
38namespace {
39
40struct ThreadParams {
41  PlatformThread::Delegate* delegate;
42  bool joinable;
43};
44
45void* ThreadFunc(void* params) {
46  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;
51  delegate->ThreadMain();
52  return NULL;
53}
54
55bool 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
119// static
120PlatformThreadId PlatformThread::CurrentId() {
121  // 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)
124  return mach_thread_self();
125#elif defined(OS_LINUX)
126  return syscall(__NR_gettid);
127#elif defined(OS_FREEBSD)
128  // TODO(BSD): find a better thread ID
129  return reinterpret_cast<int64>(pthread_self());
130#elif defined(OS_NACL)
131  return pthread_self();
132#endif
133}
134
135// 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
155// 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)
160// static
161void PlatformThread::SetName(const char* name) {
162  // 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  }
187}
188#elif defined(OS_MACOSX)
189// Mac is implemented in platform_thread_mac.mm.
190#else
191// static
192void PlatformThread::SetName(const char* name) {
193  // 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)
199
200// 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
216// static
217void PlatformThread::Join(PlatformThreadHandle thread_handle) {
218  // 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();
222  pthread_join(thread_handle, NULL);
223}
224
225}  // namespace base
226