OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 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/thread_restrictions.h" | |
9 #include "base/win/windows_version.h" | |
10 | |
11 namespace { | |
12 | |
13 // The information on how to set the thread name comes from | |
14 // a MSDN article: http://msdn2.microsoft.com/en-us/library/xcb2z8hs.aspx | |
15 const DWORD kVCThreadNameException = 0x406D1388; | |
16 | |
17 typedef struct tagTHREADNAME_INFO { | |
18 DWORD dwType; // Must be 0x1000. | |
19 LPCSTR szName; // Pointer to name (in user addr space). | |
20 DWORD dwThreadID; // Thread ID (-1=caller thread). | |
21 DWORD dwFlags; // Reserved for future use, must be zero. | |
22 } THREADNAME_INFO; | |
23 | |
24 struct ThreadParams { | |
25 PlatformThread::Delegate* delegate; | |
26 bool joinable; | |
27 }; | |
28 | |
29 DWORD __stdcall ThreadFunc(void* params) { | |
30 ThreadParams* thread_params = static_cast<ThreadParams*>(params); | |
31 PlatformThread::Delegate* delegate = thread_params->delegate; | |
32 if (!thread_params->joinable) | |
33 base::ThreadRestrictions::SetSingletonAllowed(false); | |
34 delete thread_params; | |
35 delegate->ThreadMain(); | |
36 return NULL; | |
37 } | |
38 | |
39 // CreateThreadInternal() matches PlatformThread::Create(), except that | |
40 // |out_thread_handle| may be NULL, in which case a non-joinable thread is | |
41 // created. | |
42 bool CreateThreadInternal(size_t stack_size, | |
43 PlatformThread::Delegate* delegate, | |
44 PlatformThreadHandle* out_thread_handle) { | |
45 PlatformThreadHandle thread_handle; | |
46 unsigned int flags = 0; | |
47 if (stack_size > 0 && base::win::GetVersion() >= base::win::VERSION_XP) { | |
48 flags = STACK_SIZE_PARAM_IS_A_RESERVATION; | |
49 } else { | |
50 stack_size = 0; | |
51 } | |
52 | |
53 ThreadParams* params = new ThreadParams; | |
54 params->delegate = delegate; | |
55 params->joinable = out_thread_handle != NULL; | |
56 | |
57 // Using CreateThread here vs _beginthreadex makes thread creation a bit | |
58 // faster and doesn't require the loader lock to be available. Our code will | |
59 // have to work running on CreateThread() threads anyway, since we run code | |
60 // on the Windows thread pool, etc. For some background on the difference: | |
61 // http://www.microsoft.com/msj/1099/win32/win321099.aspx | |
62 thread_handle = CreateThread( | |
63 NULL, stack_size, ThreadFunc, params, flags, NULL); | |
64 if (!thread_handle) { | |
65 delete params; | |
66 return false; | |
67 } | |
68 | |
69 if (out_thread_handle) | |
70 *out_thread_handle = thread_handle; | |
71 else | |
72 CloseHandle(thread_handle); | |
73 return true; | |
74 } | |
75 | |
76 } // namespace | |
77 | |
78 // static | |
79 PlatformThreadId PlatformThread::CurrentId() { | |
80 return GetCurrentThreadId(); | |
81 } | |
82 | |
83 // static | |
84 void PlatformThread::YieldCurrentThread() { | |
85 ::Sleep(0); | |
86 } | |
87 | |
88 // static | |
89 void PlatformThread::Sleep(int duration_ms) { | |
90 ::Sleep(duration_ms); | |
91 } | |
92 | |
93 // static | |
94 void PlatformThread::SetName(const char* name) { | |
95 // The debugger needs to be around to catch the name in the exception. If | |
96 // there isn't a debugger, we are just needlessly throwing an exception. | |
97 if (!::IsDebuggerPresent()) | |
98 return; | |
99 | |
100 THREADNAME_INFO info; | |
101 info.dwType = 0x1000; | |
102 info.szName = name; | |
103 info.dwThreadID = CurrentId(); | |
104 info.dwFlags = 0; | |
105 | |
106 __try { | |
107 RaiseException(kVCThreadNameException, 0, sizeof(info)/sizeof(DWORD), | |
108 reinterpret_cast<DWORD_PTR*>(&info)); | |
109 } __except(EXCEPTION_CONTINUE_EXECUTION) { | |
110 } | |
111 } | |
112 | |
113 // static | |
114 bool PlatformThread::Create(size_t stack_size, Delegate* delegate, | |
115 PlatformThreadHandle* thread_handle) { | |
116 DCHECK(thread_handle); | |
117 return CreateThreadInternal(stack_size, delegate, thread_handle); | |
118 } | |
119 | |
120 // static | |
121 bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) { | |
122 return CreateThreadInternal(stack_size, delegate, NULL); | |
123 } | |
124 | |
125 // static | |
126 void PlatformThread::Join(PlatformThreadHandle thread_handle) { | |
127 DCHECK(thread_handle); | |
128 // TODO(willchan): Enable this check once I can get it to work for Windows | |
129 // shutdown. | |
130 // Joining another thread may block the current thread for a long time, since | |
131 // the thread referred to by |thread_handle| may still be running long-lived / | |
132 // blocking tasks. | |
133 #if 0 | |
134 base::ThreadRestrictions::AssertIOAllowed(); | |
135 #endif | |
136 | |
137 // Wait for the thread to exit. It should already have terminated but make | |
138 // sure this assumption is valid. | |
139 DWORD result = WaitForSingleObject(thread_handle, INFINITE); | |
140 DCHECK_EQ(WAIT_OBJECT_0, result); | |
141 | |
142 CloseHandle(thread_handle); | |
143 } | |
OLD | NEW |