📄 thread.h
字号:
/* Thread management functions. BeOS threads are created in the suspended
state, so after we create the thread we have to resume it to start it
running */
#define THREADFUNC_DEFINE( name, arg ) thread_id name( void *arg )
#define THREAD_CREATE( function, arg, threadHandle, syncHandle, status ) \
{ \
threadHandle = syncHandle = \
spawn_thread( ( function ), NULL, B_NORMAL_PRIORITY, \
( arg ) ); \
if( threadHandle < B_NO_ERROR ) \
status = CRYPT_ERROR; \
else \
resume_thread( threadHandle ); \
}
#define THREAD_EXIT( sync ) exit_thread( 0 )
#define THREAD_INITIALISER 0
#define THREAD_SAME( thread1, thread2 ) ( ( thread1 ) == ( thread2 ) )
#define THREAD_SELF() find_thread( NULL )
#define THREAD_SLEEP( ms ) snooze( ms )
#define THREAD_YIELD() snooze( estimate_max_scheduling_latency( -1 ) + 1 )
#define THREAD_WAIT( sync, status ) \
{ \
status_t dummy; \
\
if( wait_for_thread( sync, &dummy ) != B_NO_ERROR.) \
status = CRYPT_ERROR; \
}
#define THREAD_CLOSE( sync )
/****************************************************************************
* *
* ChorusOS *
* *
****************************************************************************/
#elif defined( __CHORUS__ )
/* To use resource-management wrappers for the AMX thread functions,
undefine the following */
/* #define AMX_THREAD_WRAPPERS */
#include <chorus.h>
#include <exec/chExec.h>
/* Object handles */
#define THREAD_HANDLE KnThreadLid
#define MUTEX_HANDLE KnMutex
/* Mutex management functions. ChorusOS provides no way to destroy a
mutex once it's initialised, presumably it gets cleaned up when the
owning actor terminates */
#define MUTEX_DECLARE_STORAGE( name ) \
KnMutex name##Mutex; \
BOOLEAN name##MutexInitialised; \
KnThreadLid name##MutexOwner; \
int name##MutexLockcount
#define MUTEX_CREATE( name, status ) \
status = CRYPT_OK; \
if( !krnlData->name##MutexInitialised ) \
{ \
if( mutexInit( &krnlData->name##Mutex ) == K_OK ) \
krnlData->name##MutexInitialised = TRUE; \
else \
status = CRYPT_ERROR; \
}
#define MUTEX_DESTROY( name ) \
if( krnlData->name##MutexInitialised ) \
{ \
mutexGet( &krnlData->name##Mutex ); \
mutexRel( &krnlData->name##Mutex ); \
krnlData->name##MutexInitialised = FALSE; \
}
#define MUTEX_LOCK( name ) \
if( mutexTry( &krnlData->name##Mutex ) == 0 ) \
{ \
if( !THREAD_SAME( krnlData->name##MutexOwner, THREAD_SELF() ) ) \
mutexGet( &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; \
mutexRel( &krnlData->name##Mutex ); \
}
/* Thread management functions. ChorusOS 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 which hide this mess. A second problem with ChorusOS
threads is that there's no easy way to pass an argument to a thread, so
we have to include it as a "software register" value that the thread then
obtains via threadLoadR().
The 4096 byte storage area provides enough space for about half a dozen
levels of function nesting (if no large on-stack arrays are used), this
should be enough for background init but probably won't be sufficient for
the infinitely-recursive OpenSSL bignum code, so the value may need to be
adjusted if background keygen is being used.
ChorusOS provides no way to destroy a semaphore once it's initialised,
presumably it gets cleaned up when the owning actor terminates */
#define THREADFUNC_DEFINE( name, arg ) void name( void )
#define THREAD_CREATE( function, arg, threadHandle, syncHandle, status ) \
{ \
BYTE *threadStack = malloc( 4096 ); \
KnDefaultStartInfo startInfo = { \
K_START_INFO | K_START_INFO_SOFTREG, K_DEFAULT_STACK_SIZE, \
function, threadStack, K_USERTHREAD, arg }; \
\
semInit( &syncHandle, 1 ); \
if( threadCreate( K_MYACTOR, &threadHandle, K_ACTIVE, NULL,
&startInfo ) != K_OK ) \
{ \
free( threadStack ); \
status = CRYPT_ERROR; \
} \
else \
status = CRYPT_OK; \
}
#define THREAD_EXIT( sync ) semV( sync ); \
threadDelete( K_MYACTOR, K_MYSELF )
#define THREAD_INITIALISER NULL
#define THREAD_SAME( thread1, thread2 ) ( ( thread1 ) == ( thread2 ) )
#define THREAD_SELF() threadSelf()
#define THREAD_SLEEP( ms ) { \
KnTimeVal timeVal; \
\
K_MILLI_TO_TIMEVAL( &timeVal, ms ); \
threadDelay( &timeVal ); \
}
#define THREAD_YIELD() threadDelay( K_NOBLOCK )
#define THREAD_WAIT( sync, status ) \
if( semP( sync, K_NOTIMEOUT ) < 0 ) \
status = CRYPT_ERROR
#define THREAD_CLOSE( sync )
/* Because of the problems with resource management of Chorus thread stack
space, we no-op out threads 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 CHORUS_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 /* !CHORUS_THREAD_WRAPPERS */
/****************************************************************************
* *
* eCOS *
* *
****************************************************************************/
#elif defined( __ECOS__ )
/* To use resource-management wrappers for the eCOS thread functions,
undefine the following */
/* #define ECOS_THREAD_WRAPPERS */
#include <cyg/hal/hal_arch.h>
#include <cyg/kernel/kapi.h>
/* Object handles */
#define THREAD_HANDLE cyg_handle_t
#define MUTEX_HANDLE cyg_sem_t
/* Mutex management functions */
#define MUTEX_DECLARE_STORAGE( name ) \
cyg_mutex_t name##Mutex; \
BOOLEAN name##MutexInitialised; \
cyg_handle_t name##MutexOwner; \
int name##MutexLockcount
#define MUTEX_CREATE( name, status ) \
status = CRYPT_OK; /* Apparently never fails */ \
if( !krnlData->name##MutexInitialised ) \
{ \
cyg_mutex_init( &krnlData->name##Mutex ); \
krnlData->name##MutexInitialised = TRUE; \
}
#define MUTEX_DESTROY( name ) \
if( krnlData->name##MutexInitialised ) \
{ \
cyg_mutex_lock( &krnlData->name##Mutex ); \
cyg_mutex_unlock( &krnlData->name##Mutex ); \
cyg_mutex_destroy( &krnlData->name##Mutex ); \
krnlData->name##MutexInitialised = FALSE; \
}
#define MUTEX_LOCK( name ) \
if( cyg_mutex_trylock( &krnlData->name##Mutex ) ) \
{ \
if( !THREAD_SAME( krnlData->name##MutexOwner, THREAD_SELF() ) ) \
cyg_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; \
cyg_mutex_unlock( &krnlData->name##Mutex ); \
}
/* Thread management functions. eCOS 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, which hide this mess and provide access via a single scalar
variable. For synchronisation we use semaphores, eCOS also provides
condition variables for this purpose but they require a user-managed
mutex to synchronise access to them, making them (at best) a primitive
DIY semaphore.
We create the thread with the same priority as the calling thread, note
that this precludes the use of the bitmap scheduler (but not the lottery
scheduler). There doesn't seem to be any way to tell whether a thread
has been successfully created/started or not (!!), the best that we can
do is assume that if the thread handle is zero or negative then there's
been a problem. eCOS threads are created in the suspended state, so
after we create the thread we have to resume it to start it running.
The CYGNUM_HAL_STACK_SIZE_TYPICAL provides enough stack space for about
half a dozen levels of function nesting (if no large on-stack arrays are
used), this should be enough for background init but probably won't be
sufficient for the infinitely-recursive OpenSSL bignum code, so the value
may need to be adjusted if background keygen is being used.
Thread sleep times are measured in implementation-specific ticks rather
than ms, but the default is 100Hz so we divide by 10 to convert ms to
ticks */
#define THREADFUNC_DEFINE( name, arg ) void name( cyg_addrword_t arg )
#define THREAD_CREATE( function, arg, threadHandle, syncHandle, status ) \
{ \
BYTE *threadData = malloc( sizeof( cyg_thread ) + \
CYGNUM_HAL_STACK_SIZE_TYPICAL ); \
\
cyg_semaphore_init( &syncHandle, 0 ); \
cyg_thread_create( cyg_thread_get_priority( cyg_thread_self() ), \
function, ( cyg_addrword_t ) arg, NULL, \
threadData + sizeof( cyg_thread ), \
CYGNUM_HAL_STACK_SIZE_TYPICAL, \
&threadHandle, ( cyg_thread * ) threadData ); \
if( threadHandle <= 0 ) \
{ \
free( threadData ); \
status = CRYPT_ERROR; \
} \
else \
{ \
cyg_thread_resume( threadHandle ); \
status = CRYPT_OK; \
} \
}
#define THREAD_EXIT( sync ) cyg_semaphore_post( &sync ); \
cyg_thread_exit()
#define THREAD_INITIALISER 0
#define THREAD_SAME( thread1, thread2 ) ( ( thread1 ) == ( thread2 ) )
#define THREAD_SELF() cyg_thread_self()
#define THREAD_SLEEP( ms ) cyg_thread_delay( ( ms ) / 10 )
#define THREAD_YIELD() cyg_thread_yield()
#define THREAD_WAIT( sync, status ) \
if( !cyg_semaphore_wait( &sync ) ) \
status = CRYPT_ERROR; \
cyg_semaphore_destroy( &sync )
#define THREAD_CLOSE( sync ) cyg_thread_delete( &sync )
/* Because of the problems with resource management of eCOS 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 ECOS_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 /* !ECOS_THREAD_WRAPPERS */
/****************************************************************************
* *
* FreeRTOS/OpenRTOS *
* *
****************************************************************************/
#elif defined( __FreeRTOS__ )
#include <semphr.h>
#include <task.h>
/* Object handles */
#define THREAD_HANDLE xTaskHandle
#define MUTEX_HANDLE xSemaphoreHandle
/* Mutex management functions. Mutexes aren't recursive but binary
semaphores are so we use those instead of mutexes. In addition most of
the functions are implemented via macros rather than functions so we use
the handles directly instead of passing a reference. Finally, there's no
way to destroy/clean up a mutex after it's been created because the kernel
and code are linked into a single monolithic blob that's running the
entire time, so we don't perform any explicit cleanup */
#define MUTEX_WAIT_TIME ( 5000 / portTICK_RATE_MS )
#define MUTEX_DECLARE_STORAGE( name ) \
xSemaphoreHandle name##Mutex; \
BOOLEAN name##MutexInitialised
#define MUTEX_CREATE( name, status ) \
if( !krnlData->name##MutexInitialised ) \
{ \
vSemaphoreCreateBinary( krnlData->name##Mutex ); \
if( krnlData->name##Mutex == NULL ) \
status = CRYPT_ERROR; \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -