Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2006-2008 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/platform_thread.h"
      6 
      7 #include <errno.h>
      8 #include <sched.h>
      9 
     10 #if defined(OS_MACOSX)
     11 #include <mach/mach.h>
     12 #else
     13 #include <sys/syscall.h>
     14 #include <unistd.h>
     15 #endif
     16 
     17 #if defined(OS_MACOSX)
     18 namespace base {
     19 void InitThreading();
     20 }  // namespace
     21 #endif
     22 
     23 static void* ThreadFunc(void* closure) {
     24   PlatformThread::Delegate* delegate =
     25       static_cast<PlatformThread::Delegate*>(closure);
     26   delegate->ThreadMain();
     27   return NULL;
     28 }
     29 
     30 // static
     31 PlatformThreadId PlatformThread::CurrentId() {
     32   // Pthreads doesn't have the concept of a thread ID, so we have to reach down
     33   // into the kernel.
     34 #if defined(OS_MACOSX)
     35   return mach_thread_self();
     36 #elif defined(OS_LINUX)
     37   return syscall(__NR_gettid);
     38 #elif defined(OS_FREEBSD)
     39   // TODO(BSD): find a better thread ID
     40   return reinterpret_cast<int64>(pthread_self());
     41 #endif
     42 }
     43 
     44 // static
     45 void PlatformThread::YieldCurrentThread() {
     46   sched_yield();
     47 }
     48 
     49 // static
     50 void PlatformThread::Sleep(int duration_ms) {
     51   struct timespec sleep_time, remaining;
     52 
     53   // Contains the portion of duration_ms >= 1 sec.
     54   sleep_time.tv_sec = duration_ms / 1000;
     55   duration_ms -= sleep_time.tv_sec * 1000;
     56 
     57   // Contains the portion of duration_ms < 1 sec.
     58   sleep_time.tv_nsec = duration_ms * 1000 * 1000;  // nanoseconds.
     59 
     60   while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR)
     61     sleep_time = remaining;
     62 }
     63 
     64 // static
     65 void PlatformThread::SetName(const char* name) {
     66   // The POSIX standard does not provide for naming threads, and neither Linux
     67   // nor Mac OS X (our two POSIX targets) provide any non-portable way of doing
     68   // it either. (Some BSDs provide pthread_set_name_np but that isn't much of a
     69   // consolation prize.)
     70   // TODO(darin): decide whether stuffing the name in TLS or other in-memory
     71   // structure would be useful for debugging or not.
     72 }
     73 
     74 namespace {
     75 
     76 bool CreateThread(size_t stack_size, bool joinable,
     77                   PlatformThread::Delegate* delegate,
     78                   PlatformThreadHandle* thread_handle) {
     79 #if defined(OS_MACOSX)
     80   base::InitThreading();
     81 #endif  // OS_MACOSX
     82 
     83   bool success = false;
     84   pthread_attr_t attributes;
     85   pthread_attr_init(&attributes);
     86 
     87   // Pthreads are joinable by default, so only specify the detached attribute if
     88   // the thread should be non-joinable.
     89   if (!joinable) {
     90     pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
     91   }
     92 
     93   if (stack_size > 0)
     94     pthread_attr_setstacksize(&attributes, stack_size);
     95 
     96   success = !pthread_create(thread_handle, &attributes, ThreadFunc, delegate);
     97 
     98   pthread_attr_destroy(&attributes);
     99   return success;
    100 }
    101 
    102 }  // anonymous namespace
    103 
    104 // static
    105 bool PlatformThread::Create(size_t stack_size, Delegate* delegate,
    106                             PlatformThreadHandle* thread_handle) {
    107   return CreateThread(stack_size, true /* joinable thread */,
    108                       delegate, thread_handle);
    109 }
    110 
    111 // static
    112 bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
    113   PlatformThreadHandle unused;
    114 
    115   bool result = CreateThread(stack_size, false /* non-joinable thread */,
    116                              delegate, &unused);
    117   return result;
    118 }
    119 
    120 // static
    121 void PlatformThread::Join(PlatformThreadHandle thread_handle) {
    122   pthread_join(thread_handle, NULL);
    123 }
    124