blob: 2037a6f5ea1997b12fd6c913f81bf14b55c961f8 [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
13#include <assert.h>
14#include <process.h>
15#include <stdio.h>
16#include <windows.h>
17
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000018#include "webrtc/system_wrappers/interface/trace.h"
19#include "webrtc/system_wrappers/source/set_thread_name_win.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000020
niklase@google.com470e71d2011-07-07 08:21:25 +000021namespace webrtc {
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000022
niklase@google.com470e71d2011-07-07 08:21:25 +000023ThreadWindows::ThreadWindows(ThreadRunFunction func, ThreadObj obj,
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000024 ThreadPriority prio, const char* thread_name)
niklase@google.com470e71d2011-07-07 08:21:25 +000025 : ThreadWrapper(),
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000026 run_function_(func),
27 obj_(obj),
28 alive_(false),
29 dead_(true),
30 do_not_close_handle_(false),
31 prio_(prio),
32 event_(NULL),
33 thread_(NULL),
34 id_(0),
35 name_(),
36 set_thread_name_(false) {
37 event_ = EventWrapper::Create();
38 critsect_stop_ = CriticalSectionWrapper::CreateCriticalSection();
39 if (thread_name != NULL) {
40 // Set the thread name to appear in the VS debugger.
41 set_thread_name_ = true;
42 strncpy(name_, thread_name, kThreadMaxNameLength);
43 }
niklase@google.com470e71d2011-07-07 08:21:25 +000044}
45
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000046ThreadWindows::~ThreadWindows() {
niklase@google.com470e71d2011-07-07 08:21:25 +000047#ifdef _DEBUG
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000048 assert(!alive_);
niklase@google.com470e71d2011-07-07 08:21:25 +000049#endif
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000050 if (thread_) {
51 CloseHandle(thread_);
52 }
53 if (event_) {
54 delete event_;
55 }
56 if (critsect_stop_) {
57 delete critsect_stop_;
58 }
niklase@google.com470e71d2011-07-07 08:21:25 +000059}
60
pwestin@webrtc.orgb54d7272012-01-11 08:28:04 +000061uint32_t ThreadWrapper::GetThreadId() {
62 return GetCurrentThreadId();
63}
64
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000065unsigned int WINAPI ThreadWindows::StartThread(LPVOID lp_parameter) {
66 static_cast<ThreadWindows*>(lp_parameter)->Run();
67 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000068}
69
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000070bool ThreadWindows::Start(unsigned int& thread_id) {
71 if (!run_function_) {
72 return false;
73 }
74 do_not_close_handle_ = false;
niklase@google.com470e71d2011-07-07 08:21:25 +000075
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000076 // Set stack size to 1M
77 thread_ = (HANDLE)_beginthreadex(NULL, 1024 * 1024, StartThread, (void*)this,
78 0, &thread_id);
79 if (thread_ == NULL) {
80 return false;
81 }
82 id_ = thread_id;
83 event_->Wait(INFINITE);
niklase@google.com470e71d2011-07-07 08:21:25 +000084
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000085 switch (prio_) {
niklase@google.com470e71d2011-07-07 08:21:25 +000086 case kLowPriority:
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000087 SetThreadPriority(thread_, THREAD_PRIORITY_BELOW_NORMAL);
88 break;
niklase@google.com470e71d2011-07-07 08:21:25 +000089 case kNormalPriority:
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000090 SetThreadPriority(thread_, THREAD_PRIORITY_NORMAL);
91 break;
niklase@google.com470e71d2011-07-07 08:21:25 +000092 case kHighPriority:
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000093 SetThreadPriority(thread_, THREAD_PRIORITY_ABOVE_NORMAL);
94 break;
niklase@google.com470e71d2011-07-07 08:21:25 +000095 case kHighestPriority:
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000096 SetThreadPriority(thread_, THREAD_PRIORITY_HIGHEST);
97 break;
niklase@google.com470e71d2011-07-07 08:21:25 +000098 case kRealtimePriority:
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +000099 SetThreadPriority(thread_, THREAD_PRIORITY_TIME_CRITICAL);
100 break;
101 };
102 return true;
103}
104
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000105void ThreadWindows::SetNotAlive() {
106 alive_ = false;
107}
108
109bool ThreadWindows::Stop() {
110 critsect_stop_->Enter();
111
112 // Prevents the handle from being closed in ThreadWindows::Run()
113 do_not_close_handle_ = true;
114 alive_ = false;
115 bool signaled = false;
116 if (thread_ && !dead_) {
117 critsect_stop_->Leave();
118
119 // Wait up to 2 seconds for the thread to complete.
120 if (WAIT_OBJECT_0 == WaitForSingleObject(thread_, 2000)) {
121 signaled = true;
122 }
123 critsect_stop_->Enter();
124 }
125 if (thread_) {
126 CloseHandle(thread_);
127 thread_ = NULL;
128 }
129 critsect_stop_->Leave();
130
131 if (dead_ || signaled) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000132 return true;
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000133 } else {
134 return false;
135 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000136}
137
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000138void ThreadWindows::Run() {
139 alive_ = true;
140 dead_ = false;
141 event_->Set();
niklase@google.com470e71d2011-07-07 08:21:25 +0000142
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000143 // All tracing must be after event_->Set to avoid deadlock in Trace.
144 if (set_thread_name_) {
145 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, id_,
146 "Thread with name:%s started ", name_);
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +0000147 SetThreadName(static_cast<DWORD>(-1), name_); // -1 == caller thread.
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000148 } else {
149 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, id_,
150 "Thread without name started");
151 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000152
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000153 do {
154 if (run_function_) {
155 if (!run_function_(obj_)) {
156 alive_ = false;
157 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000158 } else {
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000159 alive_ = false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000160 }
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000161 } while (alive_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000162
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000163 if (set_thread_name_) {
164 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, id_,
165 "Thread with name:%s stopped", name_);
166 } else {
167 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, id_,
168 "Thread without name stopped");
169 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000170
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000171 critsect_stop_->Enter();
niklase@google.com470e71d2011-07-07 08:21:25 +0000172
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000173 if (thread_ && !do_not_close_handle_) {
174 HANDLE thread = thread_;
175 thread_ = NULL;
176 CloseHandle(thread);
177 }
178 dead_ = true;
179
180 critsect_stop_->Leave();
niklase@google.com470e71d2011-07-07 08:21:25 +0000181};
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000182
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000183} // namespace webrtc