222 lines
5.7 KiB
C++
222 lines
5.7 KiB
C++
![]() |
/*
|
||
|
** Command & Conquer Generals Zero Hour(tm)
|
||
|
** Copyright 2025 Electronic Arts Inc.
|
||
|
**
|
||
|
** This program 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.
|
||
|
**
|
||
|
** This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
#define THREADFAC_CODE
|
||
|
|
||
|
#include "threadfac.h"
|
||
|
|
||
|
int Runnable::ThreadCount_ = 0;
|
||
|
CritSec Runnable::CritSec_; // to protect ThreadCount_
|
||
|
|
||
|
// MDC: Made all this dependent on _REENTRANT being defined so VC++ doesn't complain on
|
||
|
// single-threaded programs...
|
||
|
|
||
|
|
||
|
//
|
||
|
// Note: I chose the following type signature for thread functions
|
||
|
// void function(void *data);
|
||
|
//
|
||
|
//
|
||
|
// Since Win32 & POSIX have different type signatures for the thread entry points
|
||
|
// an intermediate system-dependent function in this file gets called first.
|
||
|
// That function then calls the system independent version. So the system dependent
|
||
|
// version needs 2 Items 1) The address of the _real_ thread func 2) the data
|
||
|
// to pass. We only have 1 argument available, so you figure out the rest...
|
||
|
//
|
||
|
// This is for internal use only
|
||
|
//
|
||
|
struct ThreadInformation
|
||
|
{
|
||
|
void *startPoint; // The address of the _real_ thread function, or class
|
||
|
void *data; // data to pass to real thread function or class
|
||
|
bit8 destroy; // only applies to classes, should delete after execution?
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Start a thread inside a class
|
||
|
//
|
||
|
bit8 ThreadFactory::startThread(Runnable &runable, void *data, bit8 destroy)
|
||
|
{
|
||
|
#ifdef _REENTRANT
|
||
|
|
||
|
{
|
||
|
Runnable::CritSec_.lock();
|
||
|
Runnable::ThreadCount_++;
|
||
|
Runnable::CritSec_.unlock();
|
||
|
}
|
||
|
|
||
|
|
||
|
ThreadInformation *tInfo=new ThreadInformation;
|
||
|
tInfo->startPoint=(void *)&runable;
|
||
|
tInfo->data=data;
|
||
|
tInfo->destroy=destroy;
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
// Under windows call _beginthreadex instead of CreateThread so you can
|
||
|
// use all the normal C library stuff. (IMPORTANT!!!)
|
||
|
uint32 handle;
|
||
|
uint32 stup1d;
|
||
|
handle=_beginthreadex(NULL,0, threadClassLauncher, tInfo, 0, &stup1d);
|
||
|
if (handle!=NULL)
|
||
|
return(TRUE);
|
||
|
else
|
||
|
{
|
||
|
{
|
||
|
runable.CritSec_.lock();
|
||
|
runable.ThreadCount_--; // Ok, so it didn't really start
|
||
|
runable.CritSec_.unlock();
|
||
|
}
|
||
|
return(FALSE);
|
||
|
}
|
||
|
#else // UNIX
|
||
|
// Setup thread attributes for client threads
|
||
|
int retval;
|
||
|
pthread_attr_t threadAttr;
|
||
|
pthread_attr_init(&threadAttr);
|
||
|
pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED);
|
||
|
pthread_attr_setscope(&threadAttr,PTHREAD_SCOPE_SYSTEM);
|
||
|
retval=pthread_create(NULL,&threadAttr, threadClassLauncher, tInfo);
|
||
|
if (retval==0)
|
||
|
return(TRUE);
|
||
|
else
|
||
|
{
|
||
|
{
|
||
|
runable.CritSec_.lock();
|
||
|
runable.ThreadCount_--; // Ok, so it didn't really start
|
||
|
runable.CritSec_.unlock();
|
||
|
}
|
||
|
return(FALSE);
|
||
|
}
|
||
|
#endif
|
||
|
#else
|
||
|
return (FALSE);
|
||
|
#endif /* _REENTRANT */
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Start a thread inside a function
|
||
|
//
|
||
|
bit8 ThreadFactory::startThread(void (*start_func)(void *), void *data)
|
||
|
{
|
||
|
#ifdef _REENTRANT
|
||
|
ThreadInformation *tInfo=new ThreadInformation;
|
||
|
tInfo->startPoint=start_func;
|
||
|
tInfo->data=data;
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
// Under windows call _beginthreadex instead of CreateThread so you can
|
||
|
// use all the normal C library stuff. (IMPORTANT!!!)
|
||
|
uint32 handle;
|
||
|
unsigned temp;
|
||
|
handle=_beginthreadex(NULL,0, threadFuncLauncher, tInfo, 0, &temp);
|
||
|
if (handle!=NULL)
|
||
|
return(TRUE);
|
||
|
return(FALSE);
|
||
|
#else // UNIX
|
||
|
// Setup thread attributes for client threads
|
||
|
int retval;
|
||
|
pthread_attr_t threadAttr;
|
||
|
pthread_attr_init(&threadAttr);
|
||
|
pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED);
|
||
|
pthread_attr_setscope(&threadAttr,PTHREAD_SCOPE_SYSTEM);
|
||
|
retval=pthread_create(NULL,&threadAttr, threadFuncLauncher, tInfo);
|
||
|
if (retval==0)
|
||
|
return(TRUE);
|
||
|
else
|
||
|
return(FALSE);
|
||
|
#endif
|
||
|
#else
|
||
|
return(FALSE);
|
||
|
#endif /* REENTRANT */
|
||
|
}
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
unsigned __stdcall threadFuncLauncher(void *temp)
|
||
|
#else // UNIX
|
||
|
void *threadFuncLauncher(void *temp)
|
||
|
#endif
|
||
|
{
|
||
|
ThreadInformation *tInfo=(ThreadInformation *)temp;
|
||
|
|
||
|
void (*start_func)(void *);
|
||
|
start_func=(void (*)(void *))tInfo->startPoint;
|
||
|
|
||
|
void *data=tInfo->data;
|
||
|
delete(tInfo);
|
||
|
|
||
|
start_func(data);
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
unsigned __stdcall threadClassLauncher(void *temp)
|
||
|
#else // UNIX
|
||
|
void *threadClassLauncher(void *temp)
|
||
|
#endif
|
||
|
{
|
||
|
ThreadInformation *tInfo=(ThreadInformation *)temp;
|
||
|
|
||
|
Runnable *thrClass=(Runnable *)tInfo->startPoint;
|
||
|
void *data=tInfo->data;
|
||
|
bit8 destroy=tInfo->destroy;
|
||
|
delete(tInfo);
|
||
|
|
||
|
thrClass->run(data);
|
||
|
|
||
|
if (destroy) // May want to free memory after thread finishes
|
||
|
delete(thrClass);
|
||
|
|
||
|
{
|
||
|
Runnable::CritSec_.lock();
|
||
|
Runnable::ThreadCount_--;
|
||
|
Runnable::CritSec_.unlock();
|
||
|
}
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
ExitThread(0); // is this really needed?
|
||
|
#endif
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
Runnable::Runnable()
|
||
|
{ }
|
||
|
|
||
|
Runnable::~Runnable()
|
||
|
{ }
|
||
|
|
||
|
// Is there a thread running in this class
|
||
|
bit8 Runnable::isRunning(void)
|
||
|
{
|
||
|
// Don't need to lock a simple assignment
|
||
|
int temp=ThreadCount_;
|
||
|
return((temp>0)?TRUE:FALSE);
|
||
|
}
|
||
|
|
||
|
// How many threads are running in this class
|
||
|
int Runnable::getThreadCount(void)
|
||
|
{
|
||
|
// Don't need to lock a simple assignment
|
||
|
int temp=ThreadCount_;
|
||
|
return(temp);
|
||
|
}
|
||
|
|
||
|
#undef THREADFAC_CODE
|