blob: 67312fadd1713c23e47b3c5111f5f647aaeb178f [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
niklase@google.com470e71d2011-07-07 08:21:25 +000057ThreadWindows::ThreadWindows(ThreadRunFunction func, ThreadObj obj,
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000058 ThreadPriority prio, 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),
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000061 prio_(prio),
tommi@webrtc.org9d94a0c2015-02-11 14:16:08 +000062 stop_(false),
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000063 thread_(NULL),
tommi@webrtc.orgaef07792015-01-30 15:06:10 +000064 name_(thread_name ? thread_name : "webrtc") {
65 DCHECK(func);
niklase@google.com470e71d2011-07-07 08:21:25 +000066}
67
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000068ThreadWindows::~ThreadWindows() {
tommi@webrtc.orgaef07792015-01-30 15:06:10 +000069 DCHECK(main_thread_.CalledOnValidThread());
70 DCHECK(!thread_);
niklase@google.com470e71d2011-07-07 08:21:25 +000071}
72
tommi@webrtc.orgaef07792015-01-30 15:06:10 +000073// static
pwestin@webrtc.orgb54d7272012-01-11 08:28:04 +000074uint32_t ThreadWrapper::GetThreadId() {
75 return GetCurrentThreadId();
76}
77
tommi@webrtc.orgaef07792015-01-30 15:06:10 +000078// static
79DWORD WINAPI ThreadWindows::StartThread(void* param) {
80 static_cast<ThreadWindows*>(param)->Run();
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000081 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000082}
83
tommi@webrtc.orgaef07792015-01-30 15:06:10 +000084bool ThreadWindows::Start(unsigned int& id) {
85 DCHECK(main_thread_.CalledOnValidThread());
86 DCHECK(!thread_);
87
tommi@webrtc.org9d94a0c2015-02-11 14:16:08 +000088 stop_ = false;
89
90 // See bug 2902 for background on STACK_SIZE_PARAM_IS_A_RESERVATION.
91 // Set the reserved stack stack size to 1M, which is the default on Windows
92 // and Linux.
tommi@webrtc.orgaef07792015-01-30 15:06:10 +000093 DWORD thread_id;
tommi@webrtc.org9d94a0c2015-02-11 14:16:08 +000094 thread_ = ::CreateThread(NULL, 1024 * 1024, &StartThread, this,
tommi@webrtc.orgaef07792015-01-30 15:06:10 +000095 STACK_SIZE_PARAM_IS_A_RESERVATION, &thread_id);
96 if (!thread_ ) {
97 DCHECK(false) << "CreateThread failed";
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000098 return false;
99 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000100
tommi@webrtc.orgaef07792015-01-30 15:06:10 +0000101 id = thread_id;
102
103 if (prio_ != kNormalPriority) {
104 int priority = THREAD_PRIORITY_NORMAL;
105 switch (prio_) {
106 case kLowPriority:
107 priority = THREAD_PRIORITY_BELOW_NORMAL;
108 break;
109 case kHighPriority:
110 priority = THREAD_PRIORITY_ABOVE_NORMAL;
111 break;
112 case kHighestPriority:
113 priority = THREAD_PRIORITY_HIGHEST;
114 break;
115 case kRealtimePriority:
116 priority = THREAD_PRIORITY_TIME_CRITICAL;
117 break;
118 default:
119 break;
120 }
121
122 SetThreadPriority(thread_, priority);
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000123 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000124
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000125 return true;
126}
127
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000128bool ThreadWindows::Stop() {
tommi@webrtc.orgaef07792015-01-30 15:06:10 +0000129 DCHECK(main_thread_.CalledOnValidThread());
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000130 if (thread_) {
tommi@webrtc.org9d94a0c2015-02-11 14:16:08 +0000131 // Set stop_ to |true| on the worker thread.
132 QueueUserAPC(&RaiseFlag, thread_, reinterpret_cast<ULONG_PTR>(&stop_));
tommi@webrtc.orgaef07792015-01-30 15:06:10 +0000133 WaitForSingleObject(thread_, INFINITE);
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000134 CloseHandle(thread_);
tommi@webrtc.orgaef07792015-01-30 15:06:10 +0000135 thread_ = nullptr;
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000136 }
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000137
tommi@webrtc.orgaef07792015-01-30 15:06:10 +0000138 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000139}
140
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000141void ThreadWindows::Run() {
tommi@webrtc.orgaef07792015-01-30 15:06:10 +0000142 if (!name_.empty())
143 SetThreadName(static_cast<DWORD>(-1), name_.c_str());
niklase@google.com470e71d2011-07-07 08:21:25 +0000144
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000145 do {
tommi@webrtc.org9d94a0c2015-02-11 14:16:08 +0000146 // The interface contract of Start/Stop is that for a successfull call to
147 // Start, there should be at least one call to the run function. So we
148 // call the function before checking |stop_|.
tommi@webrtc.orgaef07792015-01-30 15:06:10 +0000149 if (!run_function_(obj_))
150 break;
tommi@webrtc.org9d94a0c2015-02-11 14:16:08 +0000151 // Alertable sleep to permit RaiseFlag to run and update |stop_|.
152 SleepEx(0, true);
153 } while (!stop_);
tommi@webrtc.orgaef07792015-01-30 15:06:10 +0000154}
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000155
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000156} // namespace webrtc