1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
53f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/platform_thread.h"
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <errno.h>
8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <sched.h>
9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
10201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include "base/logging.h"
11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h"
12201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include "base/safe_strerror_posix.h"
133f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread_restrictions.h"
14201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#if defined(OS_MACOSX)
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <mach/mach.h>
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <sys/resource.h>
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <algorithm>
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_LINUX)
224a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include <dlfcn.h>
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <sys/prctl.h>
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <sys/syscall.h>
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <unistd.h>
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
284a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#if defined(OS_NACL)
294a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include <sys/nacl_syscalls.h>
304a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#endif
314a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace base {
333f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
343f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#if defined(OS_MACOSX)
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid InitThreading();
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
38201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochnamespace {
39201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
40201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochstruct ThreadParams {
41201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  PlatformThread::Delegate* delegate;
42201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  bool joinable;
43201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch};
44201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
453f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid* ThreadFunc(void* params) {
46201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  ThreadParams* thread_params = static_cast<ThreadParams*>(params);
47201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  PlatformThread::Delegate* delegate = thread_params->delegate;
48201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (!thread_params->joinable)
49201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    base::ThreadRestrictions::SetSingletonAllowed(false);
50201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  delete thread_params;
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  delegate->ThreadMain();
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return NULL;
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
553f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenbool CreateThread(size_t stack_size, bool joinable,
563f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen                  PlatformThread::Delegate* delegate,
573f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen                  PlatformThreadHandle* thread_handle) {
583f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#if defined(OS_MACOSX)
593f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  base::InitThreading();
603f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#endif  // OS_MACOSX
613f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
623f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  bool success = false;
633f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  pthread_attr_t attributes;
643f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  pthread_attr_init(&attributes);
653f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
663f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // Pthreads are joinable by default, so only specify the detached attribute if
673f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // the thread should be non-joinable.
683f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  if (!joinable) {
693f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
703f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  }
713f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
723f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#if defined(OS_MACOSX)
733f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // The Mac OS X default for a pthread stack size is 512kB.
743f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // Libc-594.1.4/pthreads/pthread.c's pthread_attr_init uses
753f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // DEFAULT_STACK_SIZE for this purpose.
763f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  //
773f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // 512kB isn't quite generous enough for some deeply recursive threads that
783f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // otherwise request the default stack size by specifying 0. Here, adopt
793f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // glibc's behavior as on Linux, which is to use the current stack size
803f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // limit (ulimit -s) as the default stack size. See
813f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // glibc-2.11.1/nptl/nptl-init.c's __pthread_initialize_minimal_internal. To
823f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // avoid setting the limit below the Mac OS X default or the minimum usable
833f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // stack size, these values are also considered. If any of these values
843f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // can't be determined, or if stack size is unlimited (ulimit -s unlimited),
853f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // stack_size is left at 0 to get the system default.
863f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  //
873f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // Mac OS X normally only applies ulimit -s to the main thread stack. On
883f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // contemporary OS X and Linux systems alike, this value is generally 8MB
893f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // or in that neighborhood.
903f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  if (stack_size == 0) {
913f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    size_t default_stack_size;
923f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    struct rlimit stack_rlimit;
933f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    if (pthread_attr_getstacksize(&attributes, &default_stack_size) == 0 &&
943f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen        getrlimit(RLIMIT_STACK, &stack_rlimit) == 0 &&
953f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen        stack_rlimit.rlim_cur != RLIM_INFINITY) {
963f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      stack_size = std::max(std::max(default_stack_size,
973f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen                                     static_cast<size_t>(PTHREAD_STACK_MIN)),
983f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen                            static_cast<size_t>(stack_rlimit.rlim_cur));
993f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    }
1003f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  }
1013f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#endif  // OS_MACOSX
1023f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
1033f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  if (stack_size > 0)
1043f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    pthread_attr_setstacksize(&attributes, stack_size);
1053f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
1063f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  ThreadParams* params = new ThreadParams;
1073f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  params->delegate = delegate;
1083f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  params->joinable = joinable;
1093f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  success = !pthread_create(thread_handle, &attributes, ThreadFunc, params);
1103f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
1113f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  pthread_attr_destroy(&attributes);
1123f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  if (!success)
1133f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    delete params;
1143f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  return success;
1153f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen}
1163f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
1173f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen}  // namespace
1183f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottPlatformThreadId PlatformThread::CurrentId() {
121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Pthreads doesn't have the concept of a thread ID, so we have to reach down
122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // into the kernel.
123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#if defined(OS_MACOSX)
124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return mach_thread_self();
125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#elif defined(OS_LINUX)
126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return syscall(__NR_gettid);
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#elif defined(OS_FREEBSD)
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // TODO(BSD): find a better thread ID
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return reinterpret_cast<int64>(pthread_self());
1304a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#elif defined(OS_NACL)
1314a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return pthread_self();
132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif
133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid PlatformThread::YieldCurrentThread() {
137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  sched_yield();
138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid PlatformThread::Sleep(int duration_ms) {
142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  struct timespec sleep_time, remaining;
143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Contains the portion of duration_ms >= 1 sec.
145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  sleep_time.tv_sec = duration_ms / 1000;
146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  duration_ms -= sleep_time.tv_sec * 1000;
147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Contains the portion of duration_ms < 1 sec.
149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  sleep_time.tv_nsec = duration_ms * 1000 * 1000;  // nanoseconds.
150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR)
152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    sleep_time = remaining;
153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Linux SetName is currently disabled, as we need to distinguish between
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// helper threads (where it's ok to make this call) and the main thread
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// (where making this call renames our process, causing tools like killall
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// to stop working).
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if 0 && defined(OS_LINUX)
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PlatformThread::SetName(const char* name) {
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // http://0pointer.de/blog/projects/name-your-threads.html
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // glibc recently added support for pthread_setname_np, but it's not
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // commonly available yet.  So test for it at runtime.
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int (*dynamic_pthread_setname_np)(pthread_t, const char*);
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      dlsym(RTLD_DEFAULT, "pthread_setname_np");
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (dynamic_pthread_setname_np) {
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // This limit comes from glibc, which gets it from the kernel
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // (TASK_COMM_LEN).
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const int kMaxNameLength = 15;
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string shortened_name = std::string(name).substr(0, kMaxNameLength);
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int err = dynamic_pthread_setname_np(pthread_self(),
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         shortened_name.c_str());
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (err < 0)
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(ERROR) << "pthread_setname_np: " << safe_strerror(err);
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Implementing this function without glibc is simple enough.  (We
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // don't do the name length clipping as above because it will be
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // truncated by the callee (see TASK_COMM_LEN above).)
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int err = prctl(PR_SET_NAME, name);
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (err < 0)
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      PLOG(ERROR) << "prctl(PR_SET_NAME)";
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(OS_MACOSX)
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Mac is implemented in platform_thread_mac.mm.
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
192dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid PlatformThread::SetName(const char* /*name*/) {
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Leave it unimplemented.
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // (This should be relatively simple to implement for the BSDs; I
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // just don't have one handy to test the code on.)
197c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif  // defined(OS_LINUX)
199c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
200c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
201c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool PlatformThread::Create(size_t stack_size, Delegate* delegate,
202c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            PlatformThreadHandle* thread_handle) {
203c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return CreateThread(stack_size, true /* joinable thread */,
204c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                      delegate, thread_handle);
205c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
206c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
207c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
208c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
209c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  PlatformThreadHandle unused;
210c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
211c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool result = CreateThread(stack_size, false /* non-joinable thread */,
212c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                             delegate, &unused);
213c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return result;
214c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
215c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
216c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
217c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid PlatformThread::Join(PlatformThreadHandle thread_handle) {
21821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Joining another thread may block the current thread for a long time, since
21921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // the thread referred to by |thread_handle| may still be running long-lived /
22021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // blocking tasks.
22121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  base::ThreadRestrictions::AssertIOAllowed();
222c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pthread_join(thread_handle, NULL);
223c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
2243f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
2253f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen}  // namespace base
226