1731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be 3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file. 4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 53f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/platform_thread.h" 6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h" 83f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread_restrictions.h" 9731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/win/windows_version.h" 10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 113f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsennamespace base { 123f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace { 14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// The information on how to set the thread name comes from 16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// a MSDN article: http://msdn2.microsoft.com/en-us/library/xcb2z8hs.aspx 17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottconst DWORD kVCThreadNameException = 0x406D1388; 18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scotttypedef struct tagTHREADNAME_INFO { 20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DWORD dwType; // Must be 0x1000. 21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott LPCSTR szName; // Pointer to name (in user addr space). 22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DWORD dwThreadID; // Thread ID (-1=caller thread). 23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DWORD dwFlags; // Reserved for future use, must be zero. 24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} THREADNAME_INFO; 25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 26201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochstruct ThreadParams { 27201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch PlatformThread::Delegate* delegate; 28201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch bool joinable; 29201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}; 30201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch 31201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben MurdochDWORD __stdcall ThreadFunc(void* params) { 32201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch ThreadParams* thread_params = static_cast<ThreadParams*>(params); 33201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch PlatformThread::Delegate* delegate = thread_params->delegate; 34201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch if (!thread_params->joinable) 35201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch base::ThreadRestrictions::SetSingletonAllowed(false); 36201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch delete thread_params; 37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott delegate->ThreadMain(); 38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return NULL; 39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 41201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// CreateThreadInternal() matches PlatformThread::Create(), except that 42201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// |out_thread_handle| may be NULL, in which case a non-joinable thread is 43201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// created. 44201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochbool CreateThreadInternal(size_t stack_size, 45201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch PlatformThread::Delegate* delegate, 46201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch PlatformThreadHandle* out_thread_handle) { 47201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch PlatformThreadHandle thread_handle; 48201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch unsigned int flags = 0; 49201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch if (stack_size > 0 && base::win::GetVersion() >= base::win::VERSION_XP) { 50201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch flags = STACK_SIZE_PARAM_IS_A_RESERVATION; 51201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch } else { 52201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch stack_size = 0; 53201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch } 54201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch 55201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch ThreadParams* params = new ThreadParams; 56201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch params->delegate = delegate; 57201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch params->joinable = out_thread_handle != NULL; 58201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch 59201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch // Using CreateThread here vs _beginthreadex makes thread creation a bit 60201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch // faster and doesn't require the loader lock to be available. Our code will 61201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch // have to work running on CreateThread() threads anyway, since we run code 62201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch // on the Windows thread pool, etc. For some background on the difference: 63201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch // http://www.microsoft.com/msj/1099/win32/win321099.aspx 64201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch thread_handle = CreateThread( 65201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch NULL, stack_size, ThreadFunc, params, flags, NULL); 66201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch if (!thread_handle) { 67201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch delete params; 68201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch return false; 69201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch } 70201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch 71201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch if (out_thread_handle) 72201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch *out_thread_handle = thread_handle; 73201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch else 74201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch CloseHandle(thread_handle); 75201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch return true; 76201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch} 77201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch 78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} // namespace 79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottPlatformThreadId PlatformThread::CurrentId() { 82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return GetCurrentThreadId(); 83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid PlatformThread::YieldCurrentThread() { 87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ::Sleep(0); 88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid PlatformThread::Sleep(int duration_ms) { 92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ::Sleep(duration_ms); 93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid PlatformThread::SetName(const char* name) { 97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // The debugger needs to be around to catch the name in the exception. If 98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // there isn't a debugger, we are just needlessly throwing an exception. 99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!::IsDebuggerPresent()) 100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott THREADNAME_INFO info; 103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott info.dwType = 0x1000; 104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott info.szName = name; 105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott info.dwThreadID = CurrentId(); 106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott info.dwFlags = 0; 107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott __try { 109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott RaiseException(kVCThreadNameException, 0, sizeof(info)/sizeof(DWORD), 110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott reinterpret_cast<DWORD_PTR*>(&info)); 111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } __except(EXCEPTION_CONTINUE_EXECUTION) { 112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool PlatformThread::Create(size_t stack_size, Delegate* delegate, 117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott PlatformThreadHandle* thread_handle) { 118201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch DCHECK(thread_handle); 119201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch return CreateThreadInternal(stack_size, delegate, thread_handle); 120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) { 124201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch return CreateThreadInternal(stack_size, delegate, NULL); 125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid PlatformThread::Join(PlatformThreadHandle thread_handle) { 129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(thread_handle); 13021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // TODO(willchan): Enable this check once I can get it to work for Windows 13121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // shutdown. 13221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Joining another thread may block the current thread for a long time, since 13321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // the thread referred to by |thread_handle| may still be running long-lived / 13421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // blocking tasks. 13521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#if 0 13621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen base::ThreadRestrictions::AssertIOAllowed(); 13721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#endif 138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Wait for the thread to exit. It should already have terminated but make 140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // sure this assumption is valid. 141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DWORD result = WaitForSingleObject(thread_handle, INFINITE); 142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK_EQ(WAIT_OBJECT_0, result); 143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott CloseHandle(thread_handle); 145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 1463f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 1473f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen} // namespace base 148