| /* |
| * 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 "thread_windows.h" |
| |
| #include <assert.h> |
| #include <process.h> |
| #include <stdio.h> |
| #include <windows.h> |
| |
| #include "thread_windows_set_name.h" |
| #include "trace.h" |
| |
| #if defined(_WIN32) |
| // VS 2005: Disable warnings for default initialized arrays. |
| #pragma warning(disable:4351) |
| #endif |
| |
| namespace webrtc { |
| ThreadWindows::ThreadWindows(ThreadRunFunction func, ThreadObj obj, |
| ThreadPriority prio, const char* threadName) |
| : ThreadWrapper(), |
| _runFunction(func), |
| _obj(obj), |
| _alive(false), |
| _dead(true), |
| _doNotCloseHandle(false), |
| _prio(prio), |
| _event(NULL), |
| _thread(NULL), |
| _id(0), |
| _name(), |
| _setThreadName(false) |
| { |
| _event = EventWrapper::Create(); |
| _critsectStop = CriticalSectionWrapper::CreateCriticalSection(); |
| if (threadName != NULL) |
| { |
| // Set the thread name to appear in the VS debugger. |
| _setThreadName = true; |
| strncpy(_name, threadName, kThreadMaxNameLength); |
| } |
| } |
| |
| ThreadWindows::~ThreadWindows() |
| { |
| #ifdef _DEBUG |
| assert(!_alive); |
| #endif |
| if (_thread) |
| { |
| CloseHandle(_thread); |
| } |
| if(_event) |
| { |
| delete _event; |
| } |
| if(_critsectStop) |
| { |
| delete _critsectStop; |
| } |
| } |
| |
| unsigned int WINAPI ThreadWindows::StartThread(LPVOID lpParameter) |
| { |
| static_cast<ThreadWindows*>(lpParameter)->Run(); |
| return 0; |
| } |
| |
| bool ThreadWindows::Start(unsigned int& threadID) |
| { |
| _doNotCloseHandle = false; |
| |
| // Set stack size to 1M |
| _thread=(HANDLE)_beginthreadex(NULL, 1024*1024, StartThread, (void*)this, 0, |
| &threadID); |
| if(_thread == NULL) |
| { |
| return false; |
| } |
| _id = threadID; |
| _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* processorNumbers, |
| const unsigned int amountOfProcessors) |
| { |
| DWORD_PTR processorBitMask = 0; |
| for(unsigned int processorIndex = 0; |
| processorIndex < amountOfProcessors; |
| processorIndex++) |
| { |
| // 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 |= |
| processorBitMask = 1 << processorNumbers[processorIndex]; |
| } |
| return SetThreadAffinityMask(_thread,processorBitMask) != 0; |
| } |
| |
| void ThreadWindows::SetNotAlive() |
| { |
| _alive = false; |
| } |
| |
| bool ThreadWindows::Shutdown() |
| { |
| DWORD exitCode = 0; |
| BOOL ret = TRUE; |
| if (_thread) |
| { |
| ret = TerminateThread(_thread, exitCode); |
| _alive = false; |
| _dead = true; |
| _thread = NULL; |
| } |
| return ret == TRUE; |
| } |
| |
| bool ThreadWindows::Stop() |
| { |
| _critsectStop->Enter(); |
| // Prevents the handle from being closed in ThreadWindows::Run() |
| _doNotCloseHandle = true; |
| _alive = false; |
| bool signaled = false; |
| if (_thread && !_dead) |
| { |
| _critsectStop->Leave(); |
| // Wait up to 2 seconds for the thread to complete. |
| if( WAIT_OBJECT_0 == WaitForSingleObject(_thread, 2000)) |
| { |
| signaled = true; |
| } |
| _critsectStop->Enter(); |
| } |
| if (_thread) |
| { |
| CloseHandle(_thread); |
| _thread = NULL; |
| } |
| _critsectStop->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 (_setThreadName) |
| { |
| 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 (_runFunction) |
| { |
| if (!_runFunction(_obj)) |
| { |
| _alive = false; |
| } |
| } else { |
| _alive = false; |
| } |
| } while(_alive); |
| |
| if (_setThreadName) |
| { |
| WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, _id, |
| "Thread with name:%s stopped", _name); |
| } else { |
| WEBRTC_TRACE(kTraceStateInfo, kTraceUtility,_id, |
| "Thread without name stopped"); |
| } |
| |
| _critsectStop->Enter(); |
| |
| if (_thread && !_doNotCloseHandle) |
| { |
| HANDLE thread = _thread; |
| _thread = NULL; |
| CloseHandle(thread); |
| } |
| _dead = true; |
| |
| _critsectStop->Leave(); |
| }; |
| } // namespace webrtc |