1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/sandbox/chromium/base/threading/platform_thread_win.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,239 @@ 1.4 +// Copyright (c) 2012 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "base/threading/platform_thread.h" 1.9 + 1.10 +#include "base/debug/alias.h" 1.11 +#include "base/debug/profiler.h" 1.12 +#include "base/logging.h" 1.13 +#include "base/threading/thread_id_name_manager.h" 1.14 +#include "base/threading/thread_restrictions.h" 1.15 +#include "base/tracked_objects.h" 1.16 + 1.17 +#include "base/win/windows_version.h" 1.18 + 1.19 +namespace base { 1.20 + 1.21 +namespace { 1.22 + 1.23 +// The information on how to set the thread name comes from 1.24 +// a MSDN article: http://msdn2.microsoft.com/en-us/library/xcb2z8hs.aspx 1.25 +const DWORD kVCThreadNameException = 0x406D1388; 1.26 + 1.27 +typedef struct tagTHREADNAME_INFO { 1.28 + DWORD dwType; // Must be 0x1000. 1.29 + LPCSTR szName; // Pointer to name (in user addr space). 1.30 + DWORD dwThreadID; // Thread ID (-1=caller thread). 1.31 + DWORD dwFlags; // Reserved for future use, must be zero. 1.32 +} THREADNAME_INFO; 1.33 + 1.34 +// This function has try handling, so it is separated out of its caller. 1.35 +void SetNameInternal(PlatformThreadId thread_id, const char* name) { 1.36 + THREADNAME_INFO info; 1.37 + info.dwType = 0x1000; 1.38 + info.szName = name; 1.39 + info.dwThreadID = thread_id; 1.40 + info.dwFlags = 0; 1.41 + 1.42 + __try { 1.43 + RaiseException(kVCThreadNameException, 0, sizeof(info)/sizeof(DWORD), 1.44 + reinterpret_cast<DWORD_PTR*>(&info)); 1.45 + } __except(EXCEPTION_CONTINUE_EXECUTION) { 1.46 + } 1.47 +} 1.48 + 1.49 +struct ThreadParams { 1.50 + PlatformThread::Delegate* delegate; 1.51 + bool joinable; 1.52 +}; 1.53 + 1.54 +DWORD __stdcall ThreadFunc(void* params) { 1.55 + ThreadParams* thread_params = static_cast<ThreadParams*>(params); 1.56 + PlatformThread::Delegate* delegate = thread_params->delegate; 1.57 + if (!thread_params->joinable) 1.58 + base::ThreadRestrictions::SetSingletonAllowed(false); 1.59 + 1.60 + /* Retrieve a copy of the thread handle to use as the key in the 1.61 + * thread name mapping. */ 1.62 + PlatformThreadHandle::Handle platform_handle; 1.63 + DuplicateHandle( 1.64 + GetCurrentProcess(), 1.65 + GetCurrentThread(), 1.66 + GetCurrentProcess(), 1.67 + &platform_handle, 1.68 + 0, 1.69 + FALSE, 1.70 + DUPLICATE_SAME_ACCESS); 1.71 + 1.72 + ThreadIdNameManager::GetInstance()->RegisterThread( 1.73 + platform_handle, 1.74 + PlatformThread::CurrentId()); 1.75 + 1.76 + delete thread_params; 1.77 + delegate->ThreadMain(); 1.78 + 1.79 + ThreadIdNameManager::GetInstance()->RemoveName( 1.80 + platform_handle, 1.81 + PlatformThread::CurrentId()); 1.82 + return NULL; 1.83 +} 1.84 + 1.85 +// CreateThreadInternal() matches PlatformThread::Create(), except that 1.86 +// |out_thread_handle| may be NULL, in which case a non-joinable thread is 1.87 +// created. 1.88 +bool CreateThreadInternal(size_t stack_size, 1.89 + PlatformThread::Delegate* delegate, 1.90 + PlatformThreadHandle* out_thread_handle) { 1.91 + unsigned int flags = 0; 1.92 + if (stack_size > 0 && base::win::GetVersion() >= base::win::VERSION_XP) { 1.93 + flags = STACK_SIZE_PARAM_IS_A_RESERVATION; 1.94 + } else { 1.95 + stack_size = 0; 1.96 + } 1.97 + 1.98 + ThreadParams* params = new ThreadParams; 1.99 + params->delegate = delegate; 1.100 + params->joinable = out_thread_handle != NULL; 1.101 + 1.102 + // Using CreateThread here vs _beginthreadex makes thread creation a bit 1.103 + // faster and doesn't require the loader lock to be available. Our code will 1.104 + // have to work running on CreateThread() threads anyway, since we run code 1.105 + // on the Windows thread pool, etc. For some background on the difference: 1.106 + // http://www.microsoft.com/msj/1099/win32/win321099.aspx 1.107 + void* thread_handle = CreateThread( 1.108 + NULL, stack_size, ThreadFunc, params, flags, NULL); 1.109 + if (!thread_handle) { 1.110 + delete params; 1.111 + return false; 1.112 + } 1.113 + 1.114 + if (out_thread_handle) 1.115 + *out_thread_handle = PlatformThreadHandle(thread_handle); 1.116 + else 1.117 + CloseHandle(thread_handle); 1.118 + return true; 1.119 +} 1.120 + 1.121 +} // namespace 1.122 + 1.123 +// static 1.124 +PlatformThreadId PlatformThread::CurrentId() { 1.125 + return GetCurrentThreadId(); 1.126 +} 1.127 + 1.128 +// static 1.129 +PlatformThreadHandle PlatformThread::CurrentHandle() { 1.130 + NOTIMPLEMENTED(); // See OpenThread() 1.131 + return PlatformThreadHandle(); 1.132 +} 1.133 + 1.134 +// static 1.135 +void PlatformThread::YieldCurrentThread() { 1.136 + ::Sleep(0); 1.137 +} 1.138 + 1.139 +// static 1.140 +void PlatformThread::Sleep(TimeDelta duration) { 1.141 + // When measured with a high resolution clock, Sleep() sometimes returns much 1.142 + // too early. We may need to call it repeatedly to get the desired duration. 1.143 + TimeTicks end = TimeTicks::Now() + duration; 1.144 + TimeTicks now; 1.145 + while ((now = TimeTicks::Now()) < end) 1.146 + ::Sleep((end - now).InMillisecondsRoundedUp()); 1.147 +} 1.148 + 1.149 +// static 1.150 +void PlatformThread::SetName(const char* name) { 1.151 + ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name); 1.152 + 1.153 + // On Windows only, we don't need to tell the profiler about the "BrokerEvent" 1.154 + // thread, as it exists only in the chrome.exe image, and never spawns or runs 1.155 + // tasks (items which could be profiled). This test avoids the notification, 1.156 + // which would also (as a side effect) initialize the profiler in this unused 1.157 + // context, including setting up thread local storage, etc. The performance 1.158 + // impact is not terrible, but there is no reason to do initialize it. 1.159 + if (0 != strcmp(name, "BrokerEvent")) 1.160 + tracked_objects::ThreadData::InitializeThreadContext(name); 1.161 + 1.162 + // The debugger needs to be around to catch the name in the exception. If 1.163 + // there isn't a debugger, we are just needlessly throwing an exception. 1.164 + // If this image file is instrumented, we raise the exception anyway 1.165 + // to provide the profiler with human-readable thread names. 1.166 + if (!::IsDebuggerPresent() && !base::debug::IsBinaryInstrumented()) 1.167 + return; 1.168 + 1.169 + SetNameInternal(CurrentId(), name); 1.170 +} 1.171 + 1.172 +// static 1.173 +const char* PlatformThread::GetName() { 1.174 + return ThreadIdNameManager::GetInstance()->GetName(CurrentId()); 1.175 +} 1.176 + 1.177 +// static 1.178 +bool PlatformThread::Create(size_t stack_size, Delegate* delegate, 1.179 + PlatformThreadHandle* thread_handle) { 1.180 + DCHECK(thread_handle); 1.181 + return CreateThreadInternal(stack_size, delegate, thread_handle); 1.182 +} 1.183 + 1.184 +// static 1.185 +bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate, 1.186 + PlatformThreadHandle* thread_handle, 1.187 + ThreadPriority priority) { 1.188 + bool result = Create(stack_size, delegate, thread_handle); 1.189 + if (result) 1.190 + SetThreadPriority(*thread_handle, priority); 1.191 + return result; 1.192 +} 1.193 + 1.194 +// static 1.195 +bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) { 1.196 + return CreateThreadInternal(stack_size, delegate, NULL); 1.197 +} 1.198 + 1.199 +// static 1.200 +void PlatformThread::Join(PlatformThreadHandle thread_handle) { 1.201 + DCHECK(thread_handle.handle_); 1.202 + // TODO(willchan): Enable this check once I can get it to work for Windows 1.203 + // shutdown. 1.204 + // Joining another thread may block the current thread for a long time, since 1.205 + // the thread referred to by |thread_handle| may still be running long-lived / 1.206 + // blocking tasks. 1.207 +#if 0 1.208 + base::ThreadRestrictions::AssertIOAllowed(); 1.209 +#endif 1.210 + 1.211 + // Wait for the thread to exit. It should already have terminated but make 1.212 + // sure this assumption is valid. 1.213 + DWORD result = WaitForSingleObject(thread_handle.handle_, INFINITE); 1.214 + if (result != WAIT_OBJECT_0) { 1.215 + // Debug info for bug 127931. 1.216 + DWORD error = GetLastError(); 1.217 + debug::Alias(&error); 1.218 + debug::Alias(&result); 1.219 + debug::Alias(&thread_handle.handle_); 1.220 + CHECK(false); 1.221 + } 1.222 + 1.223 + CloseHandle(thread_handle.handle_); 1.224 +} 1.225 + 1.226 +// static 1.227 +void PlatformThread::SetThreadPriority(PlatformThreadHandle handle, 1.228 + ThreadPriority priority) { 1.229 + switch (priority) { 1.230 + case kThreadPriority_Normal: 1.231 + ::SetThreadPriority(handle.handle_, THREAD_PRIORITY_NORMAL); 1.232 + break; 1.233 + case kThreadPriority_RealtimeAudio: 1.234 + ::SetThreadPriority(handle.handle_, THREAD_PRIORITY_TIME_CRITICAL); 1.235 + break; 1.236 + default: 1.237 + NOTREACHED() << "Unknown priority."; 1.238 + break; 1.239 + } 1.240 +} 1.241 + 1.242 +} // namespace base