doom3-bfg/neo/idlib/sys/win32/win_thread.cpp
2012-11-26 12:58:24 -06:00

358 lines
10 KiB
C++
Raw Blame History

/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
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.
===========================================================================
*/
#pragma hdrstop
#include "../../precompiled.h"
/*
================================================================================================
================================================================================================
*/
#define MS_VC_EXCEPTION 0x406D1388
typedef struct tagTHREADNAME_INFO {
DWORD dwType; // Must be 0x1000.
LPCSTR szName; // Pointer to name (in user addr space).
DWORD dwThreadID; // Thread ID (-1=caller thread).
DWORD dwFlags; // Reserved for future use, must be zero.
} THREADNAME_INFO;
/*
========================
Sys_SetThreadName
========================
*/
void Sys_SetThreadName( DWORD threadID, const char * name ) {
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = name;
info.dwThreadID = threadID;
info.dwFlags = 0;
__try {
RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(DWORD), (const ULONG_PTR *)&info );
}
// this much is just to keep /analyze quiet
__except( GetExceptionCode() == MS_VC_EXCEPTION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
info.dwFlags = 0;
}
}
/*
========================
Sys_SetCurrentThreadName
========================
*/
void Sys_SetCurrentThreadName( const char * name ) {
Sys_SetThreadName( GetCurrentThreadId(), name );
}
/*
========================
Sys_Createthread
========================
*/
uintptr_t Sys_CreateThread( xthread_t function, void *parms, xthreadPriority priority, const char *name, core_t core, int stackSize, bool suspended ) {
DWORD flags = ( suspended ? CREATE_SUSPENDED : 0 );
// Without this flag the 'dwStackSize' parameter to CreateThread specifies the "Stack Commit Size"
// and the "Stack Reserve Size" is set to the value specified at link-time.
// With this flag the 'dwStackSize' parameter to CreateThread specifies the "Stack Reserve Size"
// and the <20>Stack Commit Size<7A> is set to the value specified at link-time.
// For various reasons (some of which historic) we reserve a large amount of stack space in the
// project settings. By setting this flag and by specifying 64 kB for the "Stack Commit Size" in
// the project settings we can create new threads with a much smaller reserved (and committed)
// stack space. It is very important that the "Stack Commit Size" is set to a small value in
// the project settings. If it is set to a large value we may be both reserving and committing
// a lot of memory by setting the STACK_SIZE_PARAM_IS_A_RESERVATION flag. There are some
// 50 threads allocated for normal game play. If, for instance, the commit size is set to 16 MB
// then by adding this flag we would be reserving and committing 50 x 16 = 800 MB of memory.
// On the other hand, if this flag is not set and the "Stack Reserve Size" is set to 16 MB in the
// project settings, then we would still be reserving 50 x 16 = 800 MB of virtual address space.
flags |= STACK_SIZE_PARAM_IS_A_RESERVATION;
DWORD threadId;
HANDLE handle = CreateThread( NULL, // LPSECURITY_ATTRIBUTES lpsa, //-V513
stackSize,
(LPTHREAD_START_ROUTINE)function,
parms,
flags,
&threadId);
if ( handle == 0 ) {
idLib::common->FatalError( "CreateThread error: %i", GetLastError() );
return (uintptr_t)0;
}
Sys_SetThreadName( threadId, name );
if ( priority == THREAD_HIGHEST ) {
SetThreadPriority( (HANDLE)handle, THREAD_PRIORITY_HIGHEST ); // we better sleep enough to do this
} else if ( priority == THREAD_ABOVE_NORMAL ) {
SetThreadPriority( (HANDLE)handle, THREAD_PRIORITY_ABOVE_NORMAL );
} else if ( priority == THREAD_BELOW_NORMAL ) {
SetThreadPriority( (HANDLE)handle, THREAD_PRIORITY_BELOW_NORMAL );
} else if ( priority == THREAD_LOWEST ) {
SetThreadPriority( (HANDLE)handle, THREAD_PRIORITY_LOWEST );
}
// Under Windows, we don't set the thread affinity and let the OS deal with scheduling
return (uintptr_t)handle;
}
/*
========================
Sys_GetCurrentThreadID
========================
*/
uintptr_t Sys_GetCurrentThreadID() {
return GetCurrentThreadId();
}
/*
========================
Sys_WaitForThread
========================
*/
void Sys_WaitForThread( uintptr_t threadHandle ) {
WaitForSingleObject( (HANDLE)threadHandle, INFINITE );
}
/*
========================
Sys_DestroyThread
========================
*/
void Sys_DestroyThread( uintptr_t threadHandle ) {
if ( threadHandle == 0 ) {
return;
}
WaitForSingleObject( (HANDLE)threadHandle, INFINITE );
CloseHandle( (HANDLE)threadHandle );
}
/*
========================
Sys_Yield
========================
*/
void Sys_Yield() {
SwitchToThread();
}
/*
================================================================================================
Signal
================================================================================================
*/
/*
========================
Sys_SignalCreate
========================
*/
void Sys_SignalCreate( signalHandle_t & handle, bool manualReset ) {
handle = CreateEvent( NULL, manualReset, FALSE, NULL );
}
/*
========================
Sys_SignalDestroy
========================
*/
void Sys_SignalDestroy( signalHandle_t &handle ) {
CloseHandle( handle );
}
/*
========================
Sys_SignalRaise
========================
*/
void Sys_SignalRaise( signalHandle_t & handle ) {
SetEvent( handle );
}
/*
========================
Sys_SignalClear
========================
*/
void Sys_SignalClear( signalHandle_t & handle ) {
// events are created as auto-reset so this should never be needed
ResetEvent( handle );
}
/*
========================
Sys_SignalWait
========================
*/
bool Sys_SignalWait( signalHandle_t & handle, int timeout ) {
DWORD result = WaitForSingleObject( handle, timeout == idSysSignal::WAIT_INFINITE ? INFINITE : timeout );
assert( result == WAIT_OBJECT_0 || ( timeout != idSysSignal::WAIT_INFINITE && result == WAIT_TIMEOUT ) );
return ( result == WAIT_OBJECT_0 );
}
/*
================================================================================================
Mutex
================================================================================================
*/
/*
========================
Sys_MutexCreate
========================
*/
void Sys_MutexCreate( mutexHandle_t & handle ) {
InitializeCriticalSection( &handle );
}
/*
========================
Sys_MutexDestroy
========================
*/
void Sys_MutexDestroy( mutexHandle_t & handle ) {
DeleteCriticalSection( &handle );
}
/*
========================
Sys_MutexLock
========================
*/
bool Sys_MutexLock( mutexHandle_t & handle, bool blocking ) {
if ( TryEnterCriticalSection( &handle ) == 0 ) {
if ( !blocking ) {
return false;
}
EnterCriticalSection( &handle );
}
return true;
}
/*
========================
Sys_MutexUnlock
========================
*/
void Sys_MutexUnlock( mutexHandle_t & handle ) {
LeaveCriticalSection( & handle );
}
/*
================================================================================================
Interlocked Integer
================================================================================================
*/
/*
========================
Sys_InterlockedIncrement
========================
*/
interlockedInt_t Sys_InterlockedIncrement( interlockedInt_t & value ) {
return InterlockedIncrementAcquire( & value );
}
/*
========================
Sys_InterlockedDecrement
========================
*/
interlockedInt_t Sys_InterlockedDecrement( interlockedInt_t & value ) {
return InterlockedDecrementRelease( & value );
}
/*
========================
Sys_InterlockedAdd
========================
*/
interlockedInt_t Sys_InterlockedAdd( interlockedInt_t & value, interlockedInt_t i ) {
return InterlockedExchangeAdd( & value, i ) + i;
}
/*
========================
Sys_InterlockedSub
========================
*/
interlockedInt_t Sys_InterlockedSub( interlockedInt_t & value, interlockedInt_t i ) {
return InterlockedExchangeAdd( & value, - i ) - i;
}
/*
========================
Sys_InterlockedExchange
========================
*/
interlockedInt_t Sys_InterlockedExchange( interlockedInt_t & value, interlockedInt_t exchange ) {
return InterlockedExchange( & value, exchange );
}
/*
========================
Sys_InterlockedCompareExchange
========================
*/
interlockedInt_t Sys_InterlockedCompareExchange( interlockedInt_t & value, interlockedInt_t comparand, interlockedInt_t exchange ) {
return InterlockedCompareExchange( & value, exchange, comparand );
}
/*
================================================================================================
Interlocked Pointer
================================================================================================
*/
/*
========================
Sys_InterlockedExchangePointer
========================
*/
void *Sys_InterlockedExchangePointer( void *& ptr, void * exchange ) {
return InterlockedExchangePointer( & ptr, exchange );
}
/*
========================
Sys_InterlockedCompareExchangePointer
========================
*/
void * Sys_InterlockedCompareExchangePointer( void * & ptr, void * comparand, void * exchange ) {
return InterlockedCompareExchangePointer( & ptr, exchange, comparand );
}