blob: aa03b91809a4a3e22981202a17517e3a68d98bc0 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000011#include "webrtc/system_wrappers/source/thread_win.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
niklase@google.com470e71d2011-07-07 08:21:25 +000013#include <process.h>
14#include <stdio.h>
15#include <windows.h>
16
tommi@webrtc.orgaef07792015-01-30 15:06:10 +000017#include "webrtc/base/checks.h"
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000018#include "webrtc/system_wrappers/interface/trace.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000019
niklase@google.com470e71d2011-07-07 08:21:25 +000020namespace webrtc {
tommi@webrtc.org9d94a0c2015-02-11 14:16:08 +000021namespace {
22void CALLBACK RaiseFlag(ULONG_PTR param) {
23 *reinterpret_cast<bool*>(param) = true;
24}
tommi@webrtc.orgd3d3baa2015-02-19 19:18:32 +000025
26// TODO(tommi): This is borrowed from webrtc/base/thread.cc, but we can't
27// include thread.h from here since thread.h pulls in libjingle dependencies.
28// Would be good to consolidate.
29
30// As seen on MSDN.
31// http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.71).aspx
32#define MSDEV_SET_THREAD_NAME 0x406D1388
33typedef struct tagTHREADNAME_INFO {
34 DWORD dwType;
35 LPCSTR szName;
36 DWORD dwThreadID;
37 DWORD dwFlags;
38} THREADNAME_INFO;
39
40void SetThreadName(DWORD dwThreadID, LPCSTR szThreadName) {
41 THREADNAME_INFO info;
42 info.dwType = 0x1000;
43 info.szName = szThreadName;
44 info.dwThreadID = dwThreadID;
45 info.dwFlags = 0;
46
47 __try {
48 RaiseException(MSDEV_SET_THREAD_NAME, 0, sizeof(info) / sizeof(DWORD),
49 reinterpret_cast<ULONG_PTR*>(&info));
50 }
51 __except(EXCEPTION_CONTINUE_EXECUTION) {
52 }
53}
54
tommi@webrtc.org9d94a0c2015-02-11 14:16:08 +000055}
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000056
tommi@webrtc.org27c0be92015-03-19 14:35:58 +000057ThreadWindows::ThreadWindows(ThreadRunFunction func, void* obj,
tommi@webrtc.orgb6817d72015-03-20 15:51:39 +000058 const char* thread_name)
tommi@webrtc.orgaef07792015-01-30 15:06:10 +000059 : run_function_(func),
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000060 obj_(obj),
tommi@webrtc.org9d94a0c2015-02-11 14:16:08 +000061 stop_(false),
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000062 thread_(NULL),
tommi@webrtc.orgaef07792015-01-30 15:06:10 +000063 name_(thread_name ? thread_name : "webrtc") {
64 DCHECK(func);
niklase@google.com470e71d2011-07-07 08:21:25 +000065}
66
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000067ThreadWindows::~ThreadWindows() {
tommi@webrtc.orgaef07792015-01-30 15:06:10 +000068 DCHECK(main_thread_.CalledOnValidThread());
69 DCHECK(!thread_);
niklase@google.com470e71d2011-07-07 08:21:25 +000070}
71
tommi@webrtc.orgaef07792015-01-30 15:06:10 +000072// static
pwestin@webrtc.orgb54d7272012-01-11 08:28:04 +000073uint32_t ThreadWrapper::GetThreadId() {
74 return GetCurrentThreadId();
75}
76
tommi@webrtc.orgaef07792015-01-30 15:06:10 +000077// static
78DWORD WINAPI ThreadWindows::StartThread(void* param) {
79 static_cast<ThreadWindows*>(param)->Run();
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000080 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000081}
82
pbos@webrtc.org86639732015-03-13 00:06:21 +000083bool ThreadWindows::Start() {
tommi@webrtc.orgaef07792015-01-30 15:06:10 +000084 DCHECK(main_thread_.CalledOnValidThread());
85 DCHECK(!thread_);
86
tommi@webrtc.org9d94a0c2015-02-11 14:16:08 +000087 stop_ = false;
88
89 // See bug 2902 for background on STACK_SIZE_PARAM_IS_A_RESERVATION.
90 // Set the reserved stack stack size to 1M, which is the default on Windows
91 // and Linux.
tommi@webrtc.orgaef07792015-01-30 15:06:10 +000092 DWORD thread_id;
tommi@webrtc.org9d94a0c2015-02-11 14:16:08 +000093 thread_ = ::CreateThread(NULL, 1024 * 1024, &StartThread, this,
tommi@webrtc.orgaef07792015-01-30 15:06:10 +000094 STACK_SIZE_PARAM_IS_A_RESERVATION, &thread_id);
95 if (!thread_ ) {
96 DCHECK(false) << "CreateThread failed";
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000097 return false;
98 }
niklase@google.com470e71d2011-07-07 08:21:25 +000099
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000100 return true;
101}
102
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000103bool ThreadWindows::Stop() {
tommi@webrtc.orgaef07792015-01-30 15:06:10 +0000104 DCHECK(main_thread_.CalledOnValidThread());
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000105 if (thread_) {
tommi@webrtc.org9d94a0c2015-02-11 14:16:08 +0000106 // Set stop_ to |true| on the worker thread.
107 QueueUserAPC(&RaiseFlag, thread_, reinterpret_cast<ULONG_PTR>(&stop_));
tommi@webrtc.orgaef07792015-01-30 15:06:10 +0000108 WaitForSingleObject(thread_, INFINITE);
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000109 CloseHandle(thread_);
tommi@webrtc.orgaef07792015-01-30 15:06:10 +0000110 thread_ = nullptr;
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000111 }
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000112
tommi@webrtc.orgaef07792015-01-30 15:06:10 +0000113 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000114}
115
tommi@webrtc.orgb6817d72015-03-20 15:51:39 +0000116bool ThreadWindows::SetPriority(ThreadPriority priority) {
117 DCHECK(main_thread_.CalledOnValidThread());
118 return thread_ && SetThreadPriority(thread_, priority);
119}
120
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000121void ThreadWindows::Run() {
tommi@webrtc.orgaef07792015-01-30 15:06:10 +0000122 if (!name_.empty())
123 SetThreadName(static_cast<DWORD>(-1), name_.c_str());
niklase@google.com470e71d2011-07-07 08:21:25 +0000124
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000125 do {
tommi@webrtc.org9d94a0c2015-02-11 14:16:08 +0000126 // The interface contract of Start/Stop is that for a successfull call to
127 // Start, there should be at least one call to the run function. So we
128 // call the function before checking |stop_|.
tommi@webrtc.orgaef07792015-01-30 15:06:10 +0000129 if (!run_function_(obj_))
130 break;
tommi@webrtc.org9d94a0c2015-02-11 14:16:08 +0000131 // Alertable sleep to permit RaiseFlag to run and update |stop_|.
132 SleepEx(0, true);
133 } while (!stop_);
tommi@webrtc.orgaef07792015-01-30 15:06:10 +0000134}
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000135
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000136} // namespace webrtc