implement fast mutex for posix; remove epicsMutexLockWithTimeout
This commit is contained in:
@@ -150,22 +150,6 @@ void epicsMutex::lock ()
|
||||
}
|
||||
}
|
||||
|
||||
bool epicsMutex::lock ( double timeOut ) // X aCC 361
|
||||
epicsThrows (( epicsMutex::invalidMutex ))
|
||||
{
|
||||
epicsMutexLockStatus status = epicsMutexLockWithTimeout ( this->id, timeOut );
|
||||
if ( status == epicsMutexLockOK ) {
|
||||
return true;
|
||||
}
|
||||
else if ( status == epicsMutexLockTimeout ) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
throw invalidMutex ();
|
||||
return false; // never here, compiler is happy
|
||||
}
|
||||
}
|
||||
|
||||
bool epicsMutex::tryLock () // X aCC 361
|
||||
epicsThrows (( epicsMutex::invalidMutex ))
|
||||
{
|
||||
|
||||
@@ -37,8 +37,6 @@ public:
|
||||
epicsThrows (( invalidMutex ));
|
||||
void unlock ()
|
||||
epicsThrows (());
|
||||
bool lock ( double timeOut ) /* true if successful */
|
||||
epicsThrows (( invalidMutex ));
|
||||
bool tryLock () /* true if successful */
|
||||
epicsThrows (( invalidMutex ));
|
||||
private:
|
||||
@@ -67,8 +65,6 @@ epicsShareFunc void epicsShareAPI epicsMutexUnlock(epicsMutexId id);
|
||||
epicsShareFunc epicsMutexLockStatus epicsShareAPI epicsMutexLock(
|
||||
epicsMutexId id);
|
||||
#define epicsMutexMustLock(ID) assert((epicsMutexLock((ID))==epicsMutexLockOK))
|
||||
epicsShareFunc epicsMutexLockStatus epicsShareAPI epicsMutexLockWithTimeout(
|
||||
epicsMutexId id, double timeOut);
|
||||
epicsShareFunc epicsMutexLockStatus epicsShareAPI epicsMutexTryLock(
|
||||
epicsMutexId id);
|
||||
epicsShareFunc void epicsShareAPI epicsMutexShow(
|
||||
|
||||
@@ -153,51 +153,6 @@ epicsMutexLockStatus epicsMutexLock(epicsMutexId id)
|
||||
#endif
|
||||
}
|
||||
|
||||
epicsMutexLockStatus epicsMutexLockWithTimeout(
|
||||
epicsMutexId id, double timeOut)
|
||||
{
|
||||
#ifdef RTEMS_FAST_MUTEX
|
||||
Semaphore_Control *the_semaphore = (Semaphore_Control *)id;
|
||||
ISR_Level level;
|
||||
boolean wait;
|
||||
rtems_interval delay;
|
||||
extern double rtemsTicksPerSecond_double;
|
||||
|
||||
SEMSTAT(1)
|
||||
if (timeOut <= 0.0) {
|
||||
wait = FALSE;
|
||||
delay = 0;
|
||||
}
|
||||
else {
|
||||
wait = TRUE;
|
||||
delay = timeOut * rtemsTicksPerSecond_double;
|
||||
if (delay == 0)
|
||||
delay++;
|
||||
}
|
||||
_ISR_Disable( level );
|
||||
_CORE_mutex_Seize(
|
||||
&the_semaphore->Core_control.mutex,
|
||||
the_semaphore->Object.id,
|
||||
wait,
|
||||
delay,
|
||||
level
|
||||
);
|
||||
if (_Thread_Executing->Wait.return_code == 0)
|
||||
return epicsMutexLockOK;
|
||||
else
|
||||
return epicsMutexLockError;
|
||||
#else
|
||||
epicsEventWaitStatus status;
|
||||
SEMSTAT(1)
|
||||
status = epicsEventWaitWithTimeout(id,timeOut);
|
||||
return((status==epicsEventWaitOK
|
||||
? epicsMutexLockOK
|
||||
: (status==epicsEventWaitTimeout)
|
||||
? epicsMutexLockTimeout
|
||||
: epicsMutexLockError));
|
||||
#endif
|
||||
}
|
||||
|
||||
epicsMutexLockStatus epicsMutexTryLock(epicsMutexId id)
|
||||
{
|
||||
#ifdef RTEMS_FAST_MUTEX
|
||||
|
||||
@@ -154,92 +154,6 @@ epicsShareFunc epicsMutexLockStatus epicsShareAPI
|
||||
return epicsMutexLockOK;
|
||||
}
|
||||
|
||||
/*
|
||||
* epicsMutexLockWithTimeout ()
|
||||
*/
|
||||
epicsShareFunc epicsMutexLockStatus epicsShareAPI
|
||||
epicsMutexLockWithTimeout ( epicsMutexId pSem, double timeOut )
|
||||
{
|
||||
static const unsigned mSecPerSec = 1000u;
|
||||
|
||||
if ( thisIsNT ) {
|
||||
DWORD begin = GetTickCount ();
|
||||
|
||||
if ( ! TryEnterCriticalSection ( &pSem->os.cs.mutex ) ) {
|
||||
DWORD delay = 0;
|
||||
DWORD tmo;
|
||||
|
||||
if ( timeOut <= 0.0 ) {
|
||||
tmo = 1;
|
||||
}
|
||||
else if ( timeOut >= INFINITE / mSecPerSec ) {
|
||||
tmo = INFINITE - 1;
|
||||
}
|
||||
else {
|
||||
tmo = ( DWORD ) ( ( timeOut * mSecPerSec ) + 0.5 );
|
||||
if ( tmo == 0 ) {
|
||||
tmo = 1;
|
||||
}
|
||||
}
|
||||
|
||||
assert ( pSem->os.cs.waitingCount < 0x7FFFFFFF );
|
||||
// this causes a cache flush on MP systems
|
||||
InterlockedIncrement ( &pSem->os.cs.waitingCount );
|
||||
|
||||
while ( ! TryEnterCriticalSection ( &pSem->os.cs.mutex ) ) {
|
||||
DWORD current;
|
||||
|
||||
WaitForSingleObject ( pSem->os.cs.unlockSignal, tmo - delay );
|
||||
|
||||
current = GetTickCount ();
|
||||
if ( current >= begin ) {
|
||||
delay = current - begin;
|
||||
}
|
||||
else {
|
||||
delay = ( 0xffffffff - begin ) + current + 1;
|
||||
}
|
||||
|
||||
if ( delay >= tmo ) {
|
||||
assert ( pSem->os.cs.waitingCount > 0 );
|
||||
// this causes a cache flush on MP systems
|
||||
InterlockedDecrement ( &pSem->os.cs.waitingCount );
|
||||
return epicsMutexLockTimeout;
|
||||
}
|
||||
}
|
||||
|
||||
assert ( pSem->os.cs.waitingCount > 0 );
|
||||
// this causes a cache flush on MP systems
|
||||
InterlockedDecrement ( &pSem->os.cs.waitingCount );
|
||||
}
|
||||
}
|
||||
else {
|
||||
DWORD tmo;
|
||||
DWORD status;
|
||||
if ( timeOut <= 0.0 ) {
|
||||
tmo = 1u;
|
||||
}
|
||||
else if ( timeOut >= INFINITE / mSecPerSec ) {
|
||||
tmo = INFINITE - 1;
|
||||
}
|
||||
else {
|
||||
tmo = ( DWORD ) ( ( timeOut * mSecPerSec ) + 0.5 );
|
||||
if ( tmo == 0 ) {
|
||||
tmo = 1;
|
||||
}
|
||||
}
|
||||
status = WaitForSingleObject ( pSem->os.mutex, tmo );
|
||||
if ( status != WAIT_OBJECT_0 ) {
|
||||
if ( status == WAIT_TIMEOUT ) {
|
||||
return epicsMutexLockTimeout;
|
||||
}
|
||||
else {
|
||||
return epicsMutexLockError;
|
||||
}
|
||||
}
|
||||
}
|
||||
return epicsMutexLockOK;
|
||||
}
|
||||
|
||||
/*
|
||||
* epicsMutexTryLock ()
|
||||
*/
|
||||
|
||||
@@ -25,11 +25,104 @@
|
||||
#include "epicsTime.h"
|
||||
#include "errlog.h"
|
||||
#include "epicsAssert.h"
|
||||
|
||||
#define checkStatus(status,message) \
|
||||
if((status)) { \
|
||||
errlogPrintf("%s failed: error %s\n",(message),strerror((status)));}
|
||||
|
||||
#define checkStatusQuit(status,message,method) \
|
||||
if(status) { \
|
||||
errlogPrintf("%s failed: error %s\n",(message),strerror((status))); \
|
||||
cantProceed((method)); \
|
||||
}
|
||||
|
||||
/* Until these can be demonstrated to work leave them undefined*/
|
||||
/* On solaris 8 _POSIX_THREAD_PRIO_INHERIT fails*/
|
||||
#undef _POSIX_THREAD_PROCESS_SHARED
|
||||
#undef _POSIX_THREAD_PRIO_INHERIT
|
||||
|
||||
/* Two completely different implementations are provided below
|
||||
* If support is available for PTHREAD_MUTEX_RECURSIVE then
|
||||
* only pthread_mutex is used.
|
||||
* If support is not available for PTHREAD_MUTEX_RECURSIVE then
|
||||
* a much more complicated solution is required
|
||||
*/
|
||||
|
||||
#if defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE)>=500
|
||||
typedef struct epicsMutexOSD {
|
||||
pthread_mutexattr_t mutexAttr;
|
||||
pthread_mutex_t lock;
|
||||
}epicsMutexOSD;
|
||||
|
||||
epicsMutexId epicsMutexOsdCreate(void) {
|
||||
epicsMutexOSD *pmutex;
|
||||
int status;
|
||||
|
||||
pmutex = callocMustSucceed(1,sizeof(*pmutex),"epicsMutexOsdCreate");
|
||||
status = pthread_mutexattr_init(&pmutex->mutexAttr);
|
||||
checkStatusQuit(status,"pthread_mutexattr_init","epicsMutexOsdCreate");
|
||||
#if defined _POSIX_THREAD_PRIO_INHERIT
|
||||
status = pthread_mutexattr_setprotocol(
|
||||
&pmutex->mutexAttr,PTHREAD_PRIO_INHERIT);
|
||||
if(errVerbose) checkStatus(status,"pthread_mutexattr_setprotocal");
|
||||
#endif /*_POSIX_THREAD_PRIO_INHERIT*/
|
||||
status = pthread_mutexattr_settype(&pmutex->mutexAttr,PTHREAD_MUTEX_RECURSIVE);
|
||||
if(errVerbose) checkStatus(status,"pthread_mutexattr_settype");
|
||||
status = pthread_mutex_init(&pmutex->lock,&pmutex->mutexAttr);
|
||||
checkStatusQuit(status,"pthread_mutex_init","epicsMutexOsdCreate");
|
||||
return((epicsMutexId)pmutex);
|
||||
}
|
||||
|
||||
void epicsMutexOsdDestroy(epicsMutexId pmutex)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = pthread_mutex_destroy(&pmutex->lock);
|
||||
checkStatus(status,"pthread_mutex_destroy");
|
||||
status = pthread_mutexattr_destroy(&pmutex->mutexAttr);
|
||||
checkStatus(status,"pthread_mutexattr_destroy");
|
||||
free(pmutex);
|
||||
}
|
||||
|
||||
void epicsMutexUnlock(epicsMutexId pmutex)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = pthread_mutex_unlock(&pmutex->lock);
|
||||
checkStatusQuit(status,"pthread_mutex_unlock","epicsMutexUnlock");
|
||||
}
|
||||
|
||||
epicsMutexLockStatus epicsMutexLock(epicsMutexId pmutex)
|
||||
{
|
||||
pthread_t tid = pthread_self();
|
||||
int status;
|
||||
|
||||
if(!pmutex || !tid) return(epicsMutexLockError);
|
||||
status = pthread_mutex_lock(&pmutex->lock);
|
||||
checkStatusQuit(status,"pthread_mutex_lock","epicsMutexLock");
|
||||
return(epicsMutexLockOK);
|
||||
}
|
||||
|
||||
epicsMutexLockStatus epicsMutexTryLock(epicsMutexId pmutex)
|
||||
{
|
||||
pthread_t tid = pthread_self();
|
||||
epicsMutexLockStatus status;
|
||||
int pthreadStatus;
|
||||
|
||||
pthreadStatus = pthread_mutex_trylock(&pmutex->lock);
|
||||
if(pthreadStatus!=0) {
|
||||
if(pthreadStatus==EBUSY) return(epicsMutexLockTimeout);
|
||||
checkStatusQuit(pthreadStatus,"pthread_mutex_lock","epicsMutexTryLock");
|
||||
}
|
||||
return(epicsMutexLockOK);
|
||||
}
|
||||
|
||||
void epicsMutexShow(epicsMutexId pmutex,unsigned int level)
|
||||
{
|
||||
}
|
||||
|
||||
#else /*defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE)>=500 */
|
||||
|
||||
typedef struct epicsMutexOSD {
|
||||
pthread_mutexattr_t mutexAttr;
|
||||
pthread_mutex_t lock;
|
||||
@@ -41,17 +134,7 @@ typedef struct epicsMutexOSD {
|
||||
int owned; /* TRUE | FALSE */
|
||||
pthread_t ownerTid;
|
||||
}epicsMutexOSD;
|
||||
|
||||
#define checkStatus(status,message) \
|
||||
if((status)) { \
|
||||
errlogPrintf("%s failed: error %s\n",(message),strerror((status)));}
|
||||
|
||||
#define checkStatusQuit(status,message,method) \
|
||||
if(status) { \
|
||||
errlogPrintf("%s failed: error %s\n",(message),strerror((status))); \
|
||||
cantProceed((method)); \
|
||||
}
|
||||
|
||||
epicsMutexId epicsMutexOsdCreate(void) {
|
||||
epicsMutexOSD *pmutex;
|
||||
int status;
|
||||
@@ -117,7 +200,7 @@ void epicsMutexUnlock(epicsMutexId pmutex)
|
||||
status = pthread_mutex_unlock(&pmutex->lock);
|
||||
checkStatusQuit(status,"pthread_mutex_unlock","epicsMutexUnlock");
|
||||
}
|
||||
|
||||
|
||||
epicsMutexLockStatus epicsMutexLock(epicsMutexId pmutex)
|
||||
{
|
||||
pthread_t tid = pthread_self();
|
||||
@@ -135,33 +218,6 @@ epicsMutexLockStatus epicsMutexLock(epicsMutexId pmutex)
|
||||
checkStatusQuit(status,"pthread_mutex_unlock","epicsMutexLock");
|
||||
return(epicsMutexLockOK);
|
||||
}
|
||||
|
||||
epicsMutexLockStatus epicsMutexLockWithTimeout(epicsMutexId pmutex, double timeout)
|
||||
{
|
||||
pthread_t tid = pthread_self();
|
||||
struct timespec wakeTime;
|
||||
int status,unlockStatus;
|
||||
|
||||
convertDoubleToWakeTime(timeout,&wakeTime);
|
||||
status = pthread_mutex_lock(&pmutex->lock);
|
||||
checkStatusQuit(status,"pthread_mutex_lock","epicsMutexLockWithTimeout");
|
||||
while(pmutex->owned && !pthread_equal(pmutex->ownerTid,tid)) {
|
||||
status = pthread_cond_timedwait(
|
||||
&pmutex->waitToBeOwner,&pmutex->lock,&wakeTime);
|
||||
if(!status) break;
|
||||
}
|
||||
if(status==0) {
|
||||
pmutex->ownerTid = tid;
|
||||
pmutex->owned = 1;
|
||||
pmutex->count++;
|
||||
}
|
||||
unlockStatus = pthread_mutex_unlock(&pmutex->lock);
|
||||
checkStatusQuit(unlockStatus,"pthread_mutex_lock","epicsMutexLockWithTimeout");
|
||||
if(status==0) return(epicsMutexLockOK);
|
||||
if(status==ETIMEDOUT) return(epicsMutexLockTimeout);
|
||||
checkStatusQuit(status,"pthread_cond_timedwait","epicsMutexLockWithTimeout");
|
||||
return(epicsMutexLockError);
|
||||
}
|
||||
|
||||
epicsMutexLockStatus epicsMutexTryLock(epicsMutexId pmutex)
|
||||
{
|
||||
@@ -190,3 +246,4 @@ void epicsMutexShow(epicsMutexId pmutex,unsigned int level)
|
||||
printf("ownerTid %p count %d owned %d\n",
|
||||
(void *)pmutex->ownerTid,pmutex->count,pmutex->owned);
|
||||
}
|
||||
#endif /*defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE)>=500 */
|
||||
|
||||
@@ -33,24 +33,6 @@ void epicsMutexOsdDestroy(epicsMutexId id)
|
||||
semDelete((SEM_ID)id);
|
||||
}
|
||||
|
||||
epicsMutexLockStatus epicsMutexLockWithTimeout(
|
||||
epicsMutexId id, double timeOut)
|
||||
{
|
||||
int status;
|
||||
int ticks;
|
||||
|
||||
if(timeOut<=0.0) {
|
||||
ticks = 0;
|
||||
} else {
|
||||
ticks = timeOut*sysClkRateGet();
|
||||
if(ticks<=0) ticks = 1;
|
||||
}
|
||||
status = semTake((SEM_ID)id,ticks);
|
||||
if(status==OK) return(epicsMutexLockOK);
|
||||
if(errno==S_objLib_OBJ_TIMEOUT) return(epicsMutexLockTimeout);
|
||||
return(epicsMutexLockError);
|
||||
}
|
||||
|
||||
epicsMutexLockStatus epicsMutexTryLock(epicsMutexId id)
|
||||
{
|
||||
int status;
|
||||
|
||||
@@ -265,9 +265,6 @@ extern "C" void epicsMutexTest(int nthreads,int verbose)
|
||||
printf("calling epicsMutexLock(mutex) time %ld\n",time(&tp));
|
||||
status = epicsMutexLock(mutex);
|
||||
if(status) printf("status %d\n",status);
|
||||
printf("calling epicsMutexLockWithTimeout(mutex,2.0) time %ld\n",time(&tp));
|
||||
status = epicsMutexLockWithTimeout(mutex,2.0);
|
||||
if(status) printf("status %d\n",status);
|
||||
printf("calling epicsMutexTryLock(mutex) time %ld\n",time(&tp));
|
||||
status = epicsMutexTryLock(mutex);
|
||||
if(status) printf("status %d\n",status);
|
||||
@@ -276,8 +273,6 @@ extern "C" void epicsMutexTest(int nthreads,int verbose)
|
||||
epicsMutexUnlock(mutex);
|
||||
printf("calling epicsMutexUnlock() time %ld\n",time(&tp));
|
||||
epicsMutexUnlock(mutex);
|
||||
printf("calling epicsMutexUnlock() time %ld\n",time(&tp));
|
||||
epicsMutexUnlock(mutex);
|
||||
epicsMutexShow(mutex,1);
|
||||
|
||||
if(nthreads<=0) {
|
||||
|
||||
Reference in New Issue
Block a user