2012-11-26 18:58:24 +00:00
|
|
|
/*
|
|
|
|
===========================================================================
|
|
|
|
|
|
|
|
Doom 3 BFG Edition GPL Source Code
|
2012-11-28 15:47:07 +00:00
|
|
|
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
2012-11-26 18:58:24 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
2012-11-26 18:58:24 +00:00
|
|
|
|
|
|
|
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
|
|
|
|
|
|
|
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
|
|
|
|
|
|
|
===========================================================================
|
|
|
|
*/
|
|
|
|
#pragma hdrstop
|
|
|
|
#include "precompiled.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
================================================================================================
|
|
|
|
Contains the vartious ThreadingClass implementations.
|
|
|
|
================================================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
================================================================================================
|
|
|
|
|
|
|
|
idSysThread
|
|
|
|
|
|
|
|
================================================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
========================
|
|
|
|
idSysThread::idSysThread
|
|
|
|
========================
|
|
|
|
*/
|
|
|
|
idSysThread::idSysThread() :
|
2012-11-28 15:47:07 +00:00
|
|
|
threadHandle( 0 ),
|
|
|
|
isWorker( false ),
|
|
|
|
isRunning( false ),
|
|
|
|
isTerminating( false ),
|
|
|
|
moreWorkToDo( false ),
|
|
|
|
signalWorkerDone( true )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
========================
|
|
|
|
idSysThread::~idSysThread
|
|
|
|
========================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
idSysThread::~idSysThread()
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
StopThread( true );
|
2012-11-28 15:47:07 +00:00
|
|
|
if( threadHandle )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
Sys_DestroyThread( threadHandle );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
========================
|
|
|
|
idSysThread::StartThread
|
|
|
|
========================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
bool idSysThread::StartThread( const char* name_, core_t core, xthreadPriority priority, int stackSize )
|
|
|
|
{
|
|
|
|
if( isRunning )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
return false;
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
name = name_;
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
isTerminating = false;
|
2012-11-28 15:47:07 +00:00
|
|
|
|
|
|
|
if( threadHandle )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
Sys_DestroyThread( threadHandle );
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
|
|
|
|
threadHandle = Sys_CreateThread( ( xthread_t )ThreadProc, this, priority, name, core, stackSize, false );
|
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
isRunning = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
========================
|
|
|
|
idSysThread::StartWorkerThread
|
|
|
|
========================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
bool idSysThread::StartWorkerThread( const char* name_, core_t core, xthreadPriority priority, int stackSize )
|
|
|
|
{
|
|
|
|
if( isRunning )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
return false;
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
isWorker = true;
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
bool result = StartThread( name_, core, priority, stackSize );
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
signalWorkerDone.Wait( idSysSignal::WAIT_INFINITE );
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
========================
|
|
|
|
idSysThread::StopThread
|
|
|
|
========================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
void idSysThread::StopThread( bool wait )
|
|
|
|
{
|
|
|
|
if( !isRunning )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
if( isWorker )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
signalMutex.Lock();
|
|
|
|
moreWorkToDo = true;
|
|
|
|
signalWorkerDone.Clear();
|
|
|
|
isTerminating = true;
|
|
|
|
signalMoreWorkToDo.Raise();
|
|
|
|
signalMutex.Unlock();
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
isTerminating = true;
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
if( wait )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
WaitForThread();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
========================
|
|
|
|
idSysThread::WaitForThread
|
|
|
|
========================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
void idSysThread::WaitForThread()
|
|
|
|
{
|
|
|
|
if( isWorker )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
signalWorkerDone.Wait( idSysSignal::WAIT_INFINITE );
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
else if( isRunning )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
Sys_DestroyThread( threadHandle );
|
|
|
|
threadHandle = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
========================
|
|
|
|
idSysThread::SignalWork
|
|
|
|
========================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
void idSysThread::SignalWork()
|
|
|
|
{
|
|
|
|
if( isWorker )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
signalMutex.Lock();
|
|
|
|
moreWorkToDo = true;
|
|
|
|
signalWorkerDone.Clear();
|
|
|
|
signalMoreWorkToDo.Raise();
|
|
|
|
signalMutex.Unlock();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
========================
|
|
|
|
idSysThread::IsWorkDone
|
|
|
|
========================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
bool idSysThread::IsWorkDone()
|
|
|
|
{
|
|
|
|
if( isWorker )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
// a timeout of 0 will return immediately with true if signaled
|
2012-11-28 15:47:07 +00:00
|
|
|
if( signalWorkerDone.Wait( 0 ) )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
========================
|
|
|
|
idSysThread::ThreadProc
|
|
|
|
========================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
int idSysThread::ThreadProc( idSysThread* thread )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
int retVal = 0;
|
2012-11-28 15:47:07 +00:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if( thread->isWorker )
|
|
|
|
{
|
|
|
|
for( ; ; )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
thread->signalMutex.Lock();
|
2012-11-28 15:47:07 +00:00
|
|
|
if( thread->moreWorkToDo )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
thread->moreWorkToDo = false;
|
|
|
|
thread->signalMoreWorkToDo.Clear();
|
|
|
|
thread->signalMutex.Unlock();
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
thread->signalWorkerDone.Raise();
|
|
|
|
thread->signalMutex.Unlock();
|
|
|
|
thread->signalMoreWorkToDo.Wait( idSysSignal::WAIT_INFINITE );
|
|
|
|
continue;
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
|
|
|
|
if( thread->isTerminating )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
break;
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
retVal = thread->Run();
|
|
|
|
}
|
|
|
|
thread->signalWorkerDone.Raise();
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
retVal = thread->Run();
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
catch( idException& ex )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
idLib::Warning( "Fatal error in thread %s: %s", thread->GetName(), ex.GetError() );
|
2012-12-06 20:31:33 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// We don't handle threads terminating unexpectedly very well, so just terminate the whole process
|
2012-12-06 20:31:33 +00:00
|
|
|
exit( 0 );
|
2012-11-26 18:58:24 +00:00
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
thread->isRunning = false;
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
return retVal;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
========================
|
|
|
|
idSysThread::Run
|
|
|
|
========================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
int idSysThread::Run()
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
// The Run() is not pure virtual because on destruction of a derived class
|
|
|
|
// the virtual function pointer will be set to NULL before the idSysThread
|
|
|
|
// destructor actually stops the thread.
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================================================================================================
|
|
|
|
|
|
|
|
test
|
|
|
|
|
|
|
|
================================================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
================================================
|
|
|
|
idMyThread test class.
|
|
|
|
================================================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
class idMyThread : public idSysThread
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
public:
|
2012-11-28 15:47:07 +00:00
|
|
|
virtual int Run()
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
// run threaded code here
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
// specify thread data here
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
========================
|
|
|
|
TestThread
|
|
|
|
========================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
void TestThread()
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
idMyThread thread;
|
|
|
|
thread.StartThread( "myThread", CORE_ANY );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
========================
|
|
|
|
TestWorkers
|
|
|
|
========================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
void TestWorkers()
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
idSysWorkerThreadGroup<idMyThread> workers( "myWorkers", 4 );
|
2012-11-28 15:47:07 +00:00
|
|
|
for( ; ; )
|
|
|
|
{
|
|
|
|
for( int i = 0; i < workers.GetNumThreads(); i++ )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
// workers.GetThread( i )-> // setup work for this thread
|
|
|
|
}
|
|
|
|
workers.SignalWorkAndWait();
|
|
|
|
}
|
|
|
|
}
|