235 lines
5.5 KiB
C++
235 lines
5.5 KiB
C++
/*
|
|
* 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
|