📄 thread.h
字号:
/* Thread management functions. Because of the strict priority-based
scheduling there's no way to perform a yield, the best that we can do
is sleep for 1ms, which is better than performing a busy wait.
Thread sleep times are measured in implementation-specific ticks rather
than ms, so we have to scale the time based on the OS_TICKS_PER_SEC
value */
#define THREADFUNC_DEFINE( name, arg ) void name( void *arg )
#define THREAD_CREATE( function, arg, threadHandle, syncHandle, status ) \
{ \
OS_STK *threadData = malloc( 4096 ); \
\
syncHandle = OSSemCreate( 0 ); \
if( OSTaskCreate( function, arg, ( BYTE * ) threadData + 4095, \
UCOS_TASKID ) != OS_NO_ERR ) \
{ \
free( threadData ); \
status = CRYPT_ERROR; \
} \
else \
status = CRYPT_OK; \
}
#define THREAD_EXIT( sync ) OSSemPost( sync ); \
OSTaskDel( OS_PRIO_SELF )
#define THREAD_INITIALISER 0
#define THREAD_SAME( thread1, thread2 ) ( ( thread1 ) == ( thread2 ) )
#define THREAD_SELF() threadSelf()
#if OS_TICKS_PER_SEC >= 1000
#define THREAD_SLEEP( ms ) OSTimeDelay( ( OS_TICKS_PER_SEC / 1000 ) * ms )
#else
#define THREAD_SLEEP( ms ) OSTimeDelay( max( ( ms * OS_TICKS_PER_SEC ) / 1000, 1 ) )
#endif /* OS_TICKS_PER_SEC time scaling */
#define THREAD_YIELD() THREAD_SLEEP( 1 )
#define THREAD_WAIT( sync ) { \
INT8U err; \
\
OSSemPend( sync, 0, &err ); \
OSSemDel( sync ); \
}
#define THREAD_CLOSE( sync )
/* uC/OS-II doesn't have a thread-self function, but allows general task
info to be queried. Because of this we provide a wrapper that returns
the task ID as its return value */
INT8U threadSelf( void );
/* Because of the inability to do round-robin scheduling, we no-opn out the
use of internal threads/tasks. Note that cryptlib itself is still thread-
safe, it just can't do its init or keygen in an internal background
thread */
#ifndef UCOS_USE_TASKS
#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 /* !UCOS_USE_TASKS */
/****************************************************************************
* *
* IBM 4758 *
* *
****************************************************************************/
#elif defined( __IBM4758__ )
#include <cpqlib.h>
/* Object handles */
#define THREAD_HANDLE long
#define MUTEX_HANDLE long
/* Mutex management functions */
#define MUTEX_DECLARE_STORAGE( name ) \
long name##Semaphore; \
BOOLEAN name##SemaphoreInitialised
#define MUTEX_CREATE( name ) \
if( !krnlData->name##SemaphoreInitialised ) \
{ \
CPCreateSerSem( NULL, 0, 0, &krnlData->name##Semaphore ); \
krnlData->name##SemaphoreInitialised = TRUE; \
}
#define MUTEX_DESTROY( name ) \
if( krnlData->name##SemaphoreInitialised ) \
{ \
CPSemClaim( krnlData->name##Semaphore, SVCWAITFOREVER ); \
CPSemRelease( krnlData->name##Semaphore ); \
CPDelete( krnlData->name##Semaphore, 0 ); \
krnlData->name##SemaphoreInitialised = FALSE; \
}
#define MUTEX_LOCK( name ) \
CPSemClaim( krnlData->name##Semaphore, SVCWAITFOREVER )
#define MUTEX_UNLOCK( name ) \
CPSemRelease( krnlData->name##Semaphore )
/* Thread management functions. CP/Q doesn't use threads but only supports
CP/Q tasks. These function in a somewhat peculiar manner, so this
facility isn't currently used */
/****************************************************************************
* *
* uITRON *
* *
****************************************************************************/
#elif defined( __ITRON__ )
/* In the following includes, kernel.h is the uITRON kernel.h, not the
cryptlib one */
#include <itron.h>
#include <kernel.h>
/* Object handles */
#define THREAD_HANDLE ID
#define MUTEX_HANDLE ID
/* Mutex management functions. We could use either semaphores or mutexes
for this, semaphores are supported under uITRON 3.0 but since we're
using automatic assignment of handles (which requires uITRON 4.0) we may
as well use mutexes */
#define MUTEX_DECLARE_STORAGE( name ) \
ID name##Mutex; \
BOOLEAN name##MutexInitialised; \
ID name##MutexOwner; \
int name##MutexLockcount
#define MUTEX_CREATE( name ) \
if( !krnlData->name##MutexInitialised ) \
{ \
static const T_CMTX pk_cmtx = { 0, 0 }; \
\
krnlData->name##Mutex = acre_mtx( ( T_CMTX * ) &pk_cmtx ); \
krnlData->name##MutexInitialised = TRUE; \
}
#define MUTEX_DESTROY( name ) \
if( krnlData->name##MutexInitialised ) \
{ \
loc_mtx( krnlData->name##Mutex ); \
unl_mtx( krnlData->name##Mutex ); \
del_mtx( krnlData->name##Mutex ); \
krnlData->name##MutexInitialised = FALSE; \
}
#define MUTEX_LOCK( name ) \
if( ploc_mtx( krnlData->name##Mutex ) == E_ILUSE ) \
{ \
if( !THREAD_SAME( krnlData->name##MutexOwner, THREAD_SELF() ) ) \
loc_mtx( krnlData->name##Mutex ); \
else \
krnlData->name##MutexLockcount++; \
} \
krnlData->name##MutexOwner = threadSelf();
#define MUTEX_UNLOCK( name ) \
if( krnlData->name##MutexLockcount > 0 ) \
krnlData->name##MutexLockcount--; \
else \
unl_mtx( krnlData->name##Mutex );
/* Thread management functions. The attributes for task creation are:
TA_HLNG | TA_ACT -- C interface, create task in the active rather
than suspended state (otherwise we'd have to use
act_tsk() to activate it a la BeOS).
arg -- Task extended info.
function -- Task function.
TPRI_SELF -- Same priority as invoking task.
16384 -- Stack size.
NULL -- Auto-allocate stack. This is given as 0 rather
than NULL since some uITRON headers define their
own NULL as 0, leading to compiler warnings.
uITRON status values are 8:8 bit pairs with the actual status in the
low 8 bits. The sub-values can be extracted with the MERCD() and SERCD()
(main- and sub-error-code) macros, however simply using the MERCD()
result isn't safe because it could be the (negative) low 8 bits of a
(positive overall) return value. When creating a task we therefore
consider a status < E_OK as being an error, without trying to pick apart
the overall value.
The handling of initialisers is a bit dodgy since TSK_NONE == TSK_SELF
(== 0) and it isn't even safe to use negative values since in some cases
these can be valid system task handles. In general however uITRON
numbers IDs from 1...n, so using 0 as a non-value is safe.
Handling of task sleep is also somewhat dodgy, time is measured in clock
ticks of an implementation-specific duration, the best that we can do is
to assume that it's close enough to ms.
In theory we don't really need to use exd_tsk() since returning from a
task ends it, but we make it explicit to be neat */
#define THREADFUNC_DEFINE( name, arg ) void name( VP_INT *arg )
#define THREAD_CREATE( function, arg, threadHandle, syncHandle, status ) \
{ \
static const T_CSEM pk_csem = { TA_TFIFO, 1, 64 }; \
T_CTSK pk_ctsk = { TA_HLNG | TA_ACT, ( arg ), ( function ), \
TPRI_SELF, 16384, 0 }; \
\
syncHandle = acre_sem( ( T_CSEM * ) &pk_csem ); \
threadHandle = acre_tsk( &pk_ctsk ); \
if( threadHandle < E_OK ) \
{ \
del_sem( syncHandle ); \
status = CRYPT_ERROR; \
} \
else \
status = CRYPT_OK; \
}
#define THREAD_EXIT( sync ) sig_sem( sync ); \
exd_tsk()
#define THREAD_INITIALISER TSK_NONE
#define THREAD_SAME( thread1, thread2 ) ( ( thread1 ) == ( thread2 ) )
#define THREAD_SELF() threadSelf()
#define THREAD_SLEEP( ms ) dly_tsk( ms )
#define THREAD_YIELD() dly_tsk( 0 )
#define THREAD_WAIT( sync ) wai_sem( sync ); \
del_sem( sync )
#define THREAD_CLOSE( sync )
/* The uITRON thread-self function returns the thread ID via a reference
parameter since uITRON IDs can be negative and there'd be no way to
differentiate a thread ID from an error code. Because of this we have
to provide a wrapper that returns it as a return value */
ID threadSelf( void );
/****************************************************************************
* *
* OS/2 *
* *
****************************************************************************/
#elif defined( __OS2__ )
#define INCL_DOSSEMAPHORES
#define INCL_DOSMISC
#define INCL_DOSFILEMGR
#define INCL_DOSMISC
#define INCL_DOSDATETIME
#define INCL_DOSPROCESS
#define INCL_WINWINDOWMGR
#define INCL_WINSYS
#include <os2.h>
ULONG DosGetThreadID( void );
/* Object handles */
#define THREAD_HANDLE TID
#define MUTEX_HANDLE HEV
/* Mutex management functions */
#define MUTEX_DECLARE_STORAGE( name ) \
HMTX name##Mutex; \
BOOLEAN name##MutexInitialised
#define MUTEX_CREATE( name ) \
if( !krnlData->name##MutexInitialised ) \
{ \
DosCreateMutexSem( NULL, &krnlData->name##Mutex, 0L, FALSE ); \
krnlData->name##MutexInitialised = TRUE; \
}
#define MUTEX_DESTROY( name ) \
if( krnlData->name##MutexInitialised ) \
{ \
DosRequestMutexSem( krnlData->name##Mutex, ( ULONG ) SEM_INDEFINITE_WAIT ); \
DosReleaseMutexSem( krnlData->name##Mutex ); \
DosCloseMutexSem( krnlData->name##Mutex ); \
krnlData->name##MutexInitialised = FALSE; \
}
#define MUTEX_LOCK( name ) \
DosRequestMutexSem( krnlData->name##Mutex, ( ULONG ) SEM_INDEFINITE_WAIT )
#define MUTEX_UNLOCK( name ) \
DosReleaseMutexSem( krnlData->name##Mutex )
/* Thread management functions */
#define THREADFUNC_DEFINE( name, arg ) void _Optlink name( void *arg )
#define THREAD_CREATE( function, arg, threadHandle, syncHandle, status ) \
{ \
threadHandle = syncHandle = \
_beginthread( ( function ), NULL, 8192, ( arg ) ); \
status = ( threadHandle == -1 ) ? CRYPT_ERROR : CRYPT_OK ); \
}
#define THREAD_EXIT( sync ) _endthread()
#define THREAD_INITIALISER 0
#define THREAD_SELF() DosGetThreadID()
#define THREAD_SAME( thread1, thread2 ) ( ( thread1 ) == ( thread2 ) )
#define THREAD_SLEEP( ms ) DosWait( ms )
#define THREAD_YIELD() DosWait( 0 )
#define THREAD_WAIT( sync ) DosWaitThread( sync, INFINITE )
#define THREAD_CLOSE( sync )
/****************************************************************************
* *
* PalmOS *
* *
****************************************************************************/
#elif defined( __PALMOS__ )
#include <CmnErrors.h>
#include <SysThread.h>
/* Object handles */
#define THREAD_HANDLE SysHandle
#define MUTEX_HANDLE SysHandle
/* Mutex management functions. These are just initialised in a slightly
odd manner, there isn't any function to explicitly initialise them but
instead they're statically initialised to a fixed value (NULL), when
the lock/unlock functions are passed this value they perform the
initialisation on-demand. This means that if the underlying hardware
supports it they can be implemented using atomic operations directly
on the critical-section value without having to allocate memory for
a struct to contain the critical-section data */
#define MUTEX_DECLARE_STORAGE( name ) \
SysCriticalSectionType name##Mutex; \
BOOLEAN name##MutexInitialised
#define MUTEX_CREATE( name ) \
if( !krnlData->name##MutexInitialised ) \
{ \
krnlData->name##Mutex = sysCriticalSectionInitializer; \
krnlData->name##MutexInitialised = TRUE; \
}
#define MUTEX_DESTROY( name ) \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -