/* ** 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 . */ #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