blob: c68ee1ad780d3467e6fd7d183fb3d66b30ac4aa7 [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
105bool ThreadWindows::SetAffinity(const int* processor_numbers,
106 const unsigned int amount_of_processors) {
107 DWORD_PTR processor_bit_mask = 0;
108 for (unsigned int processor_index = 0;
109 processor_index < amount_of_processors;
110 ++processor_index) {
111 // Convert from an array with processor numbers to a bitmask
112 // Processor numbers start at zero.
113 // TODO(hellner): this looks like a bug. Shouldn't the '=' be a '+='?
114 // Or even better |=
115 processor_bit_mask = 1 << processor_numbers[processor_index];
116 }
117 return SetThreadAffinityMask(thread_, processor_bit_mask) != 0;
118}
119
120void ThreadWindows::SetNotAlive() {
121 alive_ = false;
122}
123
124bool ThreadWindows::Stop() {
125 critsect_stop_->Enter();
126
127 // Prevents the handle from being closed in ThreadWindows::Run()
128 do_not_close_handle_ = true;
129 alive_ = false;
130 bool signaled = false;
131 if (thread_ && !dead_) {
132 critsect_stop_->Leave();
133
134 // Wait up to 2 seconds for the thread to complete.
135 if (WAIT_OBJECT_0 == WaitForSingleObject(thread_, 2000)) {
136 signaled = true;
137 }
138 critsect_stop_->Enter();
139 }
140 if (thread_) {
141 CloseHandle(thread_);
142 thread_ = NULL;
143 }
144 critsect_stop_->Leave();
145
146 if (dead_ || signaled) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000147 return true;
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000148 } else {
149 return false;
150 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000151}
152
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000153void ThreadWindows::Run() {
154 alive_ = true;
155 dead_ = false;
156 event_->Set();
niklase@google.com470e71d2011-07-07 08:21:25 +0000157
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000158 // All tracing must be after event_->Set to avoid deadlock in Trace.
159 if (set_thread_name_) {
160 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, id_,
161 "Thread with name:%s started ", name_);
162 SetThreadName(-1, name_); // -1, set thread name for the calling thread.
163 } else {
164 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, id_,
165 "Thread without name started");
166 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000167
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000168 do {
169 if (run_function_) {
170 if (!run_function_(obj_)) {
171 alive_ = false;
172 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000173 } else {
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000174 alive_ = false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000175 }
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000176 } while (alive_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000177
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000178 if (set_thread_name_) {
179 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, id_,
180 "Thread with name:%s stopped", name_);
181 } else {
182 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, id_,
183 "Thread without name stopped");
184 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000185
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000186 critsect_stop_->Enter();
niklase@google.com470e71d2011-07-07 08:21:25 +0000187
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000188 if (thread_ && !do_not_close_handle_) {
189 HANDLE thread = thread_;
190 thread_ = NULL;
191 CloseHandle(thread);
192 }
193 dead_ = true;
194
195 critsect_stop_->Leave();
niklase@google.com470e71d2011-07-07 08:21:25 +0000196};
phoglund@webrtc.orgec9c9422013-01-02 08:45:03 +0000197
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000198} // namespace webrtc