Port all thread related functions to SDL

Setting thread priorities has been dropped (it is not portable).
The background download thread now exits gracefully.
g_threads is not public anymore.
This commit is contained in:
dhewg 2011-12-20 22:03:26 +01:00
parent 7865e432a7
commit e7482b4957
16 changed files with 140 additions and 270 deletions

View file

@ -184,8 +184,6 @@ if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
if (MINGW)
set(ldflags ${ldflags} "-mwindows")
else()
set(sys_libs ${sys_libs} pthread)
endif()
if (os STREQUAL "linux")
@ -618,7 +616,6 @@ if (APPLE)
sys/sys_local.cpp
sys/posix/posix_net.cpp
sys/posix/posix_signal.cpp
sys/posix/posix_threads.cpp
sys/posix/posix_main.cpp
)
@ -660,7 +657,6 @@ else()
sys/sys_local.cpp
sys/posix/posix_net.cpp
sys/posix/posix_signal.cpp
sys/posix/posix_threads.cpp
sys/posix/posix_main.cpp
sys/linux/main.cpp
)

View file

@ -188,10 +188,7 @@ int Sys_ListFiles( const char *directory, const char *extension, idStrList &l
#endif
xthreadInfo * g_threads[MAX_THREADS];
int g_thread_count;
void Sys_CreateThread( xthread_t function, void *parms, xthreadPriority priority, xthreadInfo &info, const char *name, xthreadInfo *threads[MAX_THREADS], int *thread_count ) {}
void Sys_CreateThread( xthread_t function, void *parms, xthreadInfo &info, const char *name ) {}
void Sys_DestroyThread( xthreadInfo& info ) {}
void Sys_EnterCriticalSection( int index ) {}

View file

@ -406,7 +406,7 @@ public:
static void TouchFileList_f( const idCmdArgs &args );
private:
friend THREAD_RETURN_TYPE BackgroundDownloadThread( void *parms );
friend int BackgroundDownloadThread( void *pexit );
searchpath_t * searchPaths;
int readCount; // total bytes read
@ -433,6 +433,7 @@ private:
backgroundDownload_t * backgroundDownloads;
backgroundDownload_t defaultBackgroundDownload;
xthreadInfo backgroundThread;
bool backgroundThread_exit;
idList<pack_t *> serverPaks;
bool loadedFileFromDir; // set to true once a file was loaded from a directory - can't switch to pure anymore
@ -520,6 +521,7 @@ idFileSystemLocal::idFileSystemLocal( void ) {
loadedFileFromDir = false;
restartGamePakChecksum = 0;
memset( &backgroundThread, 0, sizeof( backgroundThread ) );
backgroundThread_exit = false;
addonPaks = NULL;
}
@ -2924,6 +2926,11 @@ Frees all resources and closes all files
void idFileSystemLocal::Shutdown( bool reloading ) {
searchpath_t *sp, *next, *loop;
backgroundThread_exit = true;
Sys_TriggerEvent();
Sys_DestroyThread(backgroundThread);
backgroundThread_exit = false;
gameFolder.Clear();
serverPaks.Clear();
@ -3619,8 +3626,10 @@ BackgroundDownload
Reads part of a file from a background thread.
===================
*/
THREAD_RETURN_TYPE BackgroundDownloadThread( void *parms ) {
while( 1 ) {
int BackgroundDownloadThread( void *pexit ) {
bool *exit = (bool *)pexit;
while (!(*exit)) {
Sys_EnterCriticalSection();
backgroundDownload_t *bgl = fileSystemLocal.backgroundDownloads;
if ( !bgl ) {
@ -3732,7 +3741,7 @@ THREAD_RETURN_TYPE BackgroundDownloadThread( void *parms ) {
#endif
}
}
return (THREAD_RETURN_TYPE) 0;
return 0;
}
/*
@ -3742,10 +3751,7 @@ idFileSystemLocal::StartBackgroundReadThread
*/
void idFileSystemLocal::StartBackgroundDownloadThread() {
if ( !backgroundThread.threadHandle ) {
Sys_CreateThread( BackgroundDownloadThread, NULL, THREAD_NORMAL, backgroundThread, "backgroundDownload", g_threads, &g_thread_count );
if ( !backgroundThread.threadHandle ) {
common->Warning( "idFileSystemLocal::StartBackgroundDownloadThread: failed" );
}
Sys_CreateThread( BackgroundDownloadThread, &backgroundThread_exit, backgroundThread, "backgroundDownload" );
} else {
common->Printf( "background thread already running\n" );
}

View file

@ -26,8 +26,6 @@ If you have questions concerning this license or the applicable additional terms
===========================================================================
*/
#include <pthread.h>
#include "sys/platform.h"
#include "framework/KeyInput.h"
#include "sys/posix/posix_public.h"

View file

@ -26,7 +26,6 @@ If you have questions concerning this license or the applicable additional terms
===========================================================================
*/
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>

View file

@ -28,7 +28,6 @@ If you have questions concerning this license or the applicable additional terms
// -*- mode: objc -*-
#import <unistd.h>
#import <pthread.h>
#import <Foundation/Foundation.h>
#import <Carbon/Carbon.h>

View file

@ -44,7 +44,6 @@ If you have questions concerning this license or the applicable additional terms
#import <sys/types.h>
#import <sys/time.h>
#import <unistd.h>
#import <pthread.h>
#import "sys/platform.h"
#import "framework/Common.h"

View file

@ -66,8 +66,6 @@ If you have questions concerning this license or the applicable additional terms
#define assertmem( x, y )
#endif
#define THREAD_RETURN_TYPE DWORD
#endif
@ -107,8 +105,6 @@ If you have questions concerning this license or the applicable additional terms
#define assertmem( x, y )
#define THREAD_RETURN_TYPE void *
#endif
@ -163,8 +159,6 @@ If you have questions concerning this license or the applicable additional terms
#define assertmem( x, y )
#define THREAD_RETURN_TYPE void *
#endif

View file

@ -34,7 +34,6 @@ If you have questions concerning this license or the applicable additional terms
#include <sys/mman.h>
#include <sys/time.h>
#include <pwd.h>
#include <pthread.h>
#include <dlfcn.h>
#include <termios.h>
#include <signal.h>
@ -544,7 +543,6 @@ void Posix_EarlyInit( void ) {
Posix_InitSigs();
// set the base time
Sys_Milliseconds();
Posix_InitPThreads();
}
/*

View file

@ -41,7 +41,6 @@ void Posix_EarlyInit( );
// called after common has been initialized
void Posix_LateInit( );
void Posix_InitPThreads( );
void Posix_InitSigs( );
void Posix_ClearSigs( );

View file

@ -1,154 +0,0 @@
/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
Doom 3 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 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 Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 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 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.
===========================================================================
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <pwd.h>
#include <pthread.h>
#include "sys/platform.h"
#include "framework/Common.h"
#include "sys/posix/posix_public.h"
#if defined(_DEBUG)
// #define ID_VERBOSE_PTHREADS
#endif
/*
======================================================
thread create and destroy
======================================================
*/
// not a hard limit, just what we keep track of for debugging
xthreadInfo *g_threads[MAX_THREADS];
int g_thread_count = 0;
typedef void *(*pthread_function_t) (void *);
/*
==================
Sys_CreateThread
==================
*/
void Sys_CreateThread( xthread_t function, void *parms, xthreadPriority priority, xthreadInfo& info, const char *name, xthreadInfo **threads, int *thread_count ) {
Sys_EnterCriticalSection( );
pthread_attr_t attr;
pthread_attr_init( &attr );
if ( pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ) != 0 ) {
common->Error( "ERROR: pthread_attr_setdetachstate %s failed\n", name );
}
if ( pthread_create( ( pthread_t* )&info.threadHandle, &attr, function, parms ) != 0 ) {
common->Error( "ERROR: pthread_create %s failed\n", name );
}
pthread_attr_destroy( &attr );
info.name = name;
if ( *thread_count < MAX_THREADS ) {
threads[ ( *thread_count )++ ] = &info;
} else {
common->DPrintf( "WARNING: MAX_THREADS reached\n" );
}
Sys_LeaveCriticalSection( );
}
/*
==================
Sys_DestroyThread
==================
*/
void Sys_DestroyThread( xthreadInfo& info ) {
// the target thread must have a cancelation point, otherwise pthread_cancel is useless
assert( info.threadHandle );
if ( pthread_cancel( ( pthread_t )info.threadHandle ) != 0 ) {
common->Error( "ERROR: pthread_cancel %s failed\n", info.name );
}
if ( pthread_join( ( pthread_t )info.threadHandle, NULL ) != 0 ) {
common->Error( "ERROR: pthread_join %s failed\n", info.name );
}
info.threadHandle = 0;
Sys_EnterCriticalSection( );
for( int i = 0 ; i < g_thread_count ; i++ ) {
if ( &info == g_threads[ i ] ) {
g_threads[ i ] = NULL;
int j;
for( j = i+1 ; j < g_thread_count ; j++ ) {
g_threads[ j-1 ] = g_threads[ j ];
}
g_threads[ j-1 ] = NULL;
g_thread_count--;
break;
}
}
Sys_LeaveCriticalSection( );
}
/*
==================
Sys_GetThreadName
find the name of the calling thread
==================
*/
const char* Sys_GetThreadName( int *index ) {
Sys_EnterCriticalSection( );
pthread_t thread = pthread_self();
for( int i = 0 ; i < g_thread_count ; i++ ) {
if ( thread == (pthread_t)g_threads[ i ]->threadHandle ) {
if ( index ) {
*index = i;
}
Sys_LeaveCriticalSection( );
return g_threads[ i ]->name;
}
}
if ( index ) {
*index = -1;
}
Sys_LeaveCriticalSection( );
return "main";
}
/*
==================
Posix_InitPThreads
==================
*/
void Posix_InitPThreads( ) {
int i;
// init threads table
for ( i = 0; i < MAX_THREADS; i++ ) {
g_threads[ i ] = NULL;
}
}

View file

@ -197,7 +197,6 @@ sys_string = ' \
posix/posix_net.cpp \
posix/posix_main.cpp \
posix/posix_signal.cpp \
posix/posix_threads.cpp \
linux/main.cpp \
stub/util_stub.cpp'
@ -241,7 +240,7 @@ if ( local_demo == 1 ):
if ( local_curl == 0 ):
local_env.Append( CPPDEFINES = [ 'ID_ENABLE_CURL=0' ] )
local_env.Append( LIBS = [ 'SDL', 'SDLmain', 'pthread', 'jpeg', 'vorbisfile' ] )
local_env.Append( LIBS = [ 'SDL', 'SDLmain', 'jpeg', 'vorbisfile' ] )
if ( local_dedicated == 0 ):
local_env.Append( LIBS = [ 'GL' ] )

View file

@ -56,7 +56,7 @@ double Sys_ClockTicksPerSecond( void ) {
void Sys_Sleep( int msec ) {
}
void Sys_CreateThread( xthread_t function, void *parms, xthreadPriority priority, xthreadInfo& info ) {
void Sys_CreateThread( xthread_t function, void *parms, xthreadInfo& info, const char *name ) {
}
void Sys_DestroyThread( xthreadInfo& info ) {

View file

@ -358,28 +358,21 @@ void Sys_ShutdownNetworking( void );
==============================================================
*/
typedef THREAD_RETURN_TYPE (*xthread_t)( void * );
struct SDL_Thread;
typedef enum {
THREAD_NORMAL,
THREAD_ABOVE_NORMAL,
THREAD_HIGHEST
} xthreadPriority;
typedef int (*xthread_t)( void * );
typedef struct {
const char * name;
intptr_t threadHandle;
size_t threadId;
const char *name;
SDL_Thread *threadHandle;
unsigned int threadId;
} xthreadInfo;
extern xthreadInfo *g_threads[MAX_THREADS];
extern int g_thread_count;
void Sys_CreateThread( xthread_t function, void *parms, xthreadPriority priority, xthreadInfo &info, const char *name, xthreadInfo *threads[MAX_THREADS], int *thread_count );
void Sys_CreateThread( xthread_t function, void *parms, xthreadInfo &info, const char *name );
void Sys_DestroyThread( xthreadInfo& info ); // sets threadHandle back to 0
// find the name of the calling thread
// if index != NULL, set the index in g_threads array (use -1 for "main" thread)
// if index != NULL, set the index in threads array (use -1 for "main" thread)
const char * Sys_GetThreadName( int *index = 0 );
extern void Sys_InitThreads();

View file

@ -27,6 +27,7 @@ If you have questions concerning this license or the applicable additional terms
*/
#include <SDL_mutex.h>
#include <SDL_thread.h>
#include "sys/platform.h"
#include "framework/Common.h"
@ -38,6 +39,9 @@ static SDL_cond *cond[MAX_TRIGGER_EVENTS] = { };
static bool signaled[MAX_TRIGGER_EVENTS] = { };
static bool waiting[MAX_TRIGGER_EVENTS] = { };
static xthreadInfo *thread[MAX_THREADS] = { };
static size_t thread_count = 0;
/*
==================
Sys_InitThreads
@ -66,6 +70,12 @@ void Sys_InitThreads() {
signaled[i] = false;
waiting[i] = false;
}
// threads
for (int i = 0; i < MAX_THREADS; i++)
thread[i] = NULL;
thread_count = 0;
}
/*
@ -74,6 +84,16 @@ Sys_ShutdownThreads
==================
*/
void Sys_ShutdownThreads() {
// threads
for (int i = 0; i < MAX_THREADS; i++) {
if (!thread[i])
continue;
Sys_Printf("WARNING: Thread '%s' still running\n", thread[i]->name);
SDL_KillThread(thread[i]->threadHandle);
thread[i] = NULL;
}
// events
for (int i = 0; i < MAX_TRIGGER_EVENTS; i++) {
SDL_DestroyCond(cond[i]);
@ -170,3 +190,99 @@ void Sys_TriggerEvent(int index) {
Sys_LeaveCriticalSection(CRITICAL_SECTION_SYS);
}
/*
==================
Sys_CreateThread
==================
*/
void Sys_CreateThread(xthread_t function, void *parms, xthreadInfo& info, const char *name) {
Sys_EnterCriticalSection();
SDL_Thread *t = SDL_CreateThread(function, parms);
if (!t) {
common->Error("ERROR: SDL_thread for '%s' failed\n", name);
Sys_LeaveCriticalSection();
return;
}
info.name = name;
info.threadHandle = t;
info.threadId = SDL_GetThreadID(t);
if (thread_count < MAX_THREADS)
thread[thread_count++] = &info;
else
common->DPrintf("WARNING: MAX_THREADS reached\n");
Sys_LeaveCriticalSection();
}
/*
==================
Sys_DestroyThread
==================
*/
void Sys_DestroyThread(xthreadInfo& info) {
assert(info.threadHandle);
SDL_WaitThread(info.threadHandle, NULL);
info.name = NULL;
info.threadHandle = NULL;
info.threadId = 0;
Sys_EnterCriticalSection();
for (int i = 0; i < thread_count; i++) {
if (&info == thread[i]) {
thread[i] = NULL;
int j;
for (j = i + 1; j < thread_count; j++)
thread[j - 1] = thread[j];
thread[j - 1] = NULL;
thread_count--;
break;
}
}
Sys_LeaveCriticalSection( );
}
/*
==================
Sys_GetThreadName
find the name of the calling thread
==================
*/
const char *Sys_GetThreadName(int *index) {
const char *name;
Sys_EnterCriticalSection();
unsigned int id = SDL_ThreadID();
for (int i = 0; i < thread_count; i++) {
if (id == thread[i]->threadId) {
if (index)
*index = i;
name = thread[i]->name;
Sys_LeaveCriticalSection();
return name;
}
}
if (index)
*index = -1;
Sys_LeaveCriticalSection();
return "main";
}

View file

@ -68,16 +68,8 @@ idCVar Win32Vars_t::win_allowMultipleInstances( "win_allowMultipleInstances", "0
Win32Vars_t win32;
// not a hard limit, just what we keep track of for debugging
xthreadInfo *g_threads[MAX_THREADS];
int g_thread_count = 0;
static sysMemoryStats_t exeLaunchMemoryStats;
static xthreadInfo threadInfo;
static HANDLE hTimer;
/*
================
Sys_GetExeLaunchMemoryStatus
@ -87,46 +79,6 @@ void Sys_GetExeLaunchMemoryStatus( sysMemoryStats_t &stats ) {
stats = exeLaunchMemoryStats;
}
/*
==================
Sys_Createthread
==================
*/
void Sys_CreateThread( xthread_t function, void *parms, xthreadPriority priority, xthreadInfo &info, const char *name, xthreadInfo *threads[MAX_THREADS], int *thread_count ) {
DWORD id;
HANDLE temp = CreateThread( NULL, // LPSECURITY_ATTRIBUTES lpsa,
0, // DWORD cbStack,
(LPTHREAD_START_ROUTINE)function, // LPTHREAD_START_ROUTINE lpStartAddr,
parms, // LPVOID lpvThreadParm,
0, // DWORD fdwCreate,
&id);
info.threadId = id;
info.threadHandle = (intptr_t) temp;
if (priority == THREAD_HIGHEST) {
SetThreadPriority( (HANDLE)info.threadHandle, THREAD_PRIORITY_HIGHEST ); // we better sleep enough to do this
} else if (priority == THREAD_ABOVE_NORMAL ) {
SetThreadPriority( (HANDLE)info.threadHandle, THREAD_PRIORITY_ABOVE_NORMAL );
}
info.name = name;
if ( *thread_count < MAX_THREADS ) {
threads[(*thread_count)++] = &info;
} else {
common->DPrintf("WARNING: MAX_THREADS reached\n");
}
}
/*
==================
Sys_DestroyThread
==================
*/
void Sys_DestroyThread( xthreadInfo& info ) {
WaitForSingleObject( (HANDLE)info.threadHandle, INFINITE);
CloseHandle( (HANDLE)info.threadHandle );
info.threadHandle = 0;
}
/*
==================
Sys_Sentry
@ -136,27 +88,6 @@ void Sys_Sentry() {
int j = 0;
}
/*
==================
Sys_GetThreadName
==================
*/
const char* Sys_GetThreadName(int *index) {
size_t id = GetCurrentThreadId();
for( int i = 0; i < g_thread_count; i++ ) {
if ( id == g_threads[i]->threadId ) {
if ( index ) {
*index = i;
}
return g_threads[i]->name;
}
}
if ( index ) {
*index = -1;
}
return "main";
}
#pragma optimize( "", on )
#ifdef DEBUG