mirror of
https://github.com/intel/intel-graphics-compiler.git
synced 2025-11-04 08:21:06 +08:00
610 lines
17 KiB
C++
610 lines
17 KiB
C++
/*========================== begin_copyright_notice ============================
|
|
|
|
Copyright (C) 2017-2021 Intel Corporation
|
|
|
|
SPDX-License-Identifier: MIT
|
|
|
|
============================= end_copyright_notice ===========================*/
|
|
|
|
#pragma once
|
|
|
|
#ifdef ISTDLIB_MT
|
|
#ifdef WIN32_NO_STATUS
|
|
#undef WIN32_NO_STATUS
|
|
#include <ntstatus.h>
|
|
#define WIN32_NO_STATUS
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
# include "types.h"
|
|
# include <process.h>
|
|
# include <malloc.h>
|
|
#endif // _WIN32
|
|
|
|
namespace iSTD
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
/*****************************************************************************\
|
|
Critical Section types
|
|
\*****************************************************************************/
|
|
#ifdef ISTDLIB_MT
|
|
#define DECL_CRITICAL_SECTION(x) CRITICAL_SECTION x
|
|
#define INIT_CRITICAL_SECTION(x) ::InitializeCriticalSection( &(x) )
|
|
#define DELETE_CRITICAL_SECTION(x) ::DeleteCriticalSection( &(x) )
|
|
#define ENTER_CRITICAL_SECTION(x) ::EnterCriticalSection( &(x) )
|
|
#define LEAVE_CRITICAL_SECTION(x) ::LeaveCriticalSection( &(x) )
|
|
#else
|
|
#define DECL_CRITICAL_SECTION(x)
|
|
#define INIT_CRITICAL_SECTION(x)
|
|
#define DELETE_CRITICAL_SECTION(x)
|
|
#define ENTER_CRITICAL_SECTION(x)
|
|
#define LEAVE_CRITICAL_SECTION(x)
|
|
#endif
|
|
|
|
/*****************************************************************************\
|
|
Critical Section debug
|
|
\*****************************************************************************/
|
|
// The following macros are used to allow synchronizing a function
|
|
// to debug multithreading issues due to re-entrancy
|
|
#define ENABLE_THREADED_FUNCTION_SYNC FALSE
|
|
|
|
#if defined(ISTDLIB_MT) && ENABLE_THREADED_FUNCTION_SYNC
|
|
|
|
// Structure to store data
|
|
struct THREADED_FUNCTION_DATA
|
|
{
|
|
// switch to enable\disable synchronizing a function to debug
|
|
// possible threading issues. intended to be toggled manually
|
|
// using the debugger. always disabled by default.
|
|
bool IsEnabled;
|
|
|
|
// critical section data to synchronize function
|
|
DECL_CRITICAL_SECTION( CS );
|
|
|
|
// default constructor to initialize data
|
|
THREADED_FUNCTION_DATA()
|
|
{
|
|
IsEnabled = false;
|
|
INIT_CRITICAL_SECTION( CS );
|
|
};
|
|
|
|
// default destructor to clean-up data
|
|
~THREADED_FUNCTION_DATA()
|
|
{
|
|
DELETE_CRITICAL_SECTION( CS );
|
|
};
|
|
};
|
|
|
|
// Macro for entry-point of threaded function
|
|
// Each function has a unique (static) enable and critical section
|
|
#define THREADED_FUNCTION_ENTER \
|
|
static iSTD::THREADED_FUNCTION_DATA sTFD; \
|
|
if( sTFD.IsEnabled ) \
|
|
{ \
|
|
ENTER_CRITICAL_SECTION( sTFD.CS ); \
|
|
}
|
|
|
|
// Macro for exit-point of threaded function
|
|
#define THREADED_FUNCTION_EXIT \
|
|
if( sTFD.IsEnabled ) \
|
|
{ \
|
|
LEAVE_CRITICAL_SECTION( sTFD.CS ); \
|
|
}
|
|
|
|
#else
|
|
|
|
#define THREADED_FUNCTION_ENTER
|
|
#define THREADED_FUNCTION_EXIT
|
|
|
|
#endif
|
|
|
|
/*****************************************************************************\
|
|
Mutex debug
|
|
\*****************************************************************************/
|
|
// The following macros are used to check that classes\functions that are not
|
|
// re-entrant, are never executed concurently for a single instance
|
|
#define ENABLE_DEBUG_MUTEX FALSE
|
|
|
|
#if defined(ISTDLIB_MT) && ENABLE_DEBUG_MUTEX
|
|
|
|
// Structure to store data needed by the debug mutex macros
|
|
// 1) a mutex handle to ensure only a single thread exists between Acquire and Release
|
|
// 2) a counter for the number of threads trying to enter
|
|
struct DEBUG_MUTEX_DATA
|
|
{
|
|
HANDLE Mutex;
|
|
(unsigned __int64*) pCounter;
|
|
};
|
|
|
|
// Declare the data structure
|
|
#define DECL_DEBUG_MUTEX(x) iSTD::DEBUG_MUTEX_DATA x
|
|
|
|
// Initialize the debug mutex data
|
|
// Read Access counter is x.pCounter[0]
|
|
// Write Access counter is x.pCounter[1]
|
|
#define INIT_DEBUG_MUTEX(x) \
|
|
{ \
|
|
x.Mutex = ::CreateMutex( NULL, FALSE, NULL ); \
|
|
x.pCounter = (unsigned __int64*)::_aligned_malloc( \
|
|
2 * sizeof(unsigned __int64), sizeof(unsigned __int64) ); \
|
|
x.pCounter[0] = 0; \
|
|
x.pCounter[1] = 0; \
|
|
}
|
|
|
|
// Clean-up the debug mutex data
|
|
#define DELETE_DEBUG_MUTEX(x) \
|
|
{ \
|
|
::CloseHandle( x.Mutex ); \
|
|
::_aligned_free( x.pCounter ); \
|
|
}
|
|
|
|
// Increment the counter of the number of threads entering with read access
|
|
// Acquire the mutex and break if another thread is waiting for write access
|
|
#define ACQUIRE_DEBUG_MUTEX_READ(x) \
|
|
{ \
|
|
::InterlockedIncrement( (unsigned __int64*)&( x.pCounter[0] ) ); \
|
|
while( WAIT_OBJECT_0 != ::WaitForSingleObject( x.Mutex, 1 ) ) \
|
|
if ( 0 != ::InterlockedOr( (unsigned __int64*)&( x.pCounter[1] ), 0 ) ) \
|
|
__debugbreak(); \
|
|
}
|
|
|
|
// Break if there is another thread waiting for write access
|
|
// Decrement read access counter
|
|
// Release the mutex
|
|
#define RELEASE_DEBUG_MUTEX_READ(x) \
|
|
{ \
|
|
if( 0 != ::InterlockedOr( (unsigned __int64*)&( x.pCounter[1] ), 0 ) ) \
|
|
__debugbreak(); \
|
|
::InterlockedDecrement( (unsigned __int64*)&( x.pCounter[0] ) ); \
|
|
::ReleaseMutex( x.Mutex ); \
|
|
}
|
|
|
|
// Increment the counter of the number of threads entering with write access
|
|
// Acquire the mutex and break if another thread owns the mutex
|
|
#define ACQUIRE_DEBUG_MUTEX_WRITE(x) \
|
|
{ \
|
|
::InterlockedIncrement( (unsigned __int64*)&( x.pCounter[1] ) ); \
|
|
while( WAIT_OBJECT_0 != ::WaitForSingleObject( x.Mutex, 1 ) ) \
|
|
__debugbreak(); \
|
|
}
|
|
|
|
// Break if there is another thread waiting for read access
|
|
// Decrement the counter and break if there is another thread waiting for write access
|
|
// Release the mutex
|
|
#define RELEASE_DEBUG_MUTEX_WRITE(x) \
|
|
{ \
|
|
if( 0 != ::InterlockedOr( (unsigned __int64*)&( x.pCounter[0] ), 0 ) ) \
|
|
__debugbreak(); \
|
|
if( 0 != ::InterlockedDecrement( (unsigned __int64*)&( x.pCounter[1] ) ) ) \
|
|
__debugbreak(); \
|
|
::ReleaseMutex( x.Mutex ); \
|
|
}
|
|
|
|
#else
|
|
#define DECL_DEBUG_MUTEX(x)
|
|
#define INIT_DEBUG_MUTEX(x)
|
|
#define DELETE_DEBUG_MUTEX(x)
|
|
#define ACQUIRE_DEBUG_MUTEX_READ(x)
|
|
#define RELEASE_DEBUG_MUTEX_READ(x)
|
|
#define ACQUIRE_DEBUG_MUTEX_WRITE(x)
|
|
#define RELEASE_DEBUG_MUTEX_WRITE(x)
|
|
#endif
|
|
|
|
#ifdef ISTDLIB_MT
|
|
|
|
/*****************************************************************************\
|
|
Thread Management types
|
|
\*****************************************************************************/
|
|
// These are heavy-weight threads; consider using Thread-Pools instead
|
|
#define THREAD_ARGUMENT void*
|
|
typedef unsigned int (__stdcall *THREAD_FUNCTION)( THREAD_ARGUMENT );
|
|
|
|
#ifdef ISTDLIB_MT
|
|
#define THREAD_HANDLE HANDLE
|
|
#else
|
|
struct THREAD_DATA
|
|
{
|
|
THREAD_FUNCTION func;
|
|
THREAD_ARGUMENT arg;
|
|
};
|
|
#define THREAD_HANDLE THREAD_DATA*
|
|
#endif
|
|
|
|
/*****************************************************************************\
|
|
Function:
|
|
CreateThreads
|
|
|
|
Input:
|
|
const DWORD numThreads - number of threads to create
|
|
THREAD_FUNCTION func - pointer to function to execute
|
|
THREAD_ARGUMENT* args - array of per-thread arguments
|
|
|
|
Output:
|
|
THREAD_HANDLE* threads - array of per-thread handles
|
|
THREAD_HANDLE* beginEvents - array of per-thread events to signal the
|
|
thread to begin
|
|
THREAD_HANDLE* endEvents - array of per-thread events the thread sets
|
|
when complete
|
|
HRESULT
|
|
|
|
\*****************************************************************************/
|
|
inline HRESULT CreateThreads(
|
|
const DWORD numThreads,
|
|
THREAD_FUNCTION func,
|
|
THREAD_ARGUMENT* args,
|
|
THREAD_HANDLE* threads,
|
|
THREAD_HANDLE* beginEvents,
|
|
THREAD_HANDLE* endEvents )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
for( DWORD i = 0; i < numThreads; ++i )
|
|
{
|
|
#ifdef ISTDLIB_MT
|
|
|
|
beginEvents[i] = ::CreateEvent( NULL, FALSE, FALSE, NULL );
|
|
endEvents[i] = ::CreateEvent( NULL, FALSE, FALSE, NULL );
|
|
|
|
threads[i] = ( THREAD_HANDLE )::_beginthreadex(
|
|
NULL,
|
|
0,
|
|
func,
|
|
args[i],
|
|
CREATE_SUSPENDED,
|
|
NULL );
|
|
|
|
if( threads[i] )
|
|
{
|
|
::ResumeThread( threads[i] );
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
#else
|
|
|
|
threads[i] = (THREAD_DATA*)malloc( sizeof(THREAD_DATA) );
|
|
|
|
if( threads[i] )
|
|
{
|
|
threads[i]->func = func;
|
|
threads[i]->arg = args[i];
|
|
|
|
beginEvents[i] = threads[i];
|
|
endEvents[i] = NULL;
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
StartThreads
|
|
\*****************************************************************************/
|
|
inline void StartThreads(
|
|
const DWORD numThreads,
|
|
THREAD_HANDLE* beginEvents )
|
|
{
|
|
for( DWORD i = 0; i < numThreads; ++i )
|
|
{
|
|
#ifdef ISTDLIB_MT
|
|
|
|
::SetEvent( beginEvents[i] );
|
|
|
|
#else
|
|
|
|
beginEvents[i]->func( beginEvents[i]->arg );
|
|
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
WaitForThreads
|
|
\*****************************************************************************/
|
|
inline void WaitForThreads(
|
|
const DWORD numThreads,
|
|
THREAD_HANDLE* endEvents )
|
|
{
|
|
#ifdef ISTDLIB_MT
|
|
|
|
#ifdef _DEBUG
|
|
|
|
// deadlock detection
|
|
DWORD result = 0;
|
|
do
|
|
{
|
|
result = ::WaitForMultipleObjects(
|
|
numThreads,
|
|
endEvents,
|
|
TRUE,
|
|
1000 );
|
|
result &= 0xfffffff0;
|
|
ASSERT( WAIT_OBJECT_0 == result );
|
|
}
|
|
while( WAIT_OBJECT_0 != result );
|
|
|
|
#else
|
|
|
|
::WaitForMultipleObjects(
|
|
numThreads,
|
|
endEvents,
|
|
TRUE,
|
|
INFINITE );
|
|
|
|
#endif
|
|
|
|
#endif
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
DeleteThreads
|
|
\*****************************************************************************/
|
|
inline void DeleteThreads(
|
|
const DWORD numThreads,
|
|
THREAD_HANDLE* threads,
|
|
THREAD_HANDLE* beginEvents,
|
|
THREAD_HANDLE* endEvents )
|
|
{
|
|
for( DWORD i = 0; i < numThreads; ++i )
|
|
{
|
|
#ifdef ISTDLIB_MT
|
|
|
|
::CloseHandle( threads[i] );
|
|
::CloseHandle( endEvents[i] );
|
|
::CloseHandle( beginEvents[i] );
|
|
|
|
#else
|
|
|
|
free( threads[i] );
|
|
threads[i] = NULL;
|
|
endEvents[i] = NULL;
|
|
beginEvents[i] = NULL;
|
|
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
Thread-Pool Management types
|
|
\*****************************************************************************/
|
|
#if defined(ISTDLIB_MT) && (_WIN32_WINNT >= 0x0600)
|
|
// Minimum supported client: Windows Vista (_WIN32_WINNT_VISTA = 0x0600)
|
|
|
|
/*****************************************************************************\
|
|
|
|
Function:
|
|
CreateThreadPool
|
|
|
|
Description:
|
|
Creates a thread pool
|
|
|
|
Input:
|
|
PTP_CALLBACK_ENVIRON ptrPoolEnv - pointer to storage where thread pool
|
|
environment will be stored
|
|
DWORD minThreads - minimum number of requested threads in the thread pool.
|
|
DWORD maxThreads - maximum number of requested threads in the thread pool.
|
|
|
|
Output:
|
|
BOOL - Success or Fail
|
|
|
|
Notes:
|
|
Client is responsible for management of PTP_CALLBACK_ENVIRON memory
|
|
|
|
\*****************************************************************************/
|
|
inline BOOL CreateThreadPool(
|
|
PTP_CALLBACK_ENVIRON ptrPoolEnv,
|
|
const DWORD minThreads,
|
|
const DWORD maxThreads )
|
|
{
|
|
if( ptrPoolEnv )
|
|
{
|
|
InitializeThreadpoolEnvironment( ptrPoolEnv );
|
|
|
|
PTP_POOL ptrPool = CreateThreadpool( NULL );
|
|
if( ptrPool )
|
|
{
|
|
SetThreadpoolThreadMinimum( ptrPool, minThreads );
|
|
SetThreadpoolThreadMaximum( ptrPool, maxThreads );
|
|
|
|
SetThreadpoolCallbackRunsLong( ptrPoolEnv );
|
|
SetThreadpoolCallbackPool( ptrPoolEnv, ptrPool );
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
|
|
Function:
|
|
CreateThreadPool
|
|
|
|
Description:
|
|
Creates a thread pool
|
|
|
|
Input:
|
|
PTP_CALLBACK_ENVIRON ptrPoolEnv - pointer to storage where thread pool
|
|
environment will be stored
|
|
|
|
Output:
|
|
BOOL - Success or Fail
|
|
|
|
Notes:
|
|
Client is responsible for management of PTP_CALLBACK_ENVIRON memory
|
|
|
|
\*****************************************************************************/
|
|
inline BOOL CreateThreadPool(
|
|
PTP_CALLBACK_ENVIRON ptrPoolEnv )
|
|
{
|
|
SYSTEM_INFO si = { 0 };
|
|
::GetSystemInfo( &si );
|
|
return CreateThreadPool( ptrPoolEnv, si.dwNumberOfProcessors, si.dwNumberOfProcessors );
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
|
|
Function:
|
|
DeleteThreadPool
|
|
|
|
Description:
|
|
Deletes a thread pool
|
|
|
|
Input:
|
|
PTP_CALLBACK_ENVIRON ptrPoolEnv - pointer to storage where thread pool
|
|
environment is stored
|
|
|
|
Output:
|
|
none
|
|
|
|
Notes:
|
|
Client is responsible for management of PTP_CALLBACK_ENVIRON memory
|
|
|
|
\*****************************************************************************/
|
|
inline void DeleteThreadPool(
|
|
PTP_CALLBACK_ENVIRON ptrPoolEnv )
|
|
{
|
|
if( ptrPoolEnv )
|
|
{
|
|
if( ptrPoolEnv->Pool )
|
|
{
|
|
CloseThreadpool( ptrPoolEnv->Pool );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
|
|
Function:
|
|
CreateThreadPoolWork
|
|
|
|
Description:
|
|
Creates a thread pool work item
|
|
|
|
Input:
|
|
PTP_WORK_CALLBACK pWorkFunc - pointer to function to add to thread pool
|
|
PVOID pWorkData - optional data to pass to function
|
|
PTP_CALLBACK_ENVIRON ptrPoolEnv - thread pool environment
|
|
|
|
Output:
|
|
PTP_WORK - pointer to work item
|
|
|
|
\*****************************************************************************/
|
|
inline PTP_WORK CreateThreadPoolWork(
|
|
PTP_WORK_CALLBACK pWorkFunc,
|
|
PVOID pWorkData,
|
|
PTP_CALLBACK_ENVIRON ptrPoolEnv )
|
|
{
|
|
return CreateThreadpoolWork( pWorkFunc, pWorkData, ptrPoolEnv );
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
|
|
Function:
|
|
SubmitThreadPoolWork
|
|
|
|
Description:
|
|
Submits a thread pool work item to the thread pool
|
|
|
|
Input:
|
|
PTP_WORK - pointer to work item
|
|
|
|
Output:
|
|
none
|
|
|
|
\*****************************************************************************/
|
|
inline void SubmitThreadPoolWork(
|
|
PTP_WORK pWorkItem )
|
|
{
|
|
if( pWorkItem )
|
|
{
|
|
SubmitThreadpoolWork( pWorkItem );
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
|
|
Function:
|
|
WaitForThreadPoolWork
|
|
|
|
Description:
|
|
Waits for the thread pool work item to complete
|
|
|
|
Input:
|
|
PTP_WORK ptrWork - pointer to work item
|
|
|
|
Output:
|
|
none
|
|
|
|
\*****************************************************************************/
|
|
inline void WaitForThreadPoolWork(
|
|
PTP_WORK ptrWork )
|
|
{
|
|
if( ptrWork )
|
|
{
|
|
WaitForThreadpoolWorkCallbacks( ptrWork, FALSE );
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
|
|
Function:
|
|
DeleteThreadPoolWork
|
|
|
|
Description:
|
|
Deletes the thread pool work item to complete
|
|
|
|
Input:
|
|
PTP_WORK ptrWork - pointer to work item
|
|
|
|
Output:
|
|
none
|
|
|
|
\*****************************************************************************/
|
|
inline void DeleteThreadPoolWork(
|
|
PTP_WORK& ptrWork )
|
|
{
|
|
if( ptrWork )
|
|
{
|
|
CloseThreadpoolWork( ptrWork );
|
|
ptrWork = NULL;
|
|
}
|
|
}
|
|
|
|
#endif //defined(ISTDLIB_MT) && (_WIN32_WINNT >= 0x0600)
|
|
|
|
#endif //ISTDLIB_MT
|
|
|
|
#else // _WIN32
|
|
|
|
#define THREADED_FUNCTION_ENTER
|
|
#define THREADED_FUNCTION_EXIT
|
|
|
|
#define DECL_CRITICAL_SECTION(x)
|
|
#define INIT_CRITICAL_SECTION(x)
|
|
#define DELETE_CRITICAL_SECTION(x)
|
|
#define ENTER_CRITICAL_SECTION(x)
|
|
#define LEAVE_CRITICAL_SECTION(x)
|
|
|
|
#define DECL_DEBUG_MUTEX(x)
|
|
#define INIT_DEBUG_MUTEX(x)
|
|
#define DELETE_DEBUG_MUTEX(x)
|
|
#define ACQUIRE_DEBUG_MUTEX_READ(x)
|
|
#define RELEASE_DEBUG_MUTEX_READ(x)
|
|
#define ACQUIRE_DEBUG_MUTEX_WRITE(x)
|
|
#define RELEASE_DEBUG_MUTEX_WRITE(x)
|
|
|
|
#endif // _WIN32
|
|
|
|
} // iSTD
|