blob: 4599bedc274942f84057840796ed15ec96feb70d [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
andrew@webrtc.org59ccd5c2011-12-15 00:17:43 +000011#include "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
andrew@webrtc.org59ccd5c2011-12-15 00:17:43 +000018#include "set_thread_name_win.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000019#include "trace.h"
20
21#if defined(_WIN32)
22// VS 2005: Disable warnings for default initialized arrays.
23#pragma warning(disable:4351)
24#endif
25
26namespace webrtc {
27ThreadWindows::ThreadWindows(ThreadRunFunction func, ThreadObj obj,
28 ThreadPriority prio, const char* threadName)
29 : ThreadWrapper(),
30 _runFunction(func),
31 _obj(obj),
32 _alive(false),
33 _dead(true),
34 _doNotCloseHandle(false),
35 _prio(prio),
36 _event(NULL),
37 _thread(NULL),
38 _id(0),
39 _name(),
40 _setThreadName(false)
41{
42 _event = EventWrapper::Create();
43 _critsectStop = CriticalSectionWrapper::CreateCriticalSection();
44 if (threadName != NULL)
45 {
46 // Set the thread name to appear in the VS debugger.
47 _setThreadName = true;
48 strncpy(_name, threadName, kThreadMaxNameLength);
49 }
50}
51
52ThreadWindows::~ThreadWindows()
53{
54#ifdef _DEBUG
55 assert(!_alive);
56#endif
57 if (_thread)
58 {
59 CloseHandle(_thread);
60 }
61 if(_event)
62 {
63 delete _event;
64 }
65 if(_critsectStop)
66 {
67 delete _critsectStop;
68 }
69}
70
pwestin@webrtc.orgb54d7272012-01-11 08:28:04 +000071uint32_t ThreadWrapper::GetThreadId() {
72 return GetCurrentThreadId();
73}
74
niklase@google.com470e71d2011-07-07 08:21:25 +000075unsigned int WINAPI ThreadWindows::StartThread(LPVOID lpParameter)
76{
77 static_cast<ThreadWindows*>(lpParameter)->Run();
78 return 0;
79}
80
81bool ThreadWindows::Start(unsigned int& threadID)
82{
83 _doNotCloseHandle = false;
84
85 // Set stack size to 1M
86 _thread=(HANDLE)_beginthreadex(NULL, 1024*1024, StartThread, (void*)this, 0,
87 &threadID);
88 if(_thread == NULL)
89 {
90 return false;
91 }
92 _id = threadID;
93 _event->Wait(INFINITE);
94
95 switch(_prio)
96 {
97 case kLowPriority:
98 SetThreadPriority(_thread, THREAD_PRIORITY_BELOW_NORMAL);
99 break;
100 case kNormalPriority:
101 SetThreadPriority(_thread, THREAD_PRIORITY_NORMAL);
102 break;
103 case kHighPriority:
104 SetThreadPriority(_thread, THREAD_PRIORITY_ABOVE_NORMAL);
105 break;
106 case kHighestPriority:
107 SetThreadPriority(_thread, THREAD_PRIORITY_HIGHEST);
108 break;
109 case kRealtimePriority:
110 SetThreadPriority(_thread, THREAD_PRIORITY_TIME_CRITICAL);
111 break;
112 };
113 return true;
114}
115
116bool ThreadWindows::SetAffinity(const int* processorNumbers,
117 const unsigned int amountOfProcessors)
118{
119 DWORD_PTR processorBitMask = 0;
120 for(unsigned int processorIndex = 0;
121 processorIndex < amountOfProcessors;
122 processorIndex++)
123 {
124 // Convert from an array with processor numbers to a bitmask
125 // Processor numbers start at zero.
126 // TODO (hellner): this looks like a bug. Shouldn't the '=' be a '+='?
127 // Or even better |=
128 processorBitMask = 1 << processorNumbers[processorIndex];
129 }
130 return SetThreadAffinityMask(_thread,processorBitMask) != 0;
131}
132
133void ThreadWindows::SetNotAlive()
134{
135 _alive = false;
136}
137
138bool ThreadWindows::Shutdown()
139{
140 DWORD exitCode = 0;
141 BOOL ret = TRUE;
142 if (_thread)
143 {
144 ret = TerminateThread(_thread, exitCode);
145 _alive = false;
146 _dead = true;
147 _thread = NULL;
148 }
149 return ret == TRUE;
150}
151
152bool ThreadWindows::Stop()
153{
154 _critsectStop->Enter();
155 // Prevents the handle from being closed in ThreadWindows::Run()
156 _doNotCloseHandle = true;
157 _alive = false;
158 bool signaled = false;
159 if (_thread && !_dead)
160 {
161 _critsectStop->Leave();
162 // Wait up to 2 seconds for the thread to complete.
163 if( WAIT_OBJECT_0 == WaitForSingleObject(_thread, 2000))
164 {
165 signaled = true;
166 }
167 _critsectStop->Enter();
168 }
169 if (_thread)
170 {
171 CloseHandle(_thread);
172 _thread = NULL;
173 }
174 _critsectStop->Leave();
175
176 if (_dead || signaled)
177 {
178 return true;
179 }
180 else
181 {
182 return false;
183 }
184}
185
186void ThreadWindows::Run()
187{
188 _alive = true;
189 _dead = false;
190 _event->Set();
191
192 // All tracing must be after _event->Set to avoid deadlock in Trace.
193 if (_setThreadName)
194 {
195 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, _id,
196 "Thread with name:%s started ", _name);
197 SetThreadName(-1, _name); // -1, set thread name for the calling thread.
198 }else
199 {
200 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, _id,
201 "Thread without name started");
202 }
203
204 do
205 {
206 if (_runFunction)
207 {
208 if (!_runFunction(_obj))
209 {
210 _alive = false;
211 }
212 } else {
213 _alive = false;
214 }
215 } while(_alive);
216
217 if (_setThreadName)
218 {
219 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, _id,
220 "Thread with name:%s stopped", _name);
221 } else {
222 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility,_id,
223 "Thread without name stopped");
224 }
225
226 _critsectStop->Enter();
227
228 if (_thread && !_doNotCloseHandle)
229 {
230 HANDLE thread = _thread;
231 _thread = NULL;
232 CloseHandle(thread);
233 }
234 _dead = true;
235
236 _critsectStop->Leave();
237};
238} // namespace webrtc