📄 thread.h
字号:
status = CRYPT_ERROR; \
else \
rtems_semaphore_release( sync ); \
rtems_semaphore_delete( sync )
#define THREAD_CLOSE( sync )
/* The RTEMS thread-self function returns the task ID via a reference
parameter, because of this we have to provide a wrapper that returns it
as a return value */
rtems_id threadSelf( void );
/****************************************************************************
* *
* ThreadX *
* *
****************************************************************************/
#elif defined( __ThreadX__ )
/* To use resource-management wrappers for the ThreadX thread functions,
undefine the following */
/* #define THREADX_THREAD_WRAPPERS */
#include <tx_api.h>
/* Object handles */
#define THREAD_HANDLE TX_THREAD
#define MUTEX_HANDLE TX_MUTEX
/* Mutex management functions. ThreadX mutexes are reentrant so we don't
have to hand-assemble reentrant mutexes as for many other OSes. All
ThreadX objects have names (presumably for debugging) but what the
requirements for these are aren't documented so we just use a dummy name
for everything. Since we don't care whether the threads waiting on the
mutex get woken up in priority order, we use TX_NO_INHERIT to ignore
priority inheritance */
#define MUTEX_DECLARE_STORAGE( name ) \
TX_MUTEX name##Mutex; \
BOOLEAN name##MutexInitialised
#define MUTEX_CREATE( name, status ) \
status = CRYPT_OK; \
if( !krnlData->name##MutexInitialised ) \
{ \
if( tx_mutex_create( &krnlData->name##Mutex, "name", \
TX_NO_INHERIT ) == TX_SUCCESS ) \
krnlData->name##MutexInitialised = TRUE; \
else \
status = CRYPT_ERROR; \
}
#define MUTEX_DESTROY( name ) \
if( krnlData->name##MutexInitialised ) \
{ \
tx_mutex_get( &krnlData->name##Mutex, TX_WAIT_FOREVER ); \
tx_mutex_put( &krnlData->name##Mutex ); \
tx_mutex_delete( &krnlData->name##Mutex ); \
krnlData->name##MutexInitialised = FALSE; \
}
#define MUTEX_LOCK( name ) \
tx_mutex_get( &krnlData->name##Mutex, TX_WAIT_FOREVER )
#define MUTEX_UNLOCK( name ) \
tx_mutex_put( &krnlData->name##Mutex )
/* Thread management functions. ThreadX threads require that the user
allocate the stack space for them, unlike virtually every other embedded
OS, which make this at most a rarely-used option. To handle this, we use
our own wrappers.
We give the thread a mid-range priority value and preemption threshold of
15 (from a range of 0 = highest ... 31 = lowest) and a 50-tick timeslice.
The timeslice value is HAL-dependent so it's not really possible to tell
how much runtime this will actually give the thread, anyone using cryptlib
with ThreadX will need to set an appropriate value for their HAL. The
same goes for the sleep time, the code assumes that 1 tick = 10ms so we
divide by 10 to convert ms to ticks */
#define THREADFUNC_DEFINE( name, arg ) VOID name( ULONG arg )
#define THREAD_CREATE( function, arg, threadHandle, syncHandle, status ) \
{ \
BYTE *threadData = malloc( 16384 ); \
\
tx_semaphore_create( &syncHandle, "name", 1 ); \
if( tx_thread_create( &threadHandle, "name", function, \
( ULONG ) arg, threadData, 16384, \
15, 50, 15, TX_AUTO_START ) != TX_SUCCESS ) \
{ \
free( threadData ); \
status = CRYPT_ERROR; \
} \
else \
status = CRYPT_OK; \
}
#define THREAD_EXIT( sync ) tx_semaphore_put( &sync ); \
tx_thread_terminate( tx_thread_identify() )
#define THREAD_INITIALISER 0
#define THREAD_SAME( thread1, thread2 ) ( ( thread1 ) == ( thread2 ) )
#define THREAD_SELF() tx_thread_identify()
#define THREAD_SLEEP( ms ) tx_thread_sleep( ( ms ) / 10 )
#define THREAD_YIELD() tx_thread_relinquish()
#define THREAD_WAIT( sync, status ) \
if( !tx_semaphore_get( &sync, TX_WAIT_FOREVER ) ) \
status = CRYPT_ERROR; \
tx_semaphore_delete( &sync )
#define THREAD_CLOSE( sync ) tx_thread_delete( &sync )
/* Because of the problems with resource management of ThreadX threads and
related metadata we no-op them out unless we're using wrappers by
ensuring that any attempt to spawn a thread inside cryptlib fails,
falling back to the non-threaded alternative. Note that cryptlib itself
is still thread-safe, it just can't do its init or keygen in an internal
background thread */
#ifndef THREADX_THREAD_WRAPPERS
#undef THREAD_CREATE
#undef THREAD_EXIT
#undef THREAD_CLOSE
#define THREAD_CREATE( function, arg, threadHandle, syncHandle, status ) \
status = CRYPT_ERROR
#define THREAD_EXIT( sync )
#define THREAD_CLOSE( sync )
#endif /* !THREADX_THREAD_WRAPPERS */
/****************************************************************************
* *
* Unix/MVS/XMK *
* *
****************************************************************************/
#elif ( defined( __UNIX__ ) || defined( __XMK__ ) ) && defined( USE_THREADS )
/* Under OSF/1 pthread.h includes c_asm.h which contains a declaration
long asm( const char *,...);
that conflicts with the gcc asm keyword. This asm stuff is only used
when inline asm alternatives to the Posix threading functions are enabled,
which isn't done by default so in theory we could also fix this by
defining asm to something else before including pthread.h, but it's safer
to just disable inclusion of c_asm.h by pre-defining the guard define.
This will result in a more useful warning if for some reason inline
threading functions with asm are enabled */
#if defined( __osf__ ) || defined( __alpha__ )
#define __C_ASM_H
#endif /* Alpha */
/* Linux threads are a particularly peculiar implementation, being based on
the Linux clone() system call, which clones an entire process and uses
a special "manager thread" to provide the appearance of a multithreaded
application. This threads == processes model produces very strange
effects such as the appearance of a mass of (pseudo-)processes, each with
their own PID, that appear to consume more memory than is physically
present. Another problem was that signals, which are done on a per-PID
basis and should have been consistent across all threads in the process,
were instead only delivered to one thread/pseudo-process and never got
any further. The clone()-based hack results in non-conformance with the
pthreads spec as well as significant scalability and performance issues.
The problem was finally (mostly) fixed with Ingo Molnar's native Posix
thread library (NPTL) patches to the 2.5 development) kernel, which
still retains the strange clone()-based threading mechanism but provides
enough kludges to other parts of the kernel that it's not longer so
obvious. For example the clone() call has been optimised to make it
more lightweight, Molnar's O(1) scheduler reduces the overhead of the
process-per-thread mechanism, fast userspace mutexes eliminate the need
for interthread signalling to implement locking, and most importantly the
kernel identification of all threads has been collapsed to a single PID,
eliminating the confusion caused by the cloned pseudo-processes */
#include <pthread.h>
#include <sys/time.h>
#ifdef __XMK__
#include <sys/process.h>
#include <sys/timer.h>
#endif /* Xilinx XMK */
/* Object handles */
#define THREAD_HANDLE pthread_t
#define MUTEX_HANDLE pthread_t
/* Mutex management functions. Most Unix mutex implementations are non-
re-entrant, which means that re-locking a mutex leads to deadlock
(charming). Some implementations can fix this by setting a mutex
attribute to ensure that it doesn't deadlock using:
pthread_mutexattr_settype( attr, PTHREAD_MUTEX_RECURSIVE );
or:
pthread_mutex_setrecursive();
but this isn't universal. To fix the problem, we implement our own
re-entrant mutexes on top of the Posix ones.
Due to the complexity of the locking process using pthreads' (usually)
non-reentrant mutexes, we don't try and lock+unlock the mutex before we
destroy it. This isn't a major issue since it's just a safety precaution,
the kernel should have forced any remaining threads to exit by the time
the shutdown occurs anyway */
#define MUTEX_DECLARE_STORAGE( name ) \
pthread_mutex_t name##Mutex; \
BOOLEAN name##MutexInitialised; \
pthread_t name##MutexOwner; \
int name##MutexLockcount
#define MUTEX_CREATE( name, status ) \
status = CRYPT_OK; \
if( !krnlData->name##MutexInitialised ) \
{ \
if( pthread_mutex_init( &krnlData->name##Mutex, \
NULL ) == 0 ) \
krnlData->name##MutexInitialised = TRUE; \
else \
status = CRYPT_ERROR; \
}
#define MUTEX_DESTROY( name ) \
if( krnlData->name##MutexInitialised ) \
{ \
pthread_mutex_destroy( &krnlData->name##Mutex ); \
krnlData->name##MutexInitialised = FALSE; \
}
#define MUTEX_LOCK( name ) \
if( pthread_mutex_trylock( &krnlData->name##Mutex ) ) \
{ \
if( !THREAD_SAME( krnlData->name##MutexOwner, THREAD_SELF() ) ) \
pthread_mutex_lock( &krnlData->name##Mutex ); \
else \
krnlData->name##MutexLockcount++; \
} \
krnlData->name##MutexOwner = THREAD_SELF();
#define MUTEX_UNLOCK( name ) \
if( krnlData->name##MutexLockcount > 0 ) \
krnlData->name##MutexLockcount--; \
else \
{ \
krnlData->name##MutexOwner = THREAD_INITIALISER; \
pthread_mutex_unlock( &krnlData->name##Mutex ); \
}
/* Instead of the DIY recursive mutexes above it's also possible to use OS
recursive mutexes if they're available. Unfortunately there's no easy
way to reliably test for these (they're often provided as _NP variants,
or require obscure preprocessor trickery to enable them), and even if
they're present they may not be supported (pthread_mutexattr_settype()
returns an error), or the implementation may be flaky (some Linux
threading implementations). Because of this the following use of
recursive mutexes needs to be manually enabled. Note that on most
systems that use gcc it's necessary to define either _XOPEN_SOURCE=500 or
_GNU_SOURCE to get PTHREAD_MUTEX_RECURSIVE, otherwise only
PTHREAD_MUTEX_RECURSIVE_NP is defined, i.e. the standard behaviour of gcc
is to be nonstandard */
#if 0
#undef MUTEX_CREATE
#undef MUTEX_LOCK
#undef MUTEX_UNLOCK
#define MUTEX_CREATE( name, status ) \
if( !krnlData->name##MutexInitialised ) \
{ \
pthread_mutexattr_t mutexAttr;\
\
pthread_mutexattr_init( &mutexAttr );\
pthread_mutexattr_settype( &mutexAttr, \
PTHREAD_MUTEX_RECURSIVE ); \
if( pthread_mutex_init( &krnlData->name##Mutex, \
&mutexAttr ) == 0 ) \
{ \
krnlData->name##MutexInitialised = TRUE; \
status = CRYPT_OK; \
} \
else \
status = CRYPT_ERROR; \
pthread_mutexattr_destroy ( &mutexAttr );\
}
#define MUTEX_LOCK( name ) pthread_mutex_lock( &krnlData->name##Mutex )
#define MUTEX_UNLOCK( name ) pthread_mutex_unlock( &krnlData->name##Mutex )
#endif /* 0 */
/* Putting a thread to sleep for a number of milliseconds can be done with
select() because it should be a thread-safe one in the presence of
pthreads. In addition there are some system-specific quirks, these are
handled by re-defining the macros below in a system-specific manner
further on.
Yielding a thread's timeslice gets rather complex due to a confusion of
non-portable "portable" Posix functions. Initially there was
pthread_yield() from draft 4 of the Posix thread standard in 1990,
popularised in the DCE threading code and picked up by a number of other
implementations. At about that time the realtime (1003.1b) and thread
(1003.1c) standardisation was proceeding independently, with neither side
knowing which one would make it to standards status first. As it turned
out this was 1003.1b with sched_yield(). When the 1003.1c folks were
looking for every place where the text said "process" but should say
"thread" once 1003.1c was in effect, they noticed that sched_yield() and
pthread_yield() were now identical. Since sched_yield() was already in
the standard, there was no need for pthread_yield() so it was removed.
However, some older implementations still do pthread_yield() and some
(also older) implementations use sched_yield() to yield the processes'
timeslice rather than the thread's timeslice, further complicated by the
fact that some implementations like PHUX 10.x/11.x have buggy manpages
that claim sched_yield() is per-process when in fact it's per-thread
(PHUX 10.x still had pthread_yield() while 11.x only has sched_yield()).
The whole is further confused by the fact that in some implementations,
threads are processes (sort of, e.g. Linux's clone()'d threads and Sun
LWPs). In addition Sun have their own thr_yield which is part of their
UI threads interface and that you have to fall back to occasionally.
Because of this mess, we try for pthread_yield() if possible (since that
definitely yields the thread's timeslice), fall back to sched_yield() if
necessary, and add a special workaround for Sun systems.
"Posix is portable in the sense that you can use a forklift to move the
printed volumes around" */
#define THREADFUNC_DEFINE( name, arg ) void *name( void *arg )
#define THREAD_CREATE( function, arg, threadHandle, syncHandle, status ) \
{ \
status = pthread_create( &threadHandle, NULL, function, arg ) ? \
CRYPT_ERROR : CRYPT_OK; \
syncHandle = threadHandle; \
}
#define THREAD_EXIT( sync ) pthread_exit( ( void * ) 0 )
#define THREAD_INITIALISER 0
#define THREAD_SELF() pthread_self()
#define THREAD_SAME( thread1, thread2 ) pthread_equal( ( thread1 ), ( thread2 ) )
#if defined( __osf__ ) || defined( __alpha__ ) || defined( __APPLE__ )
#define THREAD_YIELD() pthread_yield_np()
#elif defined( __MVS__ )
#define THREAD_YIELD() pthread_yield( NULL )
#elif defined( sun )
#if OSVERSION <= 6
/* Older Slowaris gets a bit complex, SunOS 4.x always
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -