/* Copyright (C) 1999-2006 Id Software, Inc. and contributors. For a list of contributors, see the accompanying CONTRIBUTORS file. This file is part of GtkRadiant. GtkRadiant 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 2 of the License, or (at your option) any later version. GtkRadiant 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 GtkRadiant; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef WIN32 // The below define is necessary to use // pthreads extensions like pthread_mutexattr_settype #define _GNU_SOURCE #include #endif #include "cmdlib.h" #include "mathlib.h" #include "inout.h" #include "q2_threads.h" #define MAX_THREADS 64 int dispatch; int workcount; int oldf; qboolean pacifier; qboolean threaded; /* ============= GetThreadWork ============= */ int GetThreadWork( void ){ int r; int f; ThreadLock(); if ( dispatch == workcount ) { ThreadUnlock(); return -1; } f = 10 * dispatch / workcount; if ( f != oldf ) { oldf = f; if ( pacifier ) { Sys_Printf( "%i...", f ); fflush( stdout ); /* ydnar */ } } r = dispatch; dispatch++; ThreadUnlock(); return r; } void ( *workfunction )( int ); void ThreadWorkerFunction( int threadnum ){ int work; while ( 1 ) { work = GetThreadWork(); if ( work == -1 ) { break; } //Sys_FPrintf( SYS_VRB,"thread %i, work %i\n", threadnum, work); workfunction( work ); } } void RunThreadsOnIndividual( int workcnt, qboolean showpacifier, void ( *func )( int ) ){ if ( numthreads == -1 ) { ThreadSetDefault(); } workfunction = func; RunThreadsOn( workcnt, showpacifier, ThreadWorkerFunction ); } /* =================================================================== WIN32 =================================================================== */ #ifdef WIN32 #define USED #include // Setting default Threads to 1 int numthreads = 1; CRITICAL_SECTION crit; static int enter; void ThreadSetDefault( void ){ SYSTEM_INFO info; if ( numthreads == -1 ) { // not set manually GetSystemInfo( &info ); numthreads = info.dwNumberOfProcessors; if ( numthreads < 1 || numthreads > 32 ) { numthreads = 1; } } Sys_Printf( "%i threads\n", numthreads ); } void ThreadLock( void ){ if ( !threaded ) { return; } EnterCriticalSection( &crit ); if ( enter ) { Error( "Recursive ThreadLock\n" ); } enter = 1; } void ThreadUnlock( void ){ if ( !threaded ) { return; } if ( !enter ) { Error( "ThreadUnlock without lock\n" ); } enter = 0; LeaveCriticalSection( &crit ); } /* ============= RunThreadsOn ============= */ void RunThreadsOn( int workcnt, qboolean showpacifier, void ( *func )( int ) ){ int threadid[MAX_THREADS]; HANDLE threadhandle[MAX_THREADS]; int i; int start, end; start = I_FloatTime(); dispatch = 0; workcount = workcnt; oldf = -1; pacifier = showpacifier; threaded = true; // // run threads in parallel // InitializeCriticalSection( &crit ); if ( numthreads == 1 ) { // use same thread func( 0 ); } else { for ( i = 0 ; i < numthreads ; i++ ) { threadhandle[i] = CreateThread( NULL, // LPSECURITY_ATTRIBUTES lpsa, //0, // DWORD cbStack, /* ydnar: cranking stack size to eliminate radiosity crash with 1MB stack on win32 */ ( 4096 * 1024 ), (LPTHREAD_START_ROUTINE)func, // LPTHREAD_START_ROUTINE lpStartAddr, (LPVOID)i, // LPVOID lpvThreadParm, 0, // DWORD fdwCreate, &threadid[i] ); } for ( i = 0 ; i < numthreads ; i++ ) WaitForSingleObject( threadhandle[i], INFINITE ); } DeleteCriticalSection( &crit ); threaded = false; end = I_FloatTime(); if ( pacifier ) { Sys_Printf( " (%i)\n", end - start ); } } #endif /* =================================================================== OSF1 =================================================================== */ #ifdef __osf__ #define USED int numthreads = 4; void ThreadSetDefault( void ){ if ( numthreads == -1 ) { // not set manually numthreads = 4; } } #include pthread_mutex_t *my_mutex; void ThreadLock( void ){ if ( my_mutex ) { pthread_mutex_lock( my_mutex ); } } void ThreadUnlock( void ){ if ( my_mutex ) { pthread_mutex_unlock( my_mutex ); } } /* ============= RunThreadsOn ============= */ void RunThreadsOn( int workcnt, qboolean showpacifier, void ( *func )( int ) ){ int i; pthread_t work_threads[MAX_THREADS]; pthread_addr_t status; pthread_attr_t attrib; pthread_mutexattr_t mattrib; int start, end; start = I_FloatTime(); dispatch = 0; workcount = workcnt; oldf = -1; pacifier = showpacifier; threaded = true; if ( pacifier ) { setbuf( stdout, NULL ); } if ( !my_mutex ) { my_mutex = safe_malloc( sizeof( *my_mutex ) ); if ( pthread_mutexattr_create( &mattrib ) == -1 ) { Error( "pthread_mutex_attr_create failed" ); } if ( pthread_mutexattr_setkind_np( &mattrib, MUTEX_FAST_NP ) == -1 ) { Error( "pthread_mutexattr_setkind_np failed" ); } if ( pthread_mutex_init( my_mutex, mattrib ) == -1 ) { Error( "pthread_mutex_init failed" ); } } if ( pthread_attr_create( &attrib ) == -1 ) { Error( "pthread_attr_create failed" ); } if ( pthread_attr_setstacksize( &attrib, 0x100000 ) == -1 ) { Error( "pthread_attr_setstacksize failed" ); } for ( i = 0 ; i < numthreads ; i++ ) { if ( pthread_create( &work_threads[i], attrib , (pthread_startroutine_t)func, (pthread_addr_t)i ) == -1 ) { Error( "pthread_create failed" ); } } for ( i = 0 ; i < numthreads ; i++ ) { if ( pthread_join( work_threads[i], &status ) == -1 ) { Error( "pthread_join failed" ); } } threaded = false; end = I_FloatTime(); if ( pacifier ) { Sys_Printf( " (%i)\n", end - start ); } } #endif /* =================================================================== IRIX =================================================================== */ #ifdef _MIPS_ISA #define USED #include #include #include #include int numthreads = -1; abilock_t lck; void ThreadSetDefault( void ){ if ( numthreads == -1 ) { numthreads = prctl( PR_MAXPPROCS ); } Sys_Printf( "%i threads\n", numthreads ); usconfig( CONF_INITUSERS, numthreads ); } void ThreadLock( void ){ spin_lock( &lck ); } void ThreadUnlock( void ){ release_lock( &lck ); } /* ============= RunThreadsOn ============= */ void RunThreadsOn( int workcnt, qboolean showpacifier, void ( *func )( int ) ){ int i; int pid[MAX_THREADS]; int start, end; start = I_FloatTime(); dispatch = 0; workcount = workcnt; oldf = -1; pacifier = showpacifier; threaded = true; if ( pacifier ) { setbuf( stdout, NULL ); } init_lock( &lck ); for ( i = 0 ; i < numthreads - 1 ; i++ ) { pid[i] = sprocsp( ( void ( * )( void *, size_t ) )func, PR_SALL, (void *)i , NULL, 0x200000 ); // 2 meg stacks if ( pid[i] == -1 ) { perror( "sproc" ); Error( "sproc failed" ); } } func( i ); for ( i = 0 ; i < numthreads - 1 ; i++ ) wait( NULL ); threaded = false; end = I_FloatTime(); if ( pacifier ) { Sys_Printf( " (%i)\n", end - start ); } } #endif /* ======================================================================= Linux pthreads ======================================================================= */ #if defined( __linux__ ) || defined( __APPLE__ ) #define USED // Setting default Threads to 1 int numthreads = 1; void ThreadSetDefault( void ){ if ( numthreads == -1 ) { // not set manually /* default to one thread, only multi-thread when specifically told to */ numthreads = 1; } if ( numthreads > 1 ) { Sys_Printf( "threads: %d\n", numthreads ); } } #include typedef struct pt_mutex_s { pthread_t *owner; pthread_mutex_t a_mutex; pthread_cond_t cond; unsigned int lock; } pt_mutex_t; pt_mutex_t global_lock; void ThreadLock( void ){ pt_mutex_t *pt_mutex = &global_lock; if ( !threaded ) { return; } pthread_mutex_lock( &pt_mutex->a_mutex ); if ( pthread_equal( pthread_self(), (pthread_t)&pt_mutex->owner ) ) { pt_mutex->lock++; } else { if ( ( !pt_mutex->owner ) && ( pt_mutex->lock == 0 ) ) { pt_mutex->owner = (pthread_t *)pthread_self(); pt_mutex->lock = 1; } else { while ( 1 ) { pthread_cond_wait( &pt_mutex->cond, &pt_mutex->a_mutex ); if ( ( !pt_mutex->owner ) && ( pt_mutex->lock == 0 ) ) { pt_mutex->owner = (pthread_t *)pthread_self(); pt_mutex->lock = 1; break; } } } } pthread_mutex_unlock( &pt_mutex->a_mutex ); } void ThreadUnlock( void ){ pt_mutex_t *pt_mutex = &global_lock; if ( !threaded ) { return; } pthread_mutex_lock( &pt_mutex->a_mutex ); pt_mutex->lock--; if ( pt_mutex->lock == 0 ) { pt_mutex->owner = NULL; pthread_cond_signal( &pt_mutex->cond ); } pthread_mutex_unlock( &pt_mutex->a_mutex ); } void recursive_mutex_init( pthread_mutexattr_t attribs ){ pt_mutex_t *pt_mutex = &global_lock; pt_mutex->owner = NULL; if ( pthread_mutex_init( &pt_mutex->a_mutex, &attribs ) != 0 ) { Error( "pthread_mutex_init failed\n" ); } if ( pthread_cond_init( &pt_mutex->cond, NULL ) != 0 ) { Error( "pthread_cond_init failed\n" ); } pt_mutex->lock = 0; } /* ============= RunThreadsOn ============= */ void RunThreadsOn( int workcnt, qboolean showpacifier, void ( *func )( int ) ){ pthread_mutexattr_t mattrib; pthread_t work_threads[MAX_THREADS]; int start, end; int i = 0, status = 0; start = I_FloatTime(); pacifier = showpacifier; dispatch = 0; oldf = -1; workcount = workcnt; if ( numthreads == 1 ) { func( 0 ); } else { threaded = true; if ( pacifier ) { setbuf( stdout, NULL ); } if ( pthread_mutexattr_init( &mattrib ) != 0 ) { Error( "pthread_mutexattr_init failed" ); } if ( pthread_mutexattr_settype( &mattrib, PTHREAD_MUTEX_ERRORCHECK ) != 0 ) { Error( "pthread_mutexattr_settype failed" ); } recursive_mutex_init( mattrib ); for ( i = 0 ; i < numthreads ; i++ ) { /* Default pthread attributes: joinable & non-realtime scheduling */ if ( pthread_create( &work_threads[i], NULL, (void*)func, (void*)i ) != 0 ) { Error( "pthread_create failed" ); } } for ( i = 0 ; i < numthreads ; i++ ) { if ( pthread_join( work_threads[i], (void **)&status ) != 0 ) { Error( "pthread_join failed" ); } } pthread_mutexattr_destroy( &mattrib ); threaded = false; } end = I_FloatTime(); if ( pacifier ) { Sys_Printf( " (%i)\n", end - start ); } } #endif // ifdef __linux__ /* ======================================================================= SINGLE THREAD ======================================================================= */ #ifndef USED int numthreads = 1; void ThreadSetDefault( void ){ numthreads = 1; } void ThreadLock( void ){ } void ThreadUnlock( void ){ } /* ============= RunThreadsOn ============= */ void RunThreadsOn( int workcnt, qboolean showpacifier, void ( *func )( int ) ){ int i; int start, end; dispatch = 0; workcount = workcnt; oldf = -1; pacifier = showpacifier; start = I_FloatTime(); func( 0 ); end = I_FloatTime(); if ( pacifier ) { Sys_Printf( " (%i)\n", end - start ); } } #endif