Home | History | Annotate | Download | only in threading
      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 "base/logging.h"
      8 #include "base/threading/thread_restrictions.h"
      9 #include "base/win/windows_version.h"
     10 
     11 namespace base {
     12 
     13 namespace {
     14 
     15 // The information on how to set the thread name comes from
     16 // a MSDN article: http://msdn2.microsoft.com/en-us/library/xcb2z8hs.aspx
     17 const DWORD kVCThreadNameException = 0x406D1388;
     18 
     19 typedef struct tagTHREADNAME_INFO {
     20   DWORD dwType;  // Must be 0x1000.
     21   LPCSTR szName;  // Pointer to name (in user addr space).
     22   DWORD dwThreadID;  // Thread ID (-1=caller thread).
     23   DWORD dwFlags;  // Reserved for future use, must be zero.
     24 } THREADNAME_INFO;
     25 
     26 struct ThreadParams {
     27   PlatformThread::Delegate* delegate;
     28   bool joinable;
     29 };
     30 
     31 DWORD __stdcall ThreadFunc(void* params) {
     32   ThreadParams* thread_params = static_cast<ThreadParams*>(params);
     33   PlatformThread::Delegate* delegate = thread_params->delegate;
     34   if (!thread_params->joinable)
     35     base::ThreadRestrictions::SetSingletonAllowed(false);
     36   delete thread_params;
     37   delegate->ThreadMain();
     38   return NULL;
     39 }
     40 
     41 // CreateThreadInternal() matches PlatformThread::Create(), except that
     42 // |out_thread_handle| may be NULL, in which case a non-joinable thread is
     43 // created.
     44 bool CreateThreadInternal(size_t stack_size,
     45                           PlatformThread::Delegate* delegate,
     46                           PlatformThreadHandle* out_thread_handle) {
     47   PlatformThreadHandle thread_handle;
     48   unsigned int flags = 0;
     49   if (stack_size > 0 && base::win::GetVersion() >= base::win::VERSION_XP) {
     50     flags = STACK_SIZE_PARAM_IS_A_RESERVATION;
     51   } else {
     52     stack_size = 0;
     53   }
     54 
     55   ThreadParams* params = new ThreadParams;
     56   params->delegate = delegate;
     57   params->joinable = out_thread_handle != NULL;
     58 
     59   // Using CreateThread here vs _beginthreadex makes thread creation a bit
     60   // faster and doesn't require the loader lock to be available.  Our code will
     61   // have to work running on CreateThread() threads anyway, since we run code
     62   // on the Windows thread pool, etc.  For some background on the difference:
     63   //   http://www.microsoft.com/msj/1099/win32/win321099.aspx
     64   thread_handle = CreateThread(
     65       NULL, stack_size, ThreadFunc, params, flags, NULL);
     66   if (!thread_handle) {
     67     delete params;
     68     return false;
     69   }
     70 
     71   if (out_thread_handle)
     72     *out_thread_handle = thread_handle;
     73   else
     74     CloseHandle(thread_handle);
     75   return true;
     76 }
     77 
     78 }  // namespace
     79 
     80 // static
     81 PlatformThreadId PlatformThread::CurrentId() {
     82   return GetCurrentThreadId();
     83 }
     84 
     85 // static
     86 void PlatformThread::YieldCurrentThread() {
     87   ::Sleep(0);
     88 }
     89 
     90 // static
     91 void PlatformThread::Sleep(int duration_ms) {
     92   ::Sleep(duration_ms);
     93 }
     94 
     95 // static
     96 void PlatformThread::SetName(const char* name) {
     97   // The debugger needs to be around to catch the name in the exception.  If
     98   // there isn't a debugger, we are just needlessly throwing an exception.
     99   if (!::IsDebuggerPresent())
    100     return;
    101 
    102   THREADNAME_INFO info;
    103   info.dwType = 0x1000;
    104   info.szName = name;
    105   info.dwThreadID = CurrentId();
    106   info.dwFlags = 0;
    107 
    108   __try {
    109     RaiseException(kVCThreadNameException, 0, sizeof(info)/sizeof(DWORD),
    110                    reinterpret_cast<DWORD_PTR*>(&info));
    111   } __except(EXCEPTION_CONTINUE_EXECUTION) {
    112   }
    113 }
    114 
    115 // static
    116 bool PlatformThread::Create(size_t stack_size, Delegate* delegate,
    117                             PlatformThreadHandle* thread_handle) {
    118   DCHECK(thread_handle);
    119   return CreateThreadInternal(stack_size, delegate, thread_handle);
    120 }
    121 
    122 // static
    123 bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
    124   return CreateThreadInternal(stack_size, delegate, NULL);
    125 }
    126 
    127 // static
    128 void PlatformThread::Join(PlatformThreadHandle thread_handle) {
    129   DCHECK(thread_handle);
    130   // TODO(willchan): Enable this check once I can get it to work for Windows
    131   // shutdown.
    132   // Joining another thread may block the current thread for a long time, since
    133   // the thread referred to by |thread_handle| may still be running long-lived /
    134   // blocking tasks.
    135 #if 0
    136   base::ThreadRestrictions::AssertIOAllowed();
    137 #endif
    138 
    139   // Wait for the thread to exit.  It should already have terminated but make
    140   // sure this assumption is valid.
    141   DWORD result = WaitForSingleObject(thread_handle, INFINITE);
    142   DCHECK_EQ(WAIT_OBJECT_0, result);
    143 
    144   CloseHandle(thread_handle);
    145 }
    146 
    147 }  // namespace base
    148