📄 thread.h
字号:
#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 ) \
if( !krnlData->name##MutexInitialised ) \
{ \
mutexInit( &krnlData->name##Mutex ); \
krnlData->name##MutexInitialised = TRUE; \
}
#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 \
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 ) semP( sync, K_NOTIMEOUT )
#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 ) \
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 \
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 ) cyg_semaphore_wait( &sync ); \
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 */
/****************************************************************************
* *
* uC/OS-II *
* *
****************************************************************************/
#elif defined( __UCOS__ )
/* uC/OS-II has a pure priority-based scheduler (no round-robin scheduling)
and makes a task's priority do double duty as the task ID, which means
that it's unlikely it'll ever get round-robin scheduling without a
major overhaul of the API. Because of this, a background task started
inside cryptlib for initialisation or keygen will either never run or
always run depending on the priority it's started with, thus making it
equivalent to performing the operation synchronously. This means that
there's no point in using cryptlib-internal tasks, so they're disabled
unless the following is commented out. Note that cryptlib is still
thread-(task)-safe, it just won't use internal tasks for asynchronous
ops, because uC/OS-II's scheduling will make the synchronous */
/* #define UCOS_USE_TASKS */
/* Most systems handle priority-inversion-avoidance automatically, however
for some reason in uC/OS-II this has to be managed manually by the user.
This is done by specifying the priority-inherit priority level that a
low-priority task is raised to when a high-priority task attempts to
acquire a mutex that the low-priority task is currently holding. This
has to be higher than the priority of any of the tasks that will try
to acquire the mutex, as well as being different from the task ID/
priority of any task (another problem caused by the task ID == priority
issue). The following is a sample value that'll need to be adjusted
based on usage by the calling application */
#define UCOS_PIP 10
/* Because of the strict priority scheduling, we have to specify the task
priority (which then also becomes the task ID) when we create the task.
The following is a sample task ID, which must be less than UCOS_PIP */
#define UCOS_TASKID 20
#include <includes.h>
/* Object handles */
#define THREAD_HANDLE INT8U
#define MUTEX_HANDLE OS_EVENT *
/* Mutex management functions. uC/OS-II mutexes aren't re-entrant (although
this is never mentioned explicitly in any documentation, the description
of how mutexes work in App.Note 1002 makes it clear that they're not), we
use the standard trylock()-style mechanism to work around this */
#define MUTEX_DECLARE_STORAGE( name ) \
OS_EVENT *name##Mutex; \
BOOLEAN name##MutexInitialised; \
INT8U name##MutexOwner; \
int name##MutexLockcount
#define MUTEX_CREATE( name ) \
if( !krnlData->name##MutexInitialised ) \
{ \
INT8U err; \
\
krnlData->name##Mutex = OSMutexCreate( UCOS_PIP, &err ); \
krnlData->name##MutexInitialised = TRUE; \
}
#define MUTEX_DESTROY( name ) \
if( krnlData->name##MutexInitialised ) \
{ \
INT8U err; \
\
OSMutexPend( krnlData->name##Mutex, 0, &err ); \
OSMutexPost( krnlData->name##Mutex ); \
OSMutexDel( krnlData->name##Mutex, OS_DEL_ALWAYS, &err ); \
krnlData->name##MutexInitialised = FALSE; \
}
#define MUTEX_LOCK( name ) \
{ \
INT8U err; \
\
if( OSMutexAcept( krnlData->name##Mutex, &err ) == 0 ) \
{ \
if( !THREAD_SAME( krnlData->name##MutexOwner, THREAD_SELF() ) ) \
OSMutexPend( krnlData->name##Mutex, 0, &err ); \
else \
krnlData->name##MutexLockcount++; \
} \
krnlData->name##MutexOwner = THREAD_SELF();
#define MUTEX_UNLOCK( name ) \
if( krnlData->name##MutexLockcount > 0 ) \
krnlData->name##MutexLockcount--; \
else \
OSMutexPost( krnlData->name##Mutex );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -