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"
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.
33 // This function has try handling, so it is separated out of its caller.
34 void SetNameInternal(PlatformThreadId thread_id
, const char* name
) {
38 info
.dwThreadID
= thread_id
;
42 RaiseException(kVCThreadNameException
, 0, sizeof(info
)/sizeof(DWORD
),
43 reinterpret_cast<DWORD_PTR
*>(&info
));
44 } __except(EXCEPTION_CONTINUE_EXECUTION
) {
49 PlatformThread::Delegate
* delegate
;
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);
59 delegate
->ThreadMain();
63 // CreateThreadInternal() matches PlatformThread::Create(), except that
64 // |out_thread_handle| may be NULL, in which case a non-joinable thread is
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
;
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
);
93 if (out_thread_handle
)
94 *out_thread_handle
= thread_handle
;
96 CloseHandle(thread_handle
);
103 PlatformThreadId
PlatformThread::CurrentId() {
104 return GetCurrentThreadId();
108 void PlatformThread::YieldCurrentThread() {
113 void PlatformThread::Sleep(TimeDelta duration
) {
114 ::Sleep(duration
.InMillisecondsRoundedUp());
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())
137 SetNameInternal(CurrentId(), name
);
141 const char* PlatformThread::GetName() {
142 return current_thread_name
.Get();
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
);
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
);
158 SetThreadPriority(*thread_handle
, priority
);
163 bool PlatformThread::CreateNonJoinable(size_t stack_size
, Delegate
* delegate
) {
164 return CreateThreadInternal(stack_size
, delegate
, NULL
);
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
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 /
176 base::ThreadRestrictions::AssertIOAllowed();
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
);
191 CloseHandle(thread_handle
);
195 void PlatformThread::SetThreadPriority(PlatformThreadHandle handle
,
196 ThreadPriority priority
) {
198 case kThreadPriority_Normal
:
199 ::SetThreadPriority(handle
, THREAD_PRIORITY_NORMAL
);
201 case kThreadPriority_RealtimeAudio
:
202 ::SetThreadPriority(handle
, THREAD_PRIORITY_TIME_CRITICAL
);