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