Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(123)

Side by Side Diff: base/threading/platform_thread_win.cc

Issue 1647803004: Move base to DEPS (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/threading/platform_thread_unittest.cc ('k') | base/threading/post_task_and_reply_impl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "base/threading/platform_thread.h"
6
7 #include "base/debug/alias.h"
8 #include "base/debug/profiler.h"
9 #include "base/logging.h"
10 #include "base/threading/thread_id_name_manager.h"
11 #include "base/threading/thread_restrictions.h"
12 #include "base/tracked_objects.h"
13 #include "base/win/scoped_handle.h"
14 #include "base/win/windows_version.h"
15
16 namespace base {
17
18 namespace {
19
20 // The information on how to set the thread name comes from
21 // a MSDN article: http://msdn2.microsoft.com/en-us/library/xcb2z8hs.aspx
22 const DWORD kVCThreadNameException = 0x406D1388;
23
24 typedef struct tagTHREADNAME_INFO {
25 DWORD dwType; // Must be 0x1000.
26 LPCSTR szName; // Pointer to name (in user addr space).
27 DWORD dwThreadID; // Thread ID (-1=caller thread).
28 DWORD dwFlags; // Reserved for future use, must be zero.
29 } THREADNAME_INFO;
30
31 // This function has try handling, so it is separated out of its caller.
32 void SetNameInternal(PlatformThreadId thread_id, const char* name) {
33 THREADNAME_INFO info;
34 info.dwType = 0x1000;
35 info.szName = name;
36 info.dwThreadID = thread_id;
37 info.dwFlags = 0;
38
39 __try {
40 RaiseException(kVCThreadNameException, 0, sizeof(info)/sizeof(DWORD),
41 reinterpret_cast<DWORD_PTR*>(&info));
42 } __except(EXCEPTION_CONTINUE_EXECUTION) {
43 }
44 }
45
46 struct ThreadParams {
47 PlatformThread::Delegate* delegate;
48 bool joinable;
49 ThreadPriority priority;
50 };
51
52 DWORD __stdcall ThreadFunc(void* params) {
53 ThreadParams* thread_params = static_cast<ThreadParams*>(params);
54 PlatformThread::Delegate* delegate = thread_params->delegate;
55 if (!thread_params->joinable)
56 base::ThreadRestrictions::SetSingletonAllowed(false);
57
58 if (thread_params->priority != ThreadPriority::NORMAL)
59 PlatformThread::SetCurrentThreadPriority(thread_params->priority);
60
61 // Retrieve a copy of the thread handle to use as the key in the
62 // thread name mapping.
63 PlatformThreadHandle::Handle platform_handle;
64 BOOL did_dup = DuplicateHandle(GetCurrentProcess(),
65 GetCurrentThread(),
66 GetCurrentProcess(),
67 &platform_handle,
68 0,
69 FALSE,
70 DUPLICATE_SAME_ACCESS);
71
72 win::ScopedHandle scoped_platform_handle;
73
74 if (did_dup) {
75 scoped_platform_handle.Set(platform_handle);
76 ThreadIdNameManager::GetInstance()->RegisterThread(
77 scoped_platform_handle.Get(),
78 PlatformThread::CurrentId());
79 }
80
81 delete thread_params;
82 delegate->ThreadMain();
83
84 if (did_dup) {
85 ThreadIdNameManager::GetInstance()->RemoveName(
86 scoped_platform_handle.Get(),
87 PlatformThread::CurrentId());
88 }
89
90 return NULL;
91 }
92
93 // CreateThreadInternal() matches PlatformThread::CreateWithPriority(), except
94 // that |out_thread_handle| may be NULL, in which case a non-joinable thread is
95 // created.
96 bool CreateThreadInternal(size_t stack_size,
97 PlatformThread::Delegate* delegate,
98 PlatformThreadHandle* out_thread_handle,
99 ThreadPriority priority) {
100 unsigned int flags = 0;
101 if (stack_size > 0 && base::win::GetVersion() >= base::win::VERSION_XP) {
102 flags = STACK_SIZE_PARAM_IS_A_RESERVATION;
103 } else {
104 stack_size = 0;
105 }
106
107 ThreadParams* params = new ThreadParams;
108 params->delegate = delegate;
109 params->joinable = out_thread_handle != NULL;
110 params->priority = priority;
111
112 // Using CreateThread here vs _beginthreadex makes thread creation a bit
113 // faster and doesn't require the loader lock to be available. Our code will
114 // have to work running on CreateThread() threads anyway, since we run code
115 // on the Windows thread pool, etc. For some background on the difference:
116 // http://www.microsoft.com/msj/1099/win32/win321099.aspx
117 PlatformThreadId thread_id;
118 void* thread_handle = CreateThread(
119 NULL, stack_size, ThreadFunc, params, flags, &thread_id);
120 if (!thread_handle) {
121 delete params;
122 return false;
123 }
124
125 if (out_thread_handle)
126 *out_thread_handle = PlatformThreadHandle(thread_handle, thread_id);
127 else
128 CloseHandle(thread_handle);
129 return true;
130 }
131
132 } // namespace
133
134 // static
135 PlatformThreadId PlatformThread::CurrentId() {
136 return ::GetCurrentThreadId();
137 }
138
139 // static
140 PlatformThreadRef PlatformThread::CurrentRef() {
141 return PlatformThreadRef(::GetCurrentThreadId());
142 }
143
144 // static
145 PlatformThreadHandle PlatformThread::CurrentHandle() {
146 return PlatformThreadHandle(::GetCurrentThread());
147 }
148
149 // static
150 void PlatformThread::YieldCurrentThread() {
151 ::Sleep(0);
152 }
153
154 // static
155 void PlatformThread::Sleep(TimeDelta duration) {
156 // When measured with a high resolution clock, Sleep() sometimes returns much
157 // too early. We may need to call it repeatedly to get the desired duration.
158 TimeTicks end = TimeTicks::Now() + duration;
159 for (TimeTicks now = TimeTicks::Now(); now < end; now = TimeTicks::Now())
160 ::Sleep(static_cast<DWORD>((end - now).InMillisecondsRoundedUp()));
161 }
162
163 // static
164 void PlatformThread::SetName(const std::string& name) {
165 ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
166
167 // On Windows only, we don't need to tell the profiler about the "BrokerEvent"
168 // thread, as it exists only in the chrome.exe image, and never spawns or runs
169 // tasks (items which could be profiled). This test avoids the notification,
170 // which would also (as a side effect) initialize the profiler in this unused
171 // context, including setting up thread local storage, etc. The performance
172 // impact is not terrible, but there is no reason to do initialize it.
173 if (name != "BrokerEvent")
174 tracked_objects::ThreadData::InitializeThreadContext(name);
175
176 // The debugger needs to be around to catch the name in the exception. If
177 // there isn't a debugger, we are just needlessly throwing an exception.
178 // If this image file is instrumented, we raise the exception anyway
179 // to provide the profiler with human-readable thread names.
180 if (!::IsDebuggerPresent() && !base::debug::IsBinaryInstrumented())
181 return;
182
183 SetNameInternal(CurrentId(), name.c_str());
184 }
185
186 // static
187 const char* PlatformThread::GetName() {
188 return ThreadIdNameManager::GetInstance()->GetName(CurrentId());
189 }
190
191 // static
192 bool PlatformThread::Create(size_t stack_size, Delegate* delegate,
193 PlatformThreadHandle* thread_handle) {
194 return CreateWithPriority(stack_size, delegate, thread_handle,
195 ThreadPriority::NORMAL);
196 }
197
198 // static
199 bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate,
200 PlatformThreadHandle* thread_handle,
201 ThreadPriority priority) {
202 DCHECK(thread_handle);
203 return CreateThreadInternal(stack_size, delegate, thread_handle, priority);
204 }
205
206 // static
207 bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
208 return CreateThreadInternal(stack_size, delegate, NULL,
209 ThreadPriority::NORMAL);
210 }
211
212 // static
213 void PlatformThread::Join(PlatformThreadHandle thread_handle) {
214 DCHECK(thread_handle.platform_handle());
215 // TODO(willchan): Enable this check once I can get it to work for Windows
216 // shutdown.
217 // Joining another thread may block the current thread for a long time, since
218 // the thread referred to by |thread_handle| may still be running long-lived /
219 // blocking tasks.
220 #if 0
221 base::ThreadRestrictions::AssertIOAllowed();
222 #endif
223
224 // Wait for the thread to exit. It should already have terminated but make
225 // sure this assumption is valid.
226 DWORD result = WaitForSingleObject(thread_handle.platform_handle(), INFINITE);
227 if (result != WAIT_OBJECT_0) {
228 // Debug info for bug 127931.
229 DWORD error = GetLastError();
230 debug::Alias(&error);
231 debug::Alias(&result);
232 CHECK(false);
233 }
234
235 CloseHandle(thread_handle.platform_handle());
236 }
237
238 // static
239 void PlatformThread::SetCurrentThreadPriority(ThreadPriority priority) {
240 int desired_priority = THREAD_PRIORITY_ERROR_RETURN;
241 switch (priority) {
242 case ThreadPriority::BACKGROUND:
243 desired_priority = THREAD_PRIORITY_LOWEST;
244 break;
245 case ThreadPriority::NORMAL:
246 desired_priority = THREAD_PRIORITY_NORMAL;
247 break;
248 case ThreadPriority::DISPLAY:
249 desired_priority = THREAD_PRIORITY_ABOVE_NORMAL;
250 break;
251 case ThreadPriority::REALTIME_AUDIO:
252 desired_priority = THREAD_PRIORITY_TIME_CRITICAL;
253 break;
254 default:
255 NOTREACHED() << "Unknown priority.";
256 break;
257 }
258 DCHECK_NE(desired_priority, THREAD_PRIORITY_ERROR_RETURN);
259
260 #ifndef NDEBUG
261 const BOOL success =
262 #endif
263 ::SetThreadPriority(PlatformThread::CurrentHandle().platform_handle(),
264 desired_priority);
265 DPLOG_IF(ERROR, !success) << "Failed to set thread priority to "
266 << desired_priority;
267 }
268
269 // static
270 ThreadPriority PlatformThread::GetCurrentThreadPriority() {
271 int priority =
272 ::GetThreadPriority(PlatformThread::CurrentHandle().platform_handle());
273 switch (priority) {
274 case THREAD_PRIORITY_LOWEST:
275 return ThreadPriority::BACKGROUND;
276 case THREAD_PRIORITY_NORMAL:
277 return ThreadPriority::NORMAL;
278 case THREAD_PRIORITY_ABOVE_NORMAL:
279 return ThreadPriority::DISPLAY;
280 case THREAD_PRIORITY_TIME_CRITICAL:
281 return ThreadPriority::REALTIME_AUDIO;
282 case THREAD_PRIORITY_ERROR_RETURN:
283 DPCHECK(false) << "GetThreadPriority error"; // Falls through.
284 default:
285 NOTREACHED() << "Unexpected priority: " << priority;
286 return ThreadPriority::NORMAL;
287 }
288 }
289
290 } // namespace base
OLDNEW
« no previous file with comments | « base/threading/platform_thread_unittest.cc ('k') | base/threading/post_task_and_reply_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698