doom3-bfg/neo/idlib/sys/sys_threading.h
Daniel Gibson fe18a49303 Improve POSIX threading code
* setting threadname is now done in a seperate function so it's a bit
cleaner (it's different for every platform..)
* replace/refactor signaling code (based on my SDL threading branch and
  the old pthread signaling code from RB):
  - The interface is like on win32 now (Sys_Signal* functions instead of
    overwriting idSysSignal class)
  - created a custom signalHandle_t struct for that, which contains all
    needed information
  - Mimic Windows functions used in win32 implementation more closely,
    e.g. signal all waiting threads on manualReset signalRaise, count
    waiting threads etc. I'm pretty sure the behavior on Win32 and POSIX
    now is identical (as far as possible).
2013-03-25 22:05:02 +01:00

244 lines
7 KiB
C++

/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2012 Robert Beckebans
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
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.
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.
===========================================================================
*/
#ifndef __SYS_THREADING_H__
#define __SYS_THREADING_H__
#ifndef __TYPEINFOGEN__
/*
================================================================================================
Platform specific mutex, signal, atomic integer and memory barrier.
================================================================================================
*/
// RB begin
#if defined(_WIN32)
typedef CRITICAL_SECTION mutexHandle_t;
typedef HANDLE signalHandle_t;
typedef LONG interlockedInt_t;
#else
struct signalHandle_t
{
// DG: all this stuff is needed to emulate Window's Event API
// (CreateEvent(), SetEvent(), WaitForSingleObject(), ...)
pthread_cond_t cond;
pthread_mutex_t mutex;
int waiting; // number of threads waiting for a signal
bool manualReset;
bool signaled; // is it signaled right now?
};
typedef pthread_mutex_t mutexHandle_t;
typedef int interlockedInt_t;
#endif
// RB end
// _ReadWriteBarrier() does not translate to any instructions but keeps the compiler
// from reordering read and write instructions across the barrier.
// MemoryBarrier() inserts and CPU instruction that keeps the CPU from reordering reads and writes.
#if defined(_MSC_VER)
#pragma intrinsic(_ReadWriteBarrier)
#define SYS_MEMORYBARRIER _ReadWriteBarrier(); MemoryBarrier()
#elif defined(__GNUC__) // FIXME: what about clang?
// according to http://en.wikipedia.org/wiki/Memory_ordering the following should be equivalent to the stuff above..
//#ifdef __sync_syncronize
#define SYS_MEMORYBARRIER asm volatile("" ::: "memory");__sync_synchronize()
#endif
/*
================================================================================================
Platform specific thread local storage.
Can be used to store either a pointer or an integer.
================================================================================================
*/
// RB: added POSIX implementation
#if defined(_WIN32)
class idSysThreadLocalStorage
{
public:
idSysThreadLocalStorage()
{
tlsIndex = TlsAlloc();
}
idSysThreadLocalStorage( const ptrdiff_t& val )
{
tlsIndex = TlsAlloc();
TlsSetValue( tlsIndex, ( LPVOID )val );
}
~idSysThreadLocalStorage()
{
TlsFree( tlsIndex );
}
operator ptrdiff_t()
{
return ( ptrdiff_t )TlsGetValue( tlsIndex );
}
const ptrdiff_t& operator = ( const ptrdiff_t& val )
{
TlsSetValue( tlsIndex, ( LPVOID )val );
return val;
}
DWORD tlsIndex;
};
#else
class idSysThreadLocalStorage
{
public:
idSysThreadLocalStorage()
{
pthread_key_create( &key, NULL );
}
idSysThreadLocalStorage( const ptrdiff_t& val )
{
pthread_key_create( &key, NULL );
pthread_setspecific( key, ( const void* ) val );
}
~idSysThreadLocalStorage()
{
pthread_key_delete( key );
}
operator ptrdiff_t()
{
return ( ptrdiff_t )pthread_getspecific( key );
}
const ptrdiff_t& operator = ( const ptrdiff_t& val )
{
pthread_setspecific( key, ( const void* ) val );
return val;
}
pthread_key_t key;
};
#endif
// RB end
#define ID_TLS idSysThreadLocalStorage
#endif // __TYPEINFOGEN__
/*
================================================================================================
Platform independent threading functions.
================================================================================================
*/
enum core_t
{
CORE_ANY = -1,
CORE_0A,
CORE_0B,
CORE_1A,
CORE_1B,
CORE_2A,
CORE_2B
};
typedef unsigned int ( *xthread_t )( void* );
enum xthreadPriority
{
THREAD_LOWEST,
THREAD_BELOW_NORMAL,
THREAD_NORMAL,
THREAD_ABOVE_NORMAL,
THREAD_HIGHEST
};
#define DEFAULT_THREAD_STACK_SIZE ( 256 * 1024 )
// on win32, the threadID is NOT the same as the threadHandle
uintptr_t Sys_GetCurrentThreadID();
// returns a threadHandle
uintptr_t Sys_CreateThread( xthread_t function, void* parms, xthreadPriority priority,
const char* name, core_t core, int stackSize = DEFAULT_THREAD_STACK_SIZE,
bool suspended = false );
// RB begin
// removed unused Sys_WaitForThread
void Sys_DestroyThread( uintptr_t threadHandle );
void Sys_SetCurrentThreadName( const char* name );
void Sys_SignalCreate( signalHandle_t& handle, bool manualReset );
void Sys_SignalDestroy( signalHandle_t& handle );
void Sys_SignalRaise( signalHandle_t& handle );
void Sys_SignalClear( signalHandle_t& handle );
bool Sys_SignalWait( signalHandle_t& handle, int timeout );
void Sys_MutexCreate( mutexHandle_t& handle );
void Sys_MutexDestroy( mutexHandle_t& handle );
bool Sys_MutexLock( mutexHandle_t& handle, bool blocking );
void Sys_MutexUnlock( mutexHandle_t& handle );
interlockedInt_t Sys_InterlockedIncrement( interlockedInt_t& value );
interlockedInt_t Sys_InterlockedDecrement( interlockedInt_t& value );
interlockedInt_t Sys_InterlockedAdd( interlockedInt_t& value, interlockedInt_t i );
interlockedInt_t Sys_InterlockedSub( interlockedInt_t& value, interlockedInt_t i );
interlockedInt_t Sys_InterlockedExchange( interlockedInt_t& value, interlockedInt_t exchange );
interlockedInt_t Sys_InterlockedCompareExchange( interlockedInt_t& value, interlockedInt_t comparand, interlockedInt_t exchange );
void* Sys_InterlockedExchangePointer( void*& ptr, void* exchange );
void* Sys_InterlockedCompareExchangePointer( void*& ptr, void* comparand, void* exchange );
void Sys_Yield();
const int MAX_CRITICAL_SECTIONS = 4;
enum
{
CRITICAL_SECTION_ZERO = 0,
CRITICAL_SECTION_ONE,
CRITICAL_SECTION_TWO,
CRITICAL_SECTION_THREE
};
#endif // !__SYS_THREADING_H__