blob: 0c1a8f209ef15e12c3d05ee3b288fec88fffabe2 [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,
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
pbos@webrtc.org86639732015-03-13 00:06:21 +000084bool ThreadWindows::Start() {
tommi@webrtc.orgaef07792015-01-30 15:06:10 +000085 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 if (prio_ != kNormalPriority) {
102 int priority = THREAD_PRIORITY_NORMAL;
103 switch (prio_) {
104 case kLowPriority:
105 priority = THREAD_PRIORITY_BELOW_NORMAL;
106 break;
107 case kHighPriority:
108 priority = THREAD_PRIORITY_ABOVE_NORMAL;
109 break;
110 case kHighestPriority:
111 priority = THREAD_PRIORITY_HIGHEST;
112 break;
113 case kRealtimePriority:
114 priority = THREAD_PRIORITY_TIME_CRITICAL;
115 break;
116 default:
117 break;
118 }
119
120 SetThreadPriority(thread_, priority);
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000121 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000122
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000123 return true;
124}
125
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000126bool ThreadWindows::Stop() {
tommi@webrtc.orgaef07792015-01-30 15:06:10 +0000127 DCHECK(main_thread_.CalledOnValidThread());
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000128 if (thread_) {
tommi@webrtc.org9d94a0c2015-02-11 14:16:08 +0000129 // Set stop_ to |true| on the worker thread.
130 QueueUserAPC(&RaiseFlag, thread_, reinterpret_cast<ULONG_PTR>(&stop_));
tommi@webrtc.orgaef07792015-01-30 15:06:10 +0000131 WaitForSingleObject(thread_, INFINITE);
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000132 CloseHandle(thread_);
tommi@webrtc.orgaef07792015-01-30 15:06:10 +0000133 thread_ = nullptr;
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000134 }
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000135
tommi@webrtc.orgaef07792015-01-30 15:06:10 +0000136 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000137}
138
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000139void ThreadWindows::Run() {
tommi@webrtc.orgaef07792015-01-30 15:06:10 +0000140 if (!name_.empty())
141 SetThreadName(static_cast<DWORD>(-1), name_.c_str());
niklase@google.com470e71d2011-07-07 08:21:25 +0000142
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000143 do {
tommi@webrtc.org9d94a0c2015-02-11 14:16:08 +0000144 // The interface contract of Start/Stop is that for a successfull call to
145 // Start, there should be at least one call to the run function. So we
146 // call the function before checking |stop_|.
tommi@webrtc.orgaef07792015-01-30 15:06:10 +0000147 if (!run_function_(obj_))
148 break;
tommi@webrtc.org9d94a0c2015-02-11 14:16:08 +0000149 // Alertable sleep to permit RaiseFlag to run and update |stop_|.
150 SleepEx(0, true);
151 } while (!stop_);
tommi@webrtc.orgaef07792015-01-30 15:06:10 +0000152}
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000153
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000154} // namespace webrtc