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

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

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

mercurial