Update .DEPS.git
[chromium-blink-merge.git] / base / threading / platform_thread_win.cc
blob82981adaf834b7a813cabf40756f4c2d59222ac5
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_local.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 static ThreadLocalPointer<char> current_thread_name;
22 // The information on how to set the thread name comes from
23 // a MSDN article: http://msdn2.microsoft.com/en-us/library/xcb2z8hs.aspx
24 const DWORD kVCThreadNameException = 0x406D1388;
26 typedef struct tagTHREADNAME_INFO {
27 DWORD dwType; // Must be 0x1000.
28 LPCSTR szName; // Pointer to name (in user addr space).
29 DWORD dwThreadID; // Thread ID (-1=caller thread).
30 DWORD dwFlags; // Reserved for future use, must be zero.
31 } THREADNAME_INFO;
33 // This function has try handling, so it is separated out of its caller.
34 void SetNameInternal(PlatformThreadId thread_id, const char* name) {
35 THREADNAME_INFO info;
36 info.dwType = 0x1000;
37 info.szName = name;
38 info.dwThreadID = thread_id;
39 info.dwFlags = 0;
41 __try {
42 RaiseException(kVCThreadNameException, 0, sizeof(info)/sizeof(DWORD),
43 reinterpret_cast<DWORD_PTR*>(&info));
44 } __except(EXCEPTION_CONTINUE_EXECUTION) {
48 struct ThreadParams {
49 PlatformThread::Delegate* delegate;
50 bool joinable;
53 DWORD __stdcall ThreadFunc(void* params) {
54 ThreadParams* thread_params = static_cast<ThreadParams*>(params);
55 PlatformThread::Delegate* delegate = thread_params->delegate;
56 if (!thread_params->joinable)
57 base::ThreadRestrictions::SetSingletonAllowed(false);
58 delete thread_params;
59 delegate->ThreadMain();
60 return NULL;
63 // CreateThreadInternal() matches PlatformThread::Create(), except that
64 // |out_thread_handle| may be NULL, in which case a non-joinable thread is
65 // created.
66 bool CreateThreadInternal(size_t stack_size,
67 PlatformThread::Delegate* delegate,
68 PlatformThreadHandle* out_thread_handle) {
69 PlatformThreadHandle thread_handle;
70 unsigned int flags = 0;
71 if (stack_size > 0 && base::win::GetVersion() >= base::win::VERSION_XP) {
72 flags = STACK_SIZE_PARAM_IS_A_RESERVATION;
73 } else {
74 stack_size = 0;
77 ThreadParams* params = new ThreadParams;
78 params->delegate = delegate;
79 params->joinable = out_thread_handle != NULL;
81 // Using CreateThread here vs _beginthreadex makes thread creation a bit
82 // faster and doesn't require the loader lock to be available. Our code will
83 // have to work running on CreateThread() threads anyway, since we run code
84 // on the Windows thread pool, etc. For some background on the difference:
85 // http://www.microsoft.com/msj/1099/win32/win321099.aspx
86 thread_handle = CreateThread(
87 NULL, stack_size, ThreadFunc, params, flags, NULL);
88 if (!thread_handle) {
89 delete params;
90 return false;
93 if (out_thread_handle)
94 *out_thread_handle = thread_handle;
95 else
96 CloseHandle(thread_handle);
97 return true;
100 } // namespace
102 // static
103 PlatformThreadId PlatformThread::CurrentId() {
104 return GetCurrentThreadId();
107 // static
108 void PlatformThread::YieldCurrentThread() {
109 ::Sleep(0);
112 // static
113 void PlatformThread::Sleep(TimeDelta duration) {
114 ::Sleep(duration.InMillisecondsRoundedUp());
117 // static
118 void PlatformThread::SetName(const char* name) {
119 current_thread_name.Set(const_cast<char*>(name));
121 // On Windows only, we don't need to tell the profiler about the "BrokerEvent"
122 // thread, as it exists only in the chrome.exe image, and never spawns or runs
123 // tasks (items which could be profiled). This test avoids the notification,
124 // which would also (as a side effect) initialize the profiler in this unused
125 // context, including setting up thread local storage, etc. The performance
126 // impact is not terrible, but there is no reason to do initialize it.
127 if (0 != strcmp(name, "BrokerEvent"))
128 tracked_objects::ThreadData::InitializeThreadContext(name);
130 // The debugger needs to be around to catch the name in the exception. If
131 // there isn't a debugger, we are just needlessly throwing an exception.
132 // If this image file is instrumented, we raise the exception anyway
133 // to provide the profiler with human-readable thread names.
134 if (!::IsDebuggerPresent() && !base::debug::IsBinaryInstrumented())
135 return;
137 SetNameInternal(CurrentId(), name);
140 // static
141 const char* PlatformThread::GetName() {
142 return current_thread_name.Get();
145 // static
146 bool PlatformThread::Create(size_t stack_size, Delegate* delegate,
147 PlatformThreadHandle* thread_handle) {
148 DCHECK(thread_handle);
149 return CreateThreadInternal(stack_size, delegate, thread_handle);
152 // static
153 bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate,
154 PlatformThreadHandle* thread_handle,
155 ThreadPriority priority) {
156 bool result = Create(stack_size, delegate, thread_handle);
157 if (result)
158 SetThreadPriority(*thread_handle, priority);
159 return result;
162 // static
163 bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
164 return CreateThreadInternal(stack_size, delegate, NULL);
167 // static
168 void PlatformThread::Join(PlatformThreadHandle thread_handle) {
169 DCHECK(thread_handle);
170 // TODO(willchan): Enable this check once I can get it to work for Windows
171 // shutdown.
172 // Joining another thread may block the current thread for a long time, since
173 // the thread referred to by |thread_handle| may still be running long-lived /
174 // blocking tasks.
175 #if 0
176 base::ThreadRestrictions::AssertIOAllowed();
177 #endif
179 // Wait for the thread to exit. It should already have terminated but make
180 // sure this assumption is valid.
181 DWORD result = WaitForSingleObject(thread_handle, INFINITE);
182 if (result != WAIT_OBJECT_0) {
183 // Debug info for bug 127931.
184 DWORD error = GetLastError();
185 debug::Alias(&error);
186 debug::Alias(&result);
187 debug::Alias(&thread_handle);
188 CHECK(false);
191 CloseHandle(thread_handle);
194 // static
195 void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
196 ThreadPriority priority) {
197 switch (priority) {
198 case kThreadPriority_Normal:
199 ::SetThreadPriority(handle, THREAD_PRIORITY_NORMAL);
200 break;
201 case kThreadPriority_RealtimeAudio:
202 ::SetThreadPriority(handle, THREAD_PRIORITY_TIME_CRITICAL);
203 break;
207 } // namespace base