📄 thread.h
字号:
the UI interface if necessary */
#define THREAD_YIELD() { if( sched_yield() ) thr_yield(); }
#elif defined( _AIX ) || ( defined( __hpux ) && ( OSVERSION >= 11 ) ) || \
defined( __NetBSD__ ) || defined( __QNX__ )
#define THREAD_YIELD() sched_yield()
#elif defined( __XMK__ )
/* The XMK underlying scheduling object is the process context, for which
the user-visible interface is the thread. Therefore yielding the
underlying process context should yield the associated thread */
#define THREAD_YIELD() yield()
#else
#define THREAD_YIELD() pthread_yield()
#endif /* Not-very-portable Posix portability */
#define THREAD_SLEEP( ms ) { \
struct timeval tv = { 0 }; \
\
tv.tv_usec = ( ms ) * 1000; \
select( 1, NULL, NULL, NULL, &tv ); \
}
#define THREAD_WAIT( sync ) pthread_join( sync, NULL )
#define THREAD_CLOSE( sync )
/* OSF1 includes some ghastly kludgery to handle binary compatibility from
1003.4a to 1003.1c threading functions and inline asm functions with all
sorts of name mangling and translation of function names and types.
Unfortunately a straight vanilla compile leaves pthread_self() un-
prototyped, which means that it's then implicitly prototyped as returned
an int. This generates hundreds of warnings of int <-> pointer casting
problems, so if pthread_self() isn't redefined into one of a dozen
different mangled versions we prototype it ourselves here */
#if ( defined( __osf__ ) || defined( __alpha__ ) ) && \
!defined( pthread_self )
#ifdef _PTHREAD_USE_MANGLED_NAMES_
#define pthread_self __pthread_self
#endif /* Name mangling */
extern pthread_t pthread_self( void );
#endif /* OSF1 pthread_self function prototyping bug */
/* The pthreads implementation on MP-RAS (NCR User Space Threads based on
CMA threads for DCE) doesn't accept NULL for several of the attribute
arguments so we have to supply pthread_mutexattr_default attributes */
#ifdef _MPRAS
#undef MUTEX_CREATE
#define MUTEX_CREATE( name ) \
if( !krnlData->name##MutexInitialised ) \
{ \
pthread_mutex_init( &krnlData->name##Mutex, \
pthread_mutexattr_default ); \
krnlData->name##MutexInitialised = TRUE; \
}
#undef THREAD_CREATE
#define THREAD_CREATE( function, arg, threadHandle, syncHandle, status ) \
{ \
status = pthread_create( &threadHandle, pthread_attr_default, \
function, arg ) ? \
CRYPT_ERROR : CRYPT_OK ); \
syncHandle = ( long ) threadHandle; \
}
#endif /* _MPRAS */
/* Some systems (notably MVS and MP-RAS) use non-scalar pthread_t's, so we
have to handle initialisation of these specially */
#if defined( __MVS__ ) || defined( _MPRAS )
#define NONSCALAR_THREADS
#undef THREAD_INITIALISER
#define THREAD_INITIALISER { 0 }
#endif /* Non-scalar pthread_t's */
/* XMK doesn't have a select(), however it has a sleep() as part of the timer
package that performs the same function. Note that there's a second
sleep() that takes an argument in seconds rather than ms and that sleeps
the overall process in the PPC BSP library, but presumably this won't be
used if the sleep() in the timer package is enabled */
#ifdef __XMK__
#undef THREAD_SLEEP
#define THREAD_SLEEP( ms ) sleep( ms )
#endif /* Xilinx XMK */
/* UnixWare/SCO creates threads with a ridiculously small default stack size
of a few KB or so, which means that the thread can't even start. To work
around this we have to use a custom thread-creation function that sets
the stack size to something reasonable */
#ifdef __SCO_VERSION__
#undef THREAD_CREATE
#define THREAD_CREATE( function, arg, threadHandle, syncHandle, status ) \
{ \
pthread_attr_t attr; \
\
pthread_attr_init( &attr ); \
pthread_attr_setstacksize( &attr, 32768 ); \
status = pthread_create( &threadHandle, &attr, function, arg ); \
pthread_attr_destroy( &attr ); \
if( status ) \
status = CRYPT_ERROR; \
else \
{ \
status = CRYPT_OK; \
syncHandle = ( long ) threadHandle; \
} \
}
#endif /* UnixWare/SCO */
/****************************************************************************
* *
* VxWorks *
* *
****************************************************************************/
#elif defined( __VXWORKS__ )
#include <vxWorks.h>
#include <semLib.h>
#include <taskLib.h>
/* Object handles */
#define THREAD_HANDLE int
#define MUTEX_HANDLE SEM_ID
/* Mutex management functions. VxWorks mutual exclusion semaphores (and
only mutex semaphores) are re-entrant, so we don't have to jump through
the hoops that are necessary with most other OSes */
#define MUTEX_DECLARE_STORAGE( name ) \
SEM_ID name##Mutex; \
BOOLEAN name##MutexInitialised
#define MUTEX_CREATE( name ) \
if( !krnlData->name##MutexInitialised ) \
{ \
krnlData->name##Mutex = semMCreate( SEM_Q_FIFO ); \
krnlData->name##MutexInitialised = TRUE; \
}
#define MUTEX_DESTROY( name ) \
if( krnlData->name##MutexInitialised ) \
{ \
semTake( krnlData->name##Mutex, WAIT_FOREVER ); \
semGive( krnlData->name##Mutex ); \
semDelete( krnlData->name##Mutex ); \
krnlData->name##MutexInitialised = FALSE; \
}
#define MUTEX_LOCK( name ) \
semTake( krnlData->name##Mutex, WAIT_FOREVER ); \
#define MUTEX_UNLOCK( name ) \
semGive( krnlData->name##Mutex );
/* Thread management functions. Some PPC compilers use the FP registers for
non-FP operations such as working with long long data types (used for
example in PKC key generation), so if we're building for the PPC we
create tasks with FP register saving enabled */
#ifdef __ppc__
#define TASK_ATTRIBUTES VX_FP_TASK
#else
#define TASK_ATTRIBUTES 0
#endif /* PPC vs.non-PPC register saves */
/* VxWorks tasks are exited using the standard ANSI exit() function rather
than any OS-specific exit mechanism.
Task sleep times are measured in implementation-specific ticks rather
than ms, but it's usually close enough to allow us to treat them as being
identical. If we need truly accurate timing we could call a helper
function that scales the time based on sysClkRateGet(), but at the moment
it's only used for general short delays rather than any fixed amount of
time so this isn't necessary */
#define THREADFUNC_DEFINE( name, arg ) thread_id name( void *arg )
#define THREAD_CREATE( function, arg, threadHandle, syncHandle, status ) \
{ \
syncHandle = semBCreate( SEM_Q_FIFO, SEM_EMPTY ); \
threadHandle = taskSpawn( NULL, T_PRIORITY, TASK_ATTRIBUTES, 16384, \
function, ( int ) arg, 0, 0, 0, 0, \
0, 0, 0, 0, 0 ); \
if( threadHandle == ERROR ) \
{ \
semDelete( syncHandle ); \
status = CRYPT_ERROR; \
} \
else \
status = CRYPT_OK; \
}
#define THREAD_EXIT( sync ) semGive( sync ); \
exit( 0 )
#define THREAD_INITIALISER 0
#define THREAD_SAME( thread1, thread2 ) ( ( thread1 ) == ( thread2 ) )
#define THREAD_SELF() taskIdSelf()
#define THREAD_SLEEP( ms ) taskDelay( ms )
#define THREAD_YIELD() taskDelay( NO_WAIT )
#define THREAD_WAIT( sync ) semTake( sync, WAIT_FOREVER ); \
semGive( sync ); \
semDelete( sync )
#define THREAD_CLOSE( sync )
/****************************************************************************
* *
* Win32/WinCE *
* *
****************************************************************************/
#elif ( defined( __WIN32__ ) && !defined( NT_DRIVER ) ) || \
defined( __WINCE__ )
#ifndef __WINCE__
#include <process.h>
#endif /* __WINCE__ */
/* Object handles */
#define THREAD_HANDLE HANDLE
#define MUTEX_HANDLE HANDLE
/* Mutex management functions. InitializeCriticalSection() doesn't return
an error code but can throw a STATUS_NO_MEMORY exception in certain low-
memory situations, however this exception isn't raised in an exception-
safe manner (the critical section object is left in a corrupted state) so
it can't be safely caught and recovered from. The result is that there's
no point in trying to catch it (this is a known design flaw in the
function) */
#define MUTEX_DECLARE_STORAGE( name ) \
CRITICAL_SECTION name##CriticalSection; \
BOOLEAN name##CriticalSectionInitialised
#define MUTEX_CREATE( name ) \
if( !krnlData->name##CriticalSectionInitialised ) \
{ \
InitializeCriticalSection( &krnlData->name##CriticalSection ); \
krnlData->name##CriticalSectionInitialised = TRUE; \
}
#define MUTEX_DESTROY( name ) \
if( krnlData->name##CriticalSectionInitialised ) \
{ \
EnterCriticalSection( &krnlData->name##CriticalSection ); \
LeaveCriticalSection( &krnlData->name##CriticalSection ); \
DeleteCriticalSection( &krnlData->name##CriticalSection ); \
krnlData->name##CriticalSectionInitialised = FALSE; \
}
#define MUTEX_LOCK( name ) \
EnterCriticalSection( &krnlData->name##CriticalSection )
#define MUTEX_UNLOCK( name ) \
LeaveCriticalSection( &krnlData->name##CriticalSection )
/* Thread management functions. Win32 requires a C library-aware wrapper
around the OS native CreateThread()/ExitThread() calls, with WinCE
after 2.0 the C runtime is integrated into the OS so we can call them
directly.
There are two functions that we can call to get the current thread ID,
GetCurrentThread() and GetCurrentThreadId(). These are actually
implemented as the same function (once you get past the outer wrapper),
and the times for calling either are identical. The only difference
between the two is that GetCurrentThread() returns a per-process
pseudohandle while GetCurrentThreadId() returns a systemwide, unique
handle.
An alternative to Sleep( 0 ) is SwitchToThread(), however this is only
available under the NT code base for NT 4.0 and later, so it wouldn't
work under the Win95 code base.
After we wait for the thread, we need to close the handle. This is
complicated by the fact that we can only close it once all threads have
exited the wait, which requires further calisthenics in the function that
uses it to ensure that the last thread out closes the handle. This also
means that we can't combine the close with the wait as for other OSes,
since we can only perform the close once all waits have exited */
#if defined( __WIN32__ )
#define THREADFUNC_DEFINE( name, arg ) \
unsigned __stdcall name( void *arg )
#define THREAD_CREATE( function, arg, threadHandle, syncHandle, status ) \
{ \
ULONG ulDummy; \
\
threadHandle = ( HANDLE ) \
_beginthreadex( NULL, 0, ( function ), ( arg ), 0, &ulDummy ); \
syncHandle = ( long ) threadHandle; \
status = !threadHandle ? CRYPT_ERROR : CRYPT_OK; \
}
#define THREAD_EXIT( sync ) _endthreadex( 0 ); return( 0 )
#elif defined( __WINCE__ )
#define THREADFUNC_DEFINE( name, arg ) \
DWORD WINAPI name( void *arg )
#define THREAD_CREATE( function, arg, threadHandle, syncHandle, status ) \
{ \
ULONG ulDummy; \
\
threadHandle = ( HANDLE ) \
CreateThread( NULL, 0, ( function ), ( arg ), 0, &ulDummy ); \
syncHandle = ( long ) threadHandle; \
status = !threadHandle ? CRYPT_ERROR : CRYPT_OK; \
}
#define THREAD_EXIT( sync ) ExitThread( 0 ); return( 0 )
#endif /* Win32 vs. WinCE */
#define THREAD_INITIALISER 0
#define THREAD_SELF() ( THREAD_HANDLE ) GetCurrentThreadId()
#define THREAD_SAME( thread1, thread2 ) ( ( thread1 ) == ( thread2 ) )
#define THREAD_SLEEP( ms ) Sleep( ms )
#define THREAD_YIELD() Sleep( 0 )
#define THREAD_WAIT( sync ) WaitForSingleObject( sync, INFINITE );
#define THREAD_CLOSE( sync ) CloseHandle( sync )
#elif defined( __WIN32__ ) && defined( NT_DRIVER )
/* Object handles */
#define THREAD_HANDLE HANDLE
#define MUTEX_HANDLE HANDLE
/* Mutex management functions */
#define MUTEX_DECLARE_STORAGE( name ) \
KMUTEX name##CriticalSection; \
BOOLEAN name##CriticalSectionInitialised
#define MUTEX_CREATE( name ) \
if( !krnlData->name##CriticalSectionInitialised ) \
{ \
KeInitializeMutex( &krnlData->name##CriticalSection, 1 ); \
krnlData->name##CriticalSectionInitialised = TRUE; \
}
#define MUTEX_DESTROY( name )
#define MUTEX_LOCK( name ) \
KeWaitForMutexObject( &krnlData->name##CriticalSection, Executive, \
KernelMode, FALSE, NULL )
#define MUTEX_UNLOCK( name ) \
KeReleaseMutex( &krnlData->name##CriticalSection, FALSE )
/****************************************************************************
* *
* Non-thr
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -