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