| /* |
| * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "webrtc/system_wrappers/source/thread_win.h" |
| |
| #include <assert.h> |
| #include <process.h> |
| #include <stdio.h> |
| #include <windows.h> |
| |
| #include "webrtc/system_wrappers/interface/trace.h" |
| #include "webrtc/system_wrappers/source/set_thread_name_win.h" |
| |
| namespace webrtc { |
| |
| ThreadWindows::ThreadWindows(ThreadRunFunction func, ThreadObj obj, |
| ThreadPriority prio, const char* thread_name) |
| : ThreadWrapper(), |
| run_function_(func), |
| obj_(obj), |
| alive_(false), |
| dead_(true), |
| do_not_close_handle_(false), |
| prio_(prio), |
| event_(NULL), |
| thread_(NULL), |
| id_(0), |
| name_(), |
| set_thread_name_(false) { |
| event_ = EventWrapper::Create(); |
| critsect_stop_ = CriticalSectionWrapper::CreateCriticalSection(); |
| if (thread_name != NULL) { |
| // Set the thread name to appear in the VS debugger. |
| set_thread_name_ = true; |
| strncpy(name_, thread_name, kThreadMaxNameLength); |
| } |
| } |
| |
| ThreadWindows::~ThreadWindows() { |
| #ifdef _DEBUG |
| assert(!alive_); |
| #endif |
| if (thread_) { |
| CloseHandle(thread_); |
| } |
| if (event_) { |
| delete event_; |
| } |
| if (critsect_stop_) { |
| delete critsect_stop_; |
| } |
| } |
| |
| uint32_t ThreadWrapper::GetThreadId() { |
| return GetCurrentThreadId(); |
| } |
| |
| unsigned int WINAPI ThreadWindows::StartThread(LPVOID lp_parameter) { |
| static_cast<ThreadWindows*>(lp_parameter)->Run(); |
| return 0; |
| } |
| |
| bool ThreadWindows::Start(unsigned int& thread_id) { |
| if (!run_function_) { |
| return false; |
| } |
| do_not_close_handle_ = false; |
| |
| // Set stack size to 1M |
| thread_ = (HANDLE)_beginthreadex(NULL, 1024 * 1024, StartThread, (void*)this, |
| 0, &thread_id); |
| if (thread_ == NULL) { |
| return false; |
| } |
| id_ = thread_id; |
| event_->Wait(INFINITE); |
| |
| switch (prio_) { |
| case kLowPriority: |
| SetThreadPriority(thread_, THREAD_PRIORITY_BELOW_NORMAL); |
| break; |
| case kNormalPriority: |
| SetThreadPriority(thread_, THREAD_PRIORITY_NORMAL); |
| break; |
| case kHighPriority: |
| SetThreadPriority(thread_, THREAD_PRIORITY_ABOVE_NORMAL); |
| break; |
| case kHighestPriority: |
| SetThreadPriority(thread_, THREAD_PRIORITY_HIGHEST); |
| break; |
| case kRealtimePriority: |
| SetThreadPriority(thread_, THREAD_PRIORITY_TIME_CRITICAL); |
| break; |
| }; |
| return true; |
| } |
| |
| bool ThreadWindows::SetAffinity(const int* processor_numbers, |
| const unsigned int amount_of_processors) { |
| DWORD_PTR processor_bit_mask = 0; |
| for (unsigned int processor_index = 0; |
| processor_index < amount_of_processors; |
| ++processor_index) { |
| // Convert from an array with processor numbers to a bitmask |
| // Processor numbers start at zero. |
| // TODO(hellner): this looks like a bug. Shouldn't the '=' be a '+='? |
| // Or even better |= |
| processor_bit_mask = 1 << processor_numbers[processor_index]; |
| } |
| return SetThreadAffinityMask(thread_, processor_bit_mask) != 0; |
| } |
| |
| void ThreadWindows::SetNotAlive() { |
| alive_ = false; |
| } |
| |
| bool ThreadWindows::Stop() { |
| critsect_stop_->Enter(); |
| |
| // Prevents the handle from being closed in ThreadWindows::Run() |
| do_not_close_handle_ = true; |
| alive_ = false; |
| bool signaled = false; |
| if (thread_ && !dead_) { |
| critsect_stop_->Leave(); |
| |
| // Wait up to 2 seconds for the thread to complete. |
| if (WAIT_OBJECT_0 == WaitForSingleObject(thread_, 2000)) { |
| signaled = true; |
| } |
| critsect_stop_->Enter(); |
| } |
| if (thread_) { |
| CloseHandle(thread_); |
| thread_ = NULL; |
| } |
| critsect_stop_->Leave(); |
| |
| if (dead_ || signaled) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| void ThreadWindows::Run() { |
| alive_ = true; |
| dead_ = false; |
| event_->Set(); |
| |
| // All tracing must be after event_->Set to avoid deadlock in Trace. |
| if (set_thread_name_) { |
| WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, id_, |
| "Thread with name:%s started ", name_); |
| SetThreadName(-1, name_); // -1, set thread name for the calling thread. |
| } else { |
| WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, id_, |
| "Thread without name started"); |
| } |
| |
| do { |
| if (run_function_) { |
| if (!run_function_(obj_)) { |
| alive_ = false; |
| } |
| } else { |
| alive_ = false; |
| } |
| } while (alive_); |
| |
| if (set_thread_name_) { |
| WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, id_, |
| "Thread with name:%s stopped", name_); |
| } else { |
| WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, id_, |
| "Thread without name stopped"); |
| } |
| |
| critsect_stop_->Enter(); |
| |
| if (thread_ && !do_not_close_handle_) { |
| HANDLE thread = thread_; |
| thread_ = NULL; |
| CloseHandle(thread); |
| } |
| dead_ = true; |
| |
| critsect_stop_->Leave(); |
| }; |
| |
| } // namespace webrtc |