1731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
53f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/platform_thread.h"
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h"
83f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread_restrictions.h"
9731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/win/windows_version.h"
10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
113f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsennamespace base {
123f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace {
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// The information on how to set the thread name comes from
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// a MSDN article: http://msdn2.microsoft.com/en-us/library/xcb2z8hs.aspx
17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottconst DWORD kVCThreadNameException = 0x406D1388;
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scotttypedef struct tagTHREADNAME_INFO {
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DWORD dwType;  // Must be 0x1000.
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  LPCSTR szName;  // Pointer to name (in user addr space).
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DWORD dwThreadID;  // Thread ID (-1=caller thread).
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DWORD dwFlags;  // Reserved for future use, must be zero.
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} THREADNAME_INFO;
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
26201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochstruct ThreadParams {
27201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  PlatformThread::Delegate* delegate;
28201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  bool joinable;
29201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch};
30201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
31201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben MurdochDWORD __stdcall ThreadFunc(void* params) {
32201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  ThreadParams* thread_params = static_cast<ThreadParams*>(params);
33201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  PlatformThread::Delegate* delegate = thread_params->delegate;
34201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (!thread_params->joinable)
35201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    base::ThreadRestrictions::SetSingletonAllowed(false);
36201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  delete thread_params;
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  delegate->ThreadMain();
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return NULL;
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
41201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// CreateThreadInternal() matches PlatformThread::Create(), except that
42201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// |out_thread_handle| may be NULL, in which case a non-joinable thread is
43201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// created.
44201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochbool CreateThreadInternal(size_t stack_size,
45201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                          PlatformThread::Delegate* delegate,
46201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                          PlatformThreadHandle* out_thread_handle) {
47201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  PlatformThreadHandle thread_handle;
48201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  unsigned int flags = 0;
49201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (stack_size > 0 && base::win::GetVersion() >= base::win::VERSION_XP) {
50201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    flags = STACK_SIZE_PARAM_IS_A_RESERVATION;
51201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  } else {
52201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    stack_size = 0;
53201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
54201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
55201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  ThreadParams* params = new ThreadParams;
56201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  params->delegate = delegate;
57201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  params->joinable = out_thread_handle != NULL;
58201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
59201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // Using CreateThread here vs _beginthreadex makes thread creation a bit
60201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // faster and doesn't require the loader lock to be available.  Our code will
61201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // have to work running on CreateThread() threads anyway, since we run code
62201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // on the Windows thread pool, etc.  For some background on the difference:
63201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  //   http://www.microsoft.com/msj/1099/win32/win321099.aspx
64201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  thread_handle = CreateThread(
65201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      NULL, stack_size, ThreadFunc, params, flags, NULL);
66201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (!thread_handle) {
67201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    delete params;
68201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    return false;
69201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
70201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
71201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (out_thread_handle)
72201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    *out_thread_handle = thread_handle;
73201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  else
74201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    CloseHandle(thread_handle);
75201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  return true;
76201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
77201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottPlatformThreadId PlatformThread::CurrentId() {
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return GetCurrentThreadId();
83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid PlatformThread::YieldCurrentThread() {
87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ::Sleep(0);
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid PlatformThread::Sleep(int duration_ms) {
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ::Sleep(duration_ms);
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid PlatformThread::SetName(const char* name) {
97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // The debugger needs to be around to catch the name in the exception.  If
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // there isn't a debugger, we are just needlessly throwing an exception.
99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!::IsDebuggerPresent())
100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;
101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  THREADNAME_INFO info;
103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  info.dwType = 0x1000;
104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  info.szName = name;
105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  info.dwThreadID = CurrentId();
106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  info.dwFlags = 0;
107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  __try {
109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    RaiseException(kVCThreadNameException, 0, sizeof(info)/sizeof(DWORD),
110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                   reinterpret_cast<DWORD_PTR*>(&info));
111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } __except(EXCEPTION_CONTINUE_EXECUTION) {
112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool PlatformThread::Create(size_t stack_size, Delegate* delegate,
117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            PlatformThreadHandle* thread_handle) {
118201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DCHECK(thread_handle);
119201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  return CreateThreadInternal(stack_size, delegate, thread_handle);
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
124201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  return CreateThreadInternal(stack_size, delegate, NULL);
125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid PlatformThread::Join(PlatformThreadHandle thread_handle) {
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(thread_handle);
13021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // TODO(willchan): Enable this check once I can get it to work for Windows
13121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // shutdown.
13221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Joining another thread may block the current thread for a long time, since
13321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // the thread referred to by |thread_handle| may still be running long-lived /
13421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // blocking tasks.
13521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#if 0
13621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  base::ThreadRestrictions::AssertIOAllowed();
13721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#endif
138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Wait for the thread to exit.  It should already have terminated but make
140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // sure this assumption is valid.
141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DWORD result = WaitForSingleObject(thread_handle, INFINITE);
142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(WAIT_OBJECT_0, result);
143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CloseHandle(thread_handle);
145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
1463f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
1473f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen}  // namespace base
148