diff --git a/src/libCom/osi/Makefile b/src/libCom/osi/Makefile index e22091712..94fe92c61 100644 --- a/src/libCom/osi/Makefile +++ b/src/libCom/osi/Makefile @@ -20,6 +20,7 @@ INC += osdInterrupt.h INC += epicsMutex.h INC += osdMutex.h +INC += epicsSpin.h INC += epicsEvent.h INC += osdEvent.h INC += epicsMath.h @@ -107,6 +108,7 @@ Com_SRCS += osdThread.c Com_SRCS += osdThreadExtra.c Com_SRCS += osdThreadHooks.c Com_SRCS += osdMutex.c +Com_SRCS += osdSpin.c Com_SRCS += osdEvent.c Com_SRCS += osdTime.cpp Com_SRCS += osdProcess.c diff --git a/src/libCom/osi/epicsSpin.h b/src/libCom/osi/epicsSpin.h new file mode 100644 index 000000000..06bc44a09 --- /dev/null +++ b/src/libCom/osi/epicsSpin.h @@ -0,0 +1,31 @@ +/*************************************************************************\ +* Copyright (c) 2012 Helmholtz-Zentrum Berlin +* fuer Materialien und Energie GmbH. +* Copyright (c) 2012 ITER Organization. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +#ifndef epicsSpinh +#define epicsSpinh + +#include "shareLib.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct epicsSpin *epicsSpinId; + +epicsShareFunc epicsSpinId epicsSpinCreate(); +epicsShareFunc void epicsSpinDestroy(epicsSpinId); + +epicsShareFunc void epicsSpinLock(epicsSpinId); +epicsShareFunc int epicsSpinTryLock(epicsSpinId); +epicsShareFunc void epicsSpinUnlock(epicsSpinId); + +#ifdef __cplusplus +} +#endif + +#endif /* epicsSpinh */ diff --git a/src/libCom/osi/os/default/osdSpin.c b/src/libCom/osi/os/default/osdSpin.c new file mode 100644 index 000000000..0f945d0f2 --- /dev/null +++ b/src/libCom/osi/os/default/osdSpin.c @@ -0,0 +1,71 @@ +/*************************************************************************\ +* Copyright (c) 2012 Helmholtz-Zentrum Berlin +* fuer Materialien und Energie GmbH. +* Copyright (c) 2012 ITER Organization. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author: Ralph Lange + */ + +#include "errlog.h" +#include "epicsMutex.h" +#include "epicsSpin.h" + +/* + * Default: EPICS MUTEX IMPLEMENTATION + */ + +typedef struct epicsSpin { + epicsMutexId lock; +} epicsSpin; + +epicsSpinId epicsSpinCreate() { + epicsSpin *spin; + + spin = calloc(1, sizeof(*spin)); + if (!spin) + goto fail; + + spin->lock = epicsMutexCreate(); + if (!spin->lock) + goto fail; + + return spin; + +fail: + free(spin); + return NULL; +} + +void epicsSpinDestroy(epicsSpinId spin) { + epicsMutexDestroy(spin->lock); + free(spin); +} + +void epicsSpinLock(epicsSpinId spin) { + epicsMutexLockStatus status; + + status = epicsMutexLock(spin->lock); + if (status != epicsMutexLockOK) { + errlogPrintf("epicsSpin epicsMutexLock failed: error %s\n", + status == epicsMutexLockTimeout ? "epicsMutexLockTimeout" : "epicsMutexLockError"); + } +} + +int epicsSpinTryLock(epicsSpinId spin) { + epicsMutexLockStatus status; + + status = epicsMutexTryLock(spin->lock); + if (status == epicsMutexLockOK) return 0; + if (status == epicsMutexLockTimeout) return 1; + + errlogPrintf("epicsSpin epicsMutexTryLock failed: error epicsMutexLockError\n"); + return 2; +} + +void epicsSpinUnlock(epicsSpinId spin) { + epicsMutexUnlock(spin->lock); +} diff --git a/src/libCom/osi/os/posix/osdSpin.c b/src/libCom/osi/os/posix/osdSpin.c new file mode 100644 index 000000000..71c34cca8 --- /dev/null +++ b/src/libCom/osi/os/posix/osdSpin.c @@ -0,0 +1,154 @@ +/*************************************************************************\ +* Copyright (c) 2012 Helmholtz-Zentrum Berlin +* fuer Materialien und Energie GmbH. +* Copyright (c) 2012 ITER Organization. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author: Ralph Lange + */ + +#include +#include +#include +#include +#include + +#include "errlog.h" +#include "epicsSpin.h" + +#define checkStatus(status,message) \ + if ((status)) { \ + errlogPrintf("epicsSpin %s failed: error %s\n", \ + (message), strerror((status))); \ + } + +#if defined(_POSIX_SPIN_LOCKS) && (_POSIX_SPIN_LOCKS > 1) + +/* + * POSIX SPIN LOCKS IMPLEMENTATION + */ + +typedef struct epicsSpin { + pthread_spinlock_t lock; +} epicsSpin; + +epicsSpinId epicsSpinCreate() { + epicsSpin *spin; + int status; + + spin = calloc(1, sizeof(*spin)); + if (!spin) + goto fail; + + status = pthread_spin_init(&spin->lock, PTHREAD_PROCESS_PRIVATE); + checkStatus(status, "pthread_spin_init"); + if (status) + goto fail; + + return spin; + +fail: + free(spin); + return NULL; +} + +void epicsSpinDestroy(epicsSpinId spin) { + int status; + + status = pthread_spin_destroy(&spin->lock); + checkStatus(status, "pthread_spin_destroy"); + + free(spin); +} + +void epicsSpinLock(epicsSpinId spin) { + int status; + + status = pthread_spin_lock(&spin->lock); + checkStatus(status, "pthread_spin_lock"); +} + +int epicsSpinTryLock(epicsSpinId spin) { + int status; + + status = pthread_spin_trylock(&spin->lock); + if (status == EBUSY) + return 1; + checkStatus(status, "pthread_spin_trylock"); + return 0; +} + +void epicsSpinUnlock(epicsSpinId spin) { + int status; + + status = pthread_spin_unlock(&spin->lock); + checkStatus(status, "pthread_spin_unlock"); +} + +#else /* defined(_POSIX_SPIN_LOCKS) && (_POSIX_SPIN_LOCKS > 1) */ + +/* + * POSIX MUTEX IMPLEMENTATION + */ + +typedef struct epicsSpin { + pthread_mutex_t lock; +} epicsSpin; + +epicsSpinId epicsSpinCreate() { + epicsSpin *spin; + int status; + + spin = calloc(1, sizeof(*spin)); + if (!spin) + goto fail; + + status = pthread_mutex_init(&spin->lock, NULL); + checkStatus(status, "pthread_mutex_init"); + if (status) + goto fail; + + return spin; + +fail: + free(spin); + return NULL; +} + +void epicsSpinDestroy(epicsSpinId spin) { + int status; + + status = pthread_mutex_destroy(&spin->lock); + checkStatus(status, "pthread_mutex_destroy"); + + free(spin); +} + +void epicsSpinLock(epicsSpinId spin) { + int status; + + status = pthread_mutex_lock(&spin->lock); + checkStatus(status, "pthread_mutex_lock"); +} + +int epicsSpinTryLock(epicsSpinId spin) { + int status; + + status = pthread_mutex_trylock(&spin->lock); + if (status == EBUSY) + return 1; + checkStatus(status, "pthread_mutex_trylock"); + return 0; +} + +void epicsSpinUnlock(epicsSpinId spin) { + int status; + + status = pthread_mutex_unlock(&spin->lock); + checkStatus(status, "pthread_mutex_unlock"); +} + +#endif /* defined(_POSIX_SPIN_LOCKS) && (_POSIX_SPIN_LOCKS > 1) */ diff --git a/src/libCom/osi/os/vxWorks/osdSpin.c b/src/libCom/osi/os/vxWorks/osdSpin.c new file mode 100644 index 000000000..89019738c --- /dev/null +++ b/src/libCom/osi/os/vxWorks/osdSpin.c @@ -0,0 +1,52 @@ +/*************************************************************************\ +* Copyright (c) 2012 Helmholtz-Zentrum Berlin +* fuer Materialien und Energie GmbH. +* Copyright (c) 2012 ITER Organization. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author: Ralph Lange + * + * based on epicsInterrupt.c (vxWorks implementation) by Marty Kraimer + */ + +/* + * vxWorks (single CPU): LOCK INTERRUPT + * + * CAVEAT: + * This implementation will break on vxWorks SMP architectures. + * These architectures provide spinlocks, which will have to be used. + * + */ + +#include +#include + +#include "epicsSpin.h" + +typedef struct epicsSpin { + int key; +} epicsSpin; + +epicsSpinId epicsSpinCreate() { + return calloc(1, sizeof(*spin)); +} + +void epicsSpinDestroy(epicsSpinId spin) { + free(spin); +} + +void epicsSpinLock(epicsSpinId spin) { + spin->key = intLock(); +} + +int epicsSpinTryLock(epicsSpinId spin) { + epicsSpinLock(spin); + return 0; +} + +void epicsSpinUnlock(epicsSpinId spin) { + intUnlock(spin->key); +}