|
1 // Copyright (c) 2006-2008 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/platform_thread.h" |
|
6 |
|
7 #include "base/logging.h" |
|
8 #include "base/win_util.h" |
|
9 |
|
10 namespace { |
|
11 |
|
12 // The information on how to set the thread name comes from |
|
13 // a MSDN article: http://msdn2.microsoft.com/en-us/library/xcb2z8hs.aspx |
|
14 const DWORD kVCThreadNameException = 0x406D1388; |
|
15 |
|
16 typedef struct tagTHREADNAME_INFO { |
|
17 DWORD dwType; // Must be 0x1000. |
|
18 LPCSTR szName; // Pointer to name (in user addr space). |
|
19 DWORD dwThreadID; // Thread ID (-1=caller thread). |
|
20 DWORD dwFlags; // Reserved for future use, must be zero. |
|
21 } THREADNAME_INFO; |
|
22 |
|
23 DWORD __stdcall ThreadFunc(void* closure) { |
|
24 PlatformThread::Delegate* delegate = |
|
25 static_cast<PlatformThread::Delegate*>(closure); |
|
26 delegate->ThreadMain(); |
|
27 return 0; |
|
28 } |
|
29 |
|
30 } // namespace |
|
31 |
|
32 // static |
|
33 PlatformThreadId PlatformThread::CurrentId() { |
|
34 return GetCurrentThreadId(); |
|
35 } |
|
36 |
|
37 // static |
|
38 void PlatformThread::YieldCurrentThread() { |
|
39 ::Sleep(0); |
|
40 } |
|
41 |
|
42 // static |
|
43 void PlatformThread::Sleep(int duration_ms) { |
|
44 ::Sleep(duration_ms); |
|
45 } |
|
46 |
|
47 // static |
|
48 void PlatformThread::SetName(const char* name) { |
|
49 // The debugger needs to be around to catch the name in the exception. If |
|
50 // there isn't a debugger, we are just needlessly throwing an exception. |
|
51 if (!::IsDebuggerPresent()) |
|
52 return; |
|
53 |
|
54 THREADNAME_INFO info; |
|
55 info.dwType = 0x1000; |
|
56 info.szName = name; |
|
57 info.dwThreadID = CurrentId(); |
|
58 info.dwFlags = 0; |
|
59 |
|
60 MOZ_SEH_TRY { |
|
61 RaiseException(kVCThreadNameException, 0, sizeof(info)/sizeof(DWORD), |
|
62 reinterpret_cast<DWORD_PTR*>(&info)); |
|
63 } MOZ_SEH_EXCEPT(EXCEPTION_CONTINUE_EXECUTION) { |
|
64 } |
|
65 } |
|
66 |
|
67 // static |
|
68 bool PlatformThread::Create(size_t stack_size, Delegate* delegate, |
|
69 PlatformThreadHandle* thread_handle) { |
|
70 unsigned int flags = 0; |
|
71 if (stack_size > 0 && win_util::GetWinVersion() >= win_util::WINVERSION_XP) { |
|
72 flags = STACK_SIZE_PARAM_IS_A_RESERVATION; |
|
73 } else { |
|
74 stack_size = 0; |
|
75 } |
|
76 |
|
77 // Using CreateThread here vs _beginthreadex makes thread creation a bit |
|
78 // faster and doesn't require the loader lock to be available. Our code will |
|
79 // have to work running on CreateThread() threads anyway, since we run code |
|
80 // on the Windows thread pool, etc. For some background on the difference: |
|
81 // http://www.microsoft.com/msj/1099/win32/win321099.aspx |
|
82 *thread_handle = CreateThread( |
|
83 NULL, stack_size, ThreadFunc, delegate, flags, NULL); |
|
84 return *thread_handle != NULL; |
|
85 } |
|
86 |
|
87 // static |
|
88 bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) { |
|
89 PlatformThreadHandle thread_handle; |
|
90 bool result = Create(stack_size, delegate, &thread_handle); |
|
91 CloseHandle(thread_handle); |
|
92 return result; |
|
93 } |
|
94 |
|
95 // static |
|
96 void PlatformThread::Join(PlatformThreadHandle thread_handle) { |
|
97 DCHECK(thread_handle); |
|
98 |
|
99 // Wait for the thread to exit. It should already have terminated but make |
|
100 // sure this assumption is valid. |
|
101 DWORD result = WaitForSingleObject(thread_handle, INFINITE); |
|
102 DCHECK_EQ(WAIT_OBJECT_0, result); |
|
103 |
|
104 CloseHandle(thread_handle); |
|
105 } |