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 { 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 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 66 uint32_t ThreadWrapper::GetThreadId() { 67 return GetCurrentThreadId(); 68 } 69 70 unsigned int WINAPI ThreadWindows::StartThread(LPVOID lpParameter) 71 { 72 static_cast<ThreadWindows*>(lpParameter)->Run(); 73 return 0; 74 } 75 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 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 128 void ThreadWindows::SetNotAlive() 129 { 130 _alive = false; 131 } 132 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 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 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