blob: c4a3d71aa03eb2ac2de146ac480181860bc327a6 [file] [log] [blame]
niklase@google.comf0779a22011-05-30 11:39:38 +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
11#include "thread_windows.h"
12
13#include <assert.h>
14#include <process.h>
15#include <stdio.h>
16#include <windows.h>
17
18#include "thread_windows_set_name.h"
19#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
71unsigned int WINAPI ThreadWindows::StartThread(LPVOID lpParameter)
72{
73 static_cast<ThreadWindows*>(lpParameter)->Run();
74 return 0;
75}
76
77bool ThreadWindows::Start(unsigned int& threadID)
78{
79 _doNotCloseHandle = false;
80
81 // Set stack size to 1M
82 _thread=(HANDLE)_beginthreadex(NULL, 1024*1024, StartThread, (void*)this, 0,
83 &threadID);
84 if(_thread == NULL)
85 {
86 return false;
87 }
88 _id = threadID;
89 _event->Wait(INFINITE);
90
91 switch(_prio)
92 {
93 case kLowPriority:
94 SetThreadPriority(_thread, THREAD_PRIORITY_BELOW_NORMAL);
95 break;
96 case kNormalPriority:
97 SetThreadPriority(_thread, THREAD_PRIORITY_NORMAL);
98 break;
99 case kHighPriority:
100 SetThreadPriority(_thread, THREAD_PRIORITY_ABOVE_NORMAL);
101 break;
102 case kHighestPriority:
103 SetThreadPriority(_thread, THREAD_PRIORITY_HIGHEST);
104 break;
105 case kRealtimePriority:
106 SetThreadPriority(_thread, THREAD_PRIORITY_TIME_CRITICAL);
107 break;
108 };
109 return true;
110}
111
112bool ThreadWindows::SetAffinity(const int* processorNumbers,
113 const unsigned int amountOfProcessors)
114{
115 DWORD_PTR processorBitMask = 0;
116 for(unsigned int processorIndex = 0;
117 processorIndex < amountOfProcessors;
118 processorIndex++)
119 {
120 // Convert from an array with processor numbers to a bitmask
121 // Processor numbers start at zero.
122 // TODO (hellner): this looks like a bug. Shouldn't the '=' be a '+='?
123 // Or even better |=
124 processorBitMask = 1 << processorNumbers[processorIndex];
125 }
126 return SetThreadAffinityMask(_thread,processorBitMask) != 0;
127}
128
129void ThreadWindows::SetNotAlive()
130{
131 _alive = false;
132}
133
134bool ThreadWindows::Shutdown()
135{
136 DWORD exitCode = 0;
137 BOOL ret = TRUE;
138 if (_thread)
139 {
140 ret = TerminateThread(_thread, exitCode);
141 _alive = false;
142 _dead = true;
143 _thread = NULL;
144 }
145 return ret == TRUE;
146}
147
148bool ThreadWindows::Stop()
149{
150 _critsectStop->Enter();
151 // Prevents the handle from being closed in ThreadWindows::Run()
152 _doNotCloseHandle = true;
153 _alive = false;
154 bool signaled = false;
155 if (_thread && !_dead)
156 {
157 _critsectStop->Leave();
158 // Wait up to 2 seconds for the thread to complete.
159 if( WAIT_OBJECT_0 == WaitForSingleObject(_thread, 2000))
160 {
161 signaled = true;
162 }
163 _critsectStop->Enter();
164 }
165 if (_thread)
166 {
167 CloseHandle(_thread);
168 _thread = NULL;
169 }
170 _critsectStop->Leave();
171
172 if (_dead || signaled)
173 {
174 return true;
175 }
176 else
177 {
178 return false;
179 }
180}
181
182void ThreadWindows::Run()
183{
184 _alive = true;
185 _dead = false;
186 _event->Set();
187
188 // All tracing must be after _event->Set to avoid deadlock in Trace.
189 if (_setThreadName)
190 {
191 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, _id,
192 "Thread with name:%s started ", _name);
193 SetThreadName(-1, _name); // -1, set thread name for the calling thread.
194 }else
195 {
196 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, _id,
197 "Thread without name started");
198 }
199
200 do
201 {
202 if (_runFunction)
203 {
204 if (!_runFunction(_obj))
205 {
206 _alive = false;
207 }
208 } else {
209 _alive = false;
210 }
211 } while(_alive);
212
213 if (_setThreadName)
214 {
215 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, _id,
216 "Thread with name:%s stopped", _name);
217 } else {
218 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility,_id,
219 "Thread without name stopped");
220 }
221
222 _critsectStop->Enter();
223
224 if (_thread && !_doNotCloseHandle)
225 {
226 HANDLE thread = _thread;
227 _thread = NULL;
228 CloseHandle(thread);
229 }
230 _dead = true;
231
232 _critsectStop->Leave();
233};
234} // namespace webrtc