DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

Thread.cpp (6937B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 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.
     23 
     24 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.
     25 
     26 ===========================================================================
     27 */
     28 #pragma hdrstop
     29 #include "precompiled.h"
     30 
     31 /*
     32 ================================================================================================
     33 Contains the vartious ThreadingClass implementations.
     34 ================================================================================================
     35 */
     36 
     37 /*
     38 ================================================================================================
     39 
     40 	idSysThread
     41 
     42 ================================================================================================
     43 */
     44 
     45 /*
     46 ========================
     47 idSysThread::idSysThread
     48 ========================
     49 */
     50 idSysThread::idSysThread() :
     51 		threadHandle( 0 ),
     52 		isWorker( false ),
     53 		isRunning( false ),
     54 		isTerminating( false ),
     55 		moreWorkToDo( false ),
     56 		signalWorkerDone( true ) {
     57 }
     58 
     59 /*
     60 ========================
     61 idSysThread::~idSysThread
     62 ========================
     63 */
     64 idSysThread::~idSysThread() {
     65 	StopThread( true );
     66 	if ( threadHandle ) {
     67 		Sys_DestroyThread( threadHandle );
     68 	}
     69 }
     70 
     71 /*
     72 ========================
     73 idSysThread::StartThread
     74 ========================
     75 */
     76 bool idSysThread::StartThread( const char * name_, core_t core, xthreadPriority priority, int stackSize ) {
     77 	if ( isRunning ) {
     78 		return false;
     79 	}
     80 
     81 	name = name_;
     82 
     83 	isTerminating = false;
     84 
     85 	if ( threadHandle ) {
     86 		Sys_DestroyThread( threadHandle );
     87 	}
     88 
     89 	threadHandle = Sys_CreateThread( (xthread_t)ThreadProc, this, priority, name, core, stackSize, false );
     90 
     91 	isRunning = true;
     92 	return true;
     93 }
     94 
     95 /*
     96 ========================
     97 idSysThread::StartWorkerThread
     98 ========================
     99 */
    100 bool idSysThread::StartWorkerThread( const char * name_, core_t core, xthreadPriority priority, int stackSize ) {
    101 	if ( isRunning ) {
    102 		return false;
    103 	}
    104 
    105 	isWorker = true;
    106 
    107 	bool result = StartThread( name_, core, priority, stackSize );
    108 
    109 	signalWorkerDone.Wait( idSysSignal::WAIT_INFINITE );
    110 
    111 	return result;
    112 }
    113 
    114 /*
    115 ========================
    116 idSysThread::StopThread
    117 ========================
    118 */
    119 void idSysThread::StopThread( bool wait ) {
    120 	if ( !isRunning ) {
    121 		return;
    122 	}
    123 	if ( isWorker ) {
    124 		signalMutex.Lock();
    125 		moreWorkToDo = true;
    126 		signalWorkerDone.Clear();
    127 		isTerminating = true;
    128 		signalMoreWorkToDo.Raise();
    129 		signalMutex.Unlock();
    130 	} else {
    131 		isTerminating = true;
    132 	}
    133 	if ( wait ) {
    134 		WaitForThread();
    135 	}
    136 }
    137 
    138 /*
    139 ========================
    140 idSysThread::WaitForThread
    141 ========================
    142 */
    143 void idSysThread::WaitForThread() {
    144 	if ( isWorker ) {
    145 		signalWorkerDone.Wait( idSysSignal::WAIT_INFINITE );
    146 	} else if ( isRunning ) {
    147 		Sys_DestroyThread( threadHandle );
    148 		threadHandle = 0;
    149 	}
    150 }
    151 
    152 /*
    153 ========================
    154 idSysThread::SignalWork
    155 ========================
    156 */
    157 void idSysThread::SignalWork() {
    158 	if ( isWorker ) {
    159 		signalMutex.Lock();
    160 		moreWorkToDo = true;
    161 		signalWorkerDone.Clear();
    162 		signalMoreWorkToDo.Raise();
    163 		signalMutex.Unlock();
    164 	}
    165 }
    166 
    167 /*
    168 ========================
    169 idSysThread::IsWorkDone
    170 ========================
    171 */
    172 bool idSysThread::IsWorkDone() {
    173 	if ( isWorker ) {
    174 		// a timeout of 0 will return immediately with true if signaled
    175 		if ( signalWorkerDone.Wait( 0 ) ) {
    176 			return true;
    177 		}
    178 	}
    179 	return false;
    180 }
    181 
    182 /*
    183 ========================
    184 idSysThread::ThreadProc
    185 ========================
    186 */
    187 int idSysThread::ThreadProc( idSysThread * thread ) {
    188 	int retVal = 0;
    189 
    190 	try {
    191 		if ( thread->isWorker ) {
    192 			for( ; ; ) {
    193 				thread->signalMutex.Lock();
    194 				if ( thread->moreWorkToDo ) {
    195 					thread->moreWorkToDo = false;
    196 					thread->signalMoreWorkToDo.Clear();
    197 					thread->signalMutex.Unlock();
    198 				} else {
    199 					thread->signalWorkerDone.Raise();
    200 					thread->signalMutex.Unlock();
    201 					thread->signalMoreWorkToDo.Wait( idSysSignal::WAIT_INFINITE );
    202 					continue;
    203 				}
    204 
    205 				if ( thread->isTerminating ) {
    206 					break;
    207 				}
    208 
    209 				retVal = thread->Run();
    210 			}
    211 			thread->signalWorkerDone.Raise();
    212 		} else {
    213 			retVal = thread->Run();
    214 		}
    215 	} catch ( idException & ex ) {
    216 		idLib::Warning( "Fatal error in thread %s: %s", thread->GetName(), ex.GetError() );
    217 		// We don't handle threads terminating unexpectedly very well, so just terminate the whole process
    218 		_exit( 0 );
    219 	}
    220 
    221 	thread->isRunning = false;
    222 
    223 	return retVal;
    224 }
    225 
    226 /*
    227 ========================
    228 idSysThread::Run
    229 ========================
    230 */
    231 int idSysThread::Run() {
    232 	// The Run() is not pure virtual because on destruction of a derived class
    233 	// the virtual function pointer will be set to NULL before the idSysThread
    234 	// destructor actually stops the thread.
    235 	return 0;
    236 }
    237 
    238 /*
    239 ================================================================================================
    240 
    241 	test
    242 
    243 ================================================================================================
    244 */
    245 
    246 /*
    247 ================================================
    248 idMyThread test class.
    249 ================================================
    250 */
    251 class idMyThread : public idSysThread {
    252 public:
    253 	virtual int Run() {
    254 		// run threaded code here
    255 		return 0;
    256 	}
    257 	// specify thread data here
    258 };
    259 
    260 /*
    261 ========================
    262 TestThread
    263 ========================
    264 */
    265 void TestThread() {
    266 	idMyThread thread;
    267 	thread.StartThread( "myThread", CORE_ANY );
    268 }
    269 
    270 /*
    271 ========================
    272 TestWorkers
    273 ========================
    274 */
    275 void TestWorkers() {
    276 	idSysWorkerThreadGroup<idMyThread> workers( "myWorkers", 4 );
    277 	for ( ; ; ) {
    278 		for ( int i = 0; i < workers.GetNumThreads(); i++ ) {
    279 			// workers.GetThread( i )-> // setup work for this thread
    280 		}
    281 		workers.SignalWorkAndWait();
    282 	}
    283 }