security/sandbox/chromium/base/threading/platform_thread_win.cc

Wed, 31 Dec 2014 06:55:46 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:46 +0100
changeset 1
ca08bd8f51b2
permissions
-rw-r--r--

Added tag TORBROWSER_REPLICA for changeset 6474c204b198

     1 // Copyright (c) 2012 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.
     5 #include "base/threading/platform_thread.h"
     7 #include "base/debug/alias.h"
     8 #include "base/debug/profiler.h"
     9 #include "base/logging.h"
    10 #include "base/threading/thread_id_name_manager.h"
    11 #include "base/threading/thread_restrictions.h"
    12 #include "base/tracked_objects.h"
    14 #include "base/win/windows_version.h"
    16 namespace base {
    18 namespace {
    20 // The information on how to set the thread name comes from
    21 // a MSDN article: http://msdn2.microsoft.com/en-us/library/xcb2z8hs.aspx
    22 const DWORD kVCThreadNameException = 0x406D1388;
    24 typedef struct tagTHREADNAME_INFO {
    25   DWORD dwType;  // Must be 0x1000.
    26   LPCSTR szName;  // Pointer to name (in user addr space).
    27   DWORD dwThreadID;  // Thread ID (-1=caller thread).
    28   DWORD dwFlags;  // Reserved for future use, must be zero.
    29 } THREADNAME_INFO;
    31 // This function has try handling, so it is separated out of its caller.
    32 void SetNameInternal(PlatformThreadId thread_id, const char* name) {
    33   THREADNAME_INFO info;
    34   info.dwType = 0x1000;
    35   info.szName = name;
    36   info.dwThreadID = thread_id;
    37   info.dwFlags = 0;
    39   __try {
    40     RaiseException(kVCThreadNameException, 0, sizeof(info)/sizeof(DWORD),
    41                    reinterpret_cast<DWORD_PTR*>(&info));
    42   } __except(EXCEPTION_CONTINUE_EXECUTION) {
    43   }
    44 }
    46 struct ThreadParams {
    47   PlatformThread::Delegate* delegate;
    48   bool joinable;
    49 };
    51 DWORD __stdcall ThreadFunc(void* params) {
    52   ThreadParams* thread_params = static_cast<ThreadParams*>(params);
    53   PlatformThread::Delegate* delegate = thread_params->delegate;
    54   if (!thread_params->joinable)
    55     base::ThreadRestrictions::SetSingletonAllowed(false);
    57   /* Retrieve a copy of the thread handle to use as the key in the
    58    * thread name mapping. */
    59   PlatformThreadHandle::Handle platform_handle;
    60   DuplicateHandle(
    61       GetCurrentProcess(),
    62       GetCurrentThread(),
    63       GetCurrentProcess(),
    64       &platform_handle,
    65       0,
    66       FALSE,
    67       DUPLICATE_SAME_ACCESS);
    69   ThreadIdNameManager::GetInstance()->RegisterThread(
    70       platform_handle,
    71       PlatformThread::CurrentId());
    73   delete thread_params;
    74   delegate->ThreadMain();
    76   ThreadIdNameManager::GetInstance()->RemoveName(
    77       platform_handle,
    78       PlatformThread::CurrentId());
    79   return NULL;
    80 }
    82 // CreateThreadInternal() matches PlatformThread::Create(), except that
    83 // |out_thread_handle| may be NULL, in which case a non-joinable thread is
    84 // created.
    85 bool CreateThreadInternal(size_t stack_size,
    86                           PlatformThread::Delegate* delegate,
    87                           PlatformThreadHandle* out_thread_handle) {
    88   unsigned int flags = 0;
    89   if (stack_size > 0 && base::win::GetVersion() >= base::win::VERSION_XP) {
    90     flags = STACK_SIZE_PARAM_IS_A_RESERVATION;
    91   } else {
    92     stack_size = 0;
    93   }
    95   ThreadParams* params = new ThreadParams;
    96   params->delegate = delegate;
    97   params->joinable = out_thread_handle != NULL;
    99   // Using CreateThread here vs _beginthreadex makes thread creation a bit
   100   // faster and doesn't require the loader lock to be available.  Our code will
   101   // have to work running on CreateThread() threads anyway, since we run code
   102   // on the Windows thread pool, etc.  For some background on the difference:
   103   //   http://www.microsoft.com/msj/1099/win32/win321099.aspx
   104   void* thread_handle = CreateThread(
   105       NULL, stack_size, ThreadFunc, params, flags, NULL);
   106   if (!thread_handle) {
   107     delete params;
   108     return false;
   109   }
   111   if (out_thread_handle)
   112     *out_thread_handle = PlatformThreadHandle(thread_handle);
   113   else
   114     CloseHandle(thread_handle);
   115   return true;
   116 }
   118 }  // namespace
   120 // static
   121 PlatformThreadId PlatformThread::CurrentId() {
   122   return GetCurrentThreadId();
   123 }
   125 // static
   126 PlatformThreadHandle PlatformThread::CurrentHandle() {
   127   NOTIMPLEMENTED(); // See OpenThread()
   128   return PlatformThreadHandle();
   129 }
   131 // static
   132 void PlatformThread::YieldCurrentThread() {
   133   ::Sleep(0);
   134 }
   136 // static
   137 void PlatformThread::Sleep(TimeDelta duration) {
   138   // When measured with a high resolution clock, Sleep() sometimes returns much
   139   // too early. We may need to call it repeatedly to get the desired duration.
   140   TimeTicks end = TimeTicks::Now() + duration;
   141   TimeTicks now;
   142   while ((now = TimeTicks::Now()) < end)
   143     ::Sleep((end - now).InMillisecondsRoundedUp());
   144 }
   146 // static
   147 void PlatformThread::SetName(const char* name) {
   148   ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
   150   // On Windows only, we don't need to tell the profiler about the "BrokerEvent"
   151   // thread, as it exists only in the chrome.exe image, and never spawns or runs
   152   // tasks (items which could be profiled).  This test avoids the notification,
   153   // which would also (as a side effect) initialize the profiler in this unused
   154   // context, including setting up thread local storage, etc.  The performance
   155   // impact is not terrible, but there is no reason to do initialize it.
   156   if (0 != strcmp(name, "BrokerEvent"))
   157     tracked_objects::ThreadData::InitializeThreadContext(name);
   159   // The debugger needs to be around to catch the name in the exception.  If
   160   // there isn't a debugger, we are just needlessly throwing an exception.
   161   // If this image file is instrumented, we raise the exception anyway
   162   // to provide the profiler with human-readable thread names.
   163   if (!::IsDebuggerPresent() && !base::debug::IsBinaryInstrumented())
   164     return;
   166   SetNameInternal(CurrentId(), name);
   167 }
   169 // static
   170 const char* PlatformThread::GetName() {
   171   return ThreadIdNameManager::GetInstance()->GetName(CurrentId());
   172 }
   174 // static
   175 bool PlatformThread::Create(size_t stack_size, Delegate* delegate,
   176                             PlatformThreadHandle* thread_handle) {
   177   DCHECK(thread_handle);
   178   return CreateThreadInternal(stack_size, delegate, thread_handle);
   179 }
   181 // static
   182 bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate,
   183                                         PlatformThreadHandle* thread_handle,
   184                                         ThreadPriority priority) {
   185   bool result = Create(stack_size, delegate, thread_handle);
   186   if (result)
   187     SetThreadPriority(*thread_handle, priority);
   188   return result;
   189 }
   191 // static
   192 bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
   193   return CreateThreadInternal(stack_size, delegate, NULL);
   194 }
   196 // static
   197 void PlatformThread::Join(PlatformThreadHandle thread_handle) {
   198   DCHECK(thread_handle.handle_);
   199   // TODO(willchan): Enable this check once I can get it to work for Windows
   200   // shutdown.
   201   // Joining another thread may block the current thread for a long time, since
   202   // the thread referred to by |thread_handle| may still be running long-lived /
   203   // blocking tasks.
   204 #if 0
   205   base::ThreadRestrictions::AssertIOAllowed();
   206 #endif
   208   // Wait for the thread to exit.  It should already have terminated but make
   209   // sure this assumption is valid.
   210   DWORD result = WaitForSingleObject(thread_handle.handle_, INFINITE);
   211   if (result != WAIT_OBJECT_0) {
   212     // Debug info for bug 127931.
   213     DWORD error = GetLastError();
   214     debug::Alias(&error);
   215     debug::Alias(&result);
   216     debug::Alias(&thread_handle.handle_);
   217     CHECK(false);
   218   }
   220   CloseHandle(thread_handle.handle_);
   221 }
   223 // static
   224 void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
   225                                        ThreadPriority priority) {
   226   switch (priority) {
   227     case kThreadPriority_Normal:
   228       ::SetThreadPriority(handle.handle_, THREAD_PRIORITY_NORMAL);
   229       break;
   230     case kThreadPriority_RealtimeAudio:
   231       ::SetThreadPriority(handle.handle_, THREAD_PRIORITY_TIME_CRITICAL);
   232       break;
   233     default:
   234       NOTREACHED() << "Unknown priority.";
   235       break;
   236   }
   237 }
   239 }  // namespace base

mercurial