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