Merged spinlockfix branch.
Some last-minute fixes for VxWorks build warnings.
This commit is contained in:
@@ -160,12 +160,13 @@ The basic rules which device support must follow are:</p>
|
||||
<p>The new header file epicsSpin.h adds a portable spin-locks API which is
|
||||
intended for locking very short sections of code (typically one or two lines of
|
||||
C or C++) to provide a critical section that protects against race conditions.
|
||||
On Posix platforms this uses the pthread_spinlock_t type if it's available but
|
||||
falls back to a pthread_mutex_t if not; on the UP VxWorks and RTEMS platforms
|
||||
the implementations lock out the CPU interrupts; the default implementation
|
||||
(used where no better implementation is available for the platform) uses an
|
||||
epicsMutex. Spin-locks may not be taken recursively, and the code inside the
|
||||
critical section should always be short and deterministic.</p>
|
||||
On Posix platforms this uses the pthread_spinlock_t type if it's available and
|
||||
the build is not configured to use Posix thread priorities, but otherwise it
|
||||
falls back to a pthread_mutex_t. On the UP VxWorks and RTEMS platforms the
|
||||
implementations lock out CPU interrupts and disable task preemption while a
|
||||
spin-lock is held. The default implementation (used when no other implementation
|
||||
is provided) uses an epicsMutex. Spin-locks may not be taken recursively, and
|
||||
the code inside the critical section should be short and deterministic.</p>
|
||||
|
||||
<h3>Improvements to aToIPAddr()</h3>
|
||||
|
||||
|
||||
@@ -103,6 +103,7 @@ Com_SRCS += osdStdio.c
|
||||
#POSIX thread priority scheduling flag
|
||||
THREAD_CPPFLAGS_NO += -DDONT_USE_POSIX_THREAD_PRIORITY_SCHEDULING
|
||||
osdThread_CPPFLAGS += $(THREAD_CPPFLAGS_$(USE_POSIX_THREAD_PRIORITY_SCHEDULING))
|
||||
osdSpin_CPPFLAGS += $(THREAD_CPPFLAGS_$(USE_POSIX_THREAD_PRIORITY_SCHEDULING))
|
||||
|
||||
Com_SRCS += osdThread.c
|
||||
Com_SRCS += osdThreadExtra.c
|
||||
|
||||
@@ -34,9 +34,11 @@ extern "C" {
|
||||
#ifndef EPICS_ATOMIC_INCR_INTT
|
||||
EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget )
|
||||
{
|
||||
EpicsAtomicLockKey key;
|
||||
EpicsAtomicLockKey key;
|
||||
int result;
|
||||
|
||||
epicsAtomicLock ( & key );
|
||||
const int result = ++(*pTarget);
|
||||
result = ++(*pTarget);
|
||||
epicsAtomicUnlock ( & key );
|
||||
return result;
|
||||
}
|
||||
@@ -46,8 +48,10 @@ EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget )
|
||||
EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
|
||||
{
|
||||
EpicsAtomicLockKey key;
|
||||
size_t result;
|
||||
|
||||
epicsAtomicLock ( & key );
|
||||
const size_t result = ++(*pTarget);
|
||||
result = ++(*pTarget);
|
||||
epicsAtomicUnlock ( & key );
|
||||
return result;
|
||||
}
|
||||
@@ -60,8 +64,10 @@ EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
|
||||
EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget )
|
||||
{
|
||||
EpicsAtomicLockKey key;
|
||||
int result;
|
||||
|
||||
epicsAtomicLock ( & key );
|
||||
const int result = --(*pTarget);
|
||||
result = --(*pTarget);
|
||||
epicsAtomicUnlock ( & key );
|
||||
return result;
|
||||
}
|
||||
@@ -71,8 +77,10 @@ EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget )
|
||||
EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
|
||||
{
|
||||
EpicsAtomicLockKey key;
|
||||
size_t result;
|
||||
|
||||
epicsAtomicLock ( & key );
|
||||
const size_t result = --(*pTarget);
|
||||
result = --(*pTarget);
|
||||
epicsAtomicUnlock ( & key );
|
||||
return result;
|
||||
}
|
||||
@@ -85,8 +93,10 @@ EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
|
||||
EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta )
|
||||
{
|
||||
EpicsAtomicLockKey key;
|
||||
int result;
|
||||
|
||||
epicsAtomicLock ( & key );
|
||||
const int result = *pTarget += delta;
|
||||
result = *pTarget += delta;
|
||||
epicsAtomicUnlock ( & key );
|
||||
return result;
|
||||
}
|
||||
@@ -96,8 +106,10 @@ EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta )
|
||||
EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta )
|
||||
{
|
||||
EpicsAtomicLockKey key;
|
||||
size_t result;
|
||||
|
||||
epicsAtomicLock ( & key );
|
||||
const size_t result = *pTarget += delta;
|
||||
result = *pTarget += delta;
|
||||
epicsAtomicUnlock ( & key );
|
||||
return result;
|
||||
}
|
||||
@@ -107,8 +119,10 @@ EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta
|
||||
EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta )
|
||||
{
|
||||
EpicsAtomicLockKey key;
|
||||
size_t result;
|
||||
|
||||
epicsAtomicLock ( & key );
|
||||
const size_t result = *pTarget -= delta;
|
||||
result = *pTarget -= delta;
|
||||
epicsAtomicUnlock ( & key );
|
||||
return result;
|
||||
}
|
||||
@@ -176,9 +190,11 @@ EPICS_ATOMIC_INLINE EpicsAtomicPtrT
|
||||
#ifndef EPICS_ATOMIC_CAS_INTT
|
||||
EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget, int oldval, int newval )
|
||||
{
|
||||
EpicsAtomicLockKey key;
|
||||
EpicsAtomicLockKey key;
|
||||
int cur;
|
||||
|
||||
epicsAtomicLock ( & key );
|
||||
const int cur = *pTarget;
|
||||
cur = *pTarget;
|
||||
if ( cur == oldval ) {
|
||||
*pTarget = newval;
|
||||
}
|
||||
@@ -191,9 +207,11 @@ EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget, int oldval, i
|
||||
EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget,
|
||||
size_t oldval, size_t newval )
|
||||
{
|
||||
EpicsAtomicLockKey key;
|
||||
EpicsAtomicLockKey key;
|
||||
size_t cur;
|
||||
|
||||
epicsAtomicLock ( & key );
|
||||
const size_t cur = *pTarget;
|
||||
cur = *pTarget;
|
||||
if ( cur == oldval ) {
|
||||
*pTarget = newval;
|
||||
}
|
||||
@@ -208,8 +226,10 @@ EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT (
|
||||
EpicsAtomicPtrT oldval, EpicsAtomicPtrT newval )
|
||||
{
|
||||
EpicsAtomicLockKey key;
|
||||
EpicsAtomicPtrT cur;
|
||||
|
||||
epicsAtomicLock ( & key );
|
||||
const EpicsAtomicPtrT cur = *pTarget;
|
||||
cur = *pTarget;
|
||||
if ( cur == oldval ) {
|
||||
*pTarget = newval;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,8 @@ extern "C" {
|
||||
|
||||
typedef struct epicsSpin *epicsSpinId;
|
||||
|
||||
epicsShareFunc epicsSpinId epicsSpinCreate();
|
||||
epicsShareFunc epicsSpinId epicsSpinCreate(void);
|
||||
epicsShareFunc epicsSpinId epicsSpinMustCreate(void);
|
||||
epicsShareFunc void epicsSpinDestroy(epicsSpinId);
|
||||
|
||||
epicsShareFunc void epicsSpinLock(epicsSpinId);
|
||||
|
||||
@@ -4,51 +4,103 @@
|
||||
* Copyright (c) 2012 ITER Organization.
|
||||
* Copyright (c) 2013 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2013 Brookhaven Science Assoc. as Operator of Brookhaven
|
||||
* National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Authors: Ralph Lange <Ralph.Lange@gmx.de>
|
||||
* Andrew Johnson <anj@aps.anl.gov>
|
||||
* Authors: Ralph Lange <Ralph.Lange@gmx.de>
|
||||
* Andrew Johnson <anj@aps.anl.gov>
|
||||
* Michael Davidsaver <mdavidsaver@bnl.gov>
|
||||
*
|
||||
* Based on epicsInterrupt.c (RTEMS implementation) by Eric Norum
|
||||
* Inspired by Linux UP spinlocks implemention
|
||||
* include/linux/spinlock_api_up.h
|
||||
*/
|
||||
|
||||
/*
|
||||
* RTEMS (single CPU): LOCK INTERRUPT
|
||||
* RTEMS (single CPU): LOCK INTERRUPT and DISABLE PREEMPTION
|
||||
*
|
||||
* CAVEAT:
|
||||
* This implementation is for UP architectures only.
|
||||
*
|
||||
* This implementation is intended for UP architectures only.
|
||||
*/
|
||||
|
||||
#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ 1
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <rtems.h>
|
||||
|
||||
#include "cantProceed.h"
|
||||
#include "epicsSpin.h"
|
||||
|
||||
typedef struct epicsSpin {
|
||||
rtems_interrupt_level level;
|
||||
unsigned int locked;
|
||||
} epicsSpin;
|
||||
|
||||
epicsSpinId epicsSpinCreate() {
|
||||
epicsSpinId epicsSpinCreate(void) {
|
||||
return calloc(1, sizeof(epicsSpin));
|
||||
}
|
||||
|
||||
epicsSpinId epicsSpinMustCreate(void)
|
||||
{
|
||||
epicsSpinId ret = epicsSpinCreate();
|
||||
if (!ret)
|
||||
cantProceed("epicsSpinMustCreate: epicsSpinCreate failed.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void epicsSpinDestroy(epicsSpinId spin) {
|
||||
free(spin);
|
||||
}
|
||||
|
||||
void epicsSpinLock(epicsSpinId spin) {
|
||||
rtems_interrupt_disable(spin->level);
|
||||
rtems_interrupt_level level;
|
||||
|
||||
rtems_interrupt_disable(level);
|
||||
_Thread_Disable_dispatch();
|
||||
if (spin->locked) {
|
||||
rtems_interrupt_enable(level);
|
||||
_Thread_Enable_dispatch();
|
||||
if (!rtems_interrupt_is_in_progress()) {
|
||||
printk("epicsSpinLock(%p): Deadlock.\n", spin);
|
||||
cantProceed("Recursive lock, missed unlock or block when locked.");
|
||||
}
|
||||
else {
|
||||
printk("epicsSpinLock(%p): Deadlock in ISR.\n"
|
||||
"Recursive lock, missed unlock or block when locked.\n",
|
||||
spin);
|
||||
}
|
||||
return;
|
||||
}
|
||||
spin->level = level;
|
||||
spin->locked = 1;
|
||||
}
|
||||
|
||||
int epicsSpinTryLock(epicsSpinId spin) {
|
||||
epicsSpinLock(spin);
|
||||
rtems_interrupt_level level;
|
||||
|
||||
rtems_interrupt_disable(level);
|
||||
_Thread_Disable_dispatch();
|
||||
if (spin->locked) {
|
||||
rtems_interrupt_enable(level);
|
||||
_Thread_Enable_dispatch();
|
||||
return 1;
|
||||
}
|
||||
spin->level = level;
|
||||
spin->locked = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void epicsSpinUnlock(epicsSpinId spin) {
|
||||
rtems_interrupt_enable(spin->level);
|
||||
rtems_interrupt_level level = spin->level;
|
||||
|
||||
if (!spin->locked) {
|
||||
printk("epicsSpinUnlock(%p): not locked\n", spin);
|
||||
return;
|
||||
}
|
||||
spin->level = spin->locked = 0;
|
||||
rtems_interrupt_enable (level);
|
||||
_Thread_Enable_dispatch();
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ typedef struct epicsSpin {
|
||||
epicsMutexId lock;
|
||||
} epicsSpin;
|
||||
|
||||
epicsSpinId epicsSpinCreate() {
|
||||
epicsSpinId epicsSpinCreate(void) {
|
||||
epicsSpin *spin;
|
||||
|
||||
spin = calloc(1, sizeof(*spin));
|
||||
@@ -43,6 +43,14 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
epicsSpinId epicsSpinMustCreate(void)
|
||||
{
|
||||
epicsSpinId ret = epicsSpinCreate();
|
||||
if(!ret)
|
||||
cantProceed("epicsSpinMustCreate fails");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void epicsSpinDestroy(epicsSpinId spin) {
|
||||
epicsMutexDestroy(spin->lock);
|
||||
free(spin);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#ifndef epicsAtomicOSD_h
|
||||
#define epicsAtomicOSD_h
|
||||
|
||||
struct EpicsAtomicLockKey {};
|
||||
typedef struct EpicsAtomicLockKey {} EpicsAtomicLockKey;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -18,15 +18,27 @@
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "errlog.h"
|
||||
#include "cantProceed.h"
|
||||
#include "epicsSpin.h"
|
||||
|
||||
/* POSIX spinlocks may be subject to priority inversion
|
||||
* and so can't be guaranteed safe in situations where
|
||||
* threads have different priorities, and thread
|
||||
* preemption can't be disabled.
|
||||
*/
|
||||
#if defined(DONT_USE_POSIX_THREAD_PRIORITY_SCHEDULING)
|
||||
#if defined(_POSIX_SPIN_LOCKS) && (_POSIX_SPIN_LOCKS > 1)
|
||||
# define USE_PSPIN
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#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)
|
||||
#ifdef USE_PSPIN
|
||||
|
||||
/*
|
||||
* POSIX SPIN LOCKS IMPLEMENTATION
|
||||
@@ -36,7 +48,7 @@ typedef struct epicsSpin {
|
||||
pthread_spinlock_t lock;
|
||||
} epicsSpin;
|
||||
|
||||
epicsSpinId epicsSpinCreate() {
|
||||
epicsSpinId epicsSpinCreate(void) {
|
||||
epicsSpin *spin;
|
||||
int status;
|
||||
|
||||
@@ -70,6 +82,8 @@ void epicsSpinLock(epicsSpinId spin) {
|
||||
|
||||
status = pthread_spin_lock(&spin->lock);
|
||||
checkStatus(status, "pthread_spin_lock");
|
||||
if (status)
|
||||
cantProceed(NULL);
|
||||
}
|
||||
|
||||
int epicsSpinTryLock(epicsSpinId spin) {
|
||||
@@ -79,7 +93,7 @@ int epicsSpinTryLock(epicsSpinId spin) {
|
||||
if (status == EBUSY)
|
||||
return 1;
|
||||
checkStatus(status, "pthread_spin_trylock");
|
||||
return 0;
|
||||
return status;
|
||||
}
|
||||
|
||||
void epicsSpinUnlock(epicsSpinId spin) {
|
||||
@@ -89,7 +103,7 @@ void epicsSpinUnlock(epicsSpinId spin) {
|
||||
checkStatus(status, "pthread_spin_unlock");
|
||||
}
|
||||
|
||||
#else /* defined(_POSIX_SPIN_LOCKS) && (_POSIX_SPIN_LOCKS > 1) */
|
||||
#else /* USE_PSPIN */
|
||||
|
||||
/*
|
||||
* POSIX MUTEX IMPLEMENTATION
|
||||
@@ -99,7 +113,7 @@ typedef struct epicsSpin {
|
||||
pthread_mutex_t lock;
|
||||
} epicsSpin;
|
||||
|
||||
epicsSpinId epicsSpinCreate() {
|
||||
epicsSpinId epicsSpinCreate(void) {
|
||||
epicsSpin *spin;
|
||||
int status;
|
||||
|
||||
@@ -133,6 +147,8 @@ void epicsSpinLock(epicsSpinId spin) {
|
||||
|
||||
status = pthread_mutex_lock(&spin->lock);
|
||||
checkStatus(status, "pthread_mutex_lock");
|
||||
if (status)
|
||||
cantProceed(NULL);
|
||||
}
|
||||
|
||||
int epicsSpinTryLock(epicsSpinId spin) {
|
||||
@@ -142,7 +158,7 @@ int epicsSpinTryLock(epicsSpinId spin) {
|
||||
if (status == EBUSY)
|
||||
return 1;
|
||||
checkStatus(status, "pthread_mutex_trylock");
|
||||
return 0;
|
||||
return status;
|
||||
}
|
||||
|
||||
void epicsSpinUnlock(epicsSpinId spin) {
|
||||
@@ -152,4 +168,13 @@ void epicsSpinUnlock(epicsSpinId spin) {
|
||||
checkStatus(status, "pthread_mutex_unlock");
|
||||
}
|
||||
|
||||
#endif /* defined(_POSIX_SPIN_LOCKS) && (_POSIX_SPIN_LOCKS > 1) */
|
||||
#endif /* USE_PSPIN */
|
||||
|
||||
|
||||
epicsSpinId epicsSpinMustCreate(void)
|
||||
{
|
||||
epicsSpinId ret = epicsSpinCreate();
|
||||
if(!ret)
|
||||
cantProceed("epicsSpinMustCreate fails");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget,
|
||||
|
||||
#endif /* ifdef __SunOS_5_10 */
|
||||
|
||||
struct EpicsAtomicLockKey {};
|
||||
typedef struct EpicsAtomicLockKey {} EpicsAtomicLockKey;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -2,18 +2,25 @@
|
||||
* Copyright (c) 2012 Helmholtz-Zentrum Berlin
|
||||
* fuer Materialien und Energie GmbH.
|
||||
* Copyright (c) 2012 ITER Organization.
|
||||
* Copyright (c) 2013 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2013 Brookhaven Science Assoc. as Operator of Brookhaven
|
||||
* National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Author: Ralph Lange <Ralph.Lange@gmx.de>
|
||||
* Authors: Ralph Lange <Ralph.Lange@gmx.de>
|
||||
* Andrew Johnson <anj@aps.anl.gov>
|
||||
* Michael Davidsaver <mdavidsaver@bnl.gov>
|
||||
*
|
||||
* based on epicsInterrupt.c (vxWorks implementation) by Marty Kraimer
|
||||
* Inspired by Linux UP spinlocks implemention
|
||||
* include/linux/spinlock_api_up.h
|
||||
*/
|
||||
|
||||
/*
|
||||
* vxWorks (single CPU): LOCK INTERRUPT
|
||||
* vxWorks (single CPU): LOCK INTERRUPT and DISABLE PREEMPTION
|
||||
*
|
||||
* CAVEAT:
|
||||
* This implementation will not compile on vxWorks SMP architectures.
|
||||
@@ -21,32 +28,88 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/* This is needed for vxWorks 6.x to prevent an obnoxious compiler warning */
|
||||
#define _VSB_CONFIG_FILE <../lib/h/config/vsbConfig.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <intLib.h>
|
||||
#include <logLib.h>
|
||||
#include <taskLib.h>
|
||||
|
||||
#include "cantProceed.h"
|
||||
#include "epicsSpin.h"
|
||||
|
||||
typedef struct epicsSpin {
|
||||
int key;
|
||||
unsigned int locked;
|
||||
} epicsSpin;
|
||||
|
||||
epicsSpinId epicsSpinCreate() {
|
||||
epicsSpinId epicsSpinCreate(void) {
|
||||
return calloc(1, sizeof(epicsSpin));
|
||||
}
|
||||
|
||||
epicsSpinId epicsSpinMustCreate(void)
|
||||
{
|
||||
epicsSpinId ret = epicsSpinCreate();
|
||||
if (!ret)
|
||||
cantProceed("epicsSpinMustCreate: epicsSpinCreate failed.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void epicsSpinDestroy(epicsSpinId spin) {
|
||||
free(spin);
|
||||
}
|
||||
|
||||
void epicsSpinLock(epicsSpinId spin) {
|
||||
spin->key = intLock();
|
||||
int key = intLock();
|
||||
|
||||
if (!intContext())
|
||||
taskLock();
|
||||
if (spin->locked) {
|
||||
intUnlock(key);
|
||||
if (!intContext()) {
|
||||
taskUnlock();
|
||||
logMsg("epicsSpinLock(%p): Deadlock.\n",
|
||||
(int) spin, 0, 0, 0, 0, 0);
|
||||
cantProceed("Recursive lock, missed unlock or block when locked.");
|
||||
}
|
||||
else {
|
||||
logMsg("epicsSpinLock(%p): Deadlock in ISR.\n"
|
||||
"Recursive lock, missed unlock or block when locked.\n",
|
||||
(int) spin, 0, 0, 0, 0, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
spin->key = key;
|
||||
spin->locked = 1;
|
||||
}
|
||||
|
||||
int epicsSpinTryLock(epicsSpinId spin) {
|
||||
epicsSpinLock(spin);
|
||||
int key = intLock();
|
||||
|
||||
if (!intContext())
|
||||
taskLock();
|
||||
if (spin->locked) {
|
||||
intUnlock(key);
|
||||
if (!intContext())
|
||||
taskUnlock();
|
||||
return 1;
|
||||
}
|
||||
spin->key = key;
|
||||
spin->locked = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void epicsSpinUnlock(epicsSpinId spin) {
|
||||
intUnlock(spin->key);
|
||||
int key = spin->key;
|
||||
|
||||
if (!spin->locked) {
|
||||
logMsg("epicsSpinUnlock(%p): not locked\n",
|
||||
(int) spin, 0, 0, 0, 0, 0);
|
||||
return;
|
||||
}
|
||||
spin->key = spin->locked = 0;
|
||||
intUnlock(key);
|
||||
if (!intContext())
|
||||
taskUnlock();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
int epicsThreadTest(void);
|
||||
int epicsTimerTest(void);
|
||||
int epicsSpinTest(void);
|
||||
int epicsAlgorithm(void);
|
||||
int epicsEllTest(void);
|
||||
int epicsEnvTest(void);
|
||||
@@ -61,6 +62,8 @@ void epicsRunLibComTests(void)
|
||||
*/
|
||||
runTest(epicsTimerTest);
|
||||
|
||||
runTest(epicsSpinTest);
|
||||
|
||||
runTest(epicsAlgorithm);
|
||||
|
||||
runTest(epicsEllTest);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "epicsTime.h"
|
||||
#include "epicsThread.h"
|
||||
#include "epicsAtomic.h"
|
||||
#include "epicsSpin.h"
|
||||
#include "epicsEvent.h"
|
||||
#include "errlog.h"
|
||||
@@ -31,22 +32,26 @@
|
||||
typedef struct info {
|
||||
int threadnum;
|
||||
epicsSpinId spin;
|
||||
int quit;
|
||||
int *counter;
|
||||
int rounds;
|
||||
epicsEventId done;
|
||||
} info;
|
||||
|
||||
#define spinDelay 0.016667
|
||||
|
||||
void spinThread(void *arg)
|
||||
{
|
||||
info *pinfo = (info *) arg;
|
||||
testDiag("spinThread %d starting", pinfo->threadnum);
|
||||
while (pinfo->quit--) {
|
||||
epicsThreadSleep(0.1); /* Try to align threads */
|
||||
while (pinfo->rounds--) {
|
||||
epicsThreadSleep(spinDelay);
|
||||
epicsSpinLock(pinfo->spin);
|
||||
testPass("spinThread %d epicsSpinLock taken", pinfo->threadnum);
|
||||
epicsThreadSleep(.1);
|
||||
pinfo->counter[0]++;
|
||||
epicsSpinUnlock(pinfo->spin);
|
||||
epicsThreadSleep(.9);
|
||||
}
|
||||
testDiag("spinThread %d exiting", pinfo->threadnum);
|
||||
return;
|
||||
epicsEventSignal(pinfo->done);
|
||||
}
|
||||
|
||||
static void lockPair(struct epicsSpin *spin)
|
||||
@@ -94,6 +99,8 @@ void epicsSpinPerformance ()
|
||||
|
||||
/* Initialize spinlock */
|
||||
spin = epicsSpinCreate();
|
||||
if (!spin)
|
||||
testAbort("epicsSpinCreate() returned NULL");
|
||||
|
||||
/* test a single lock pair */
|
||||
epicsTimeGetCurrent(&begin);
|
||||
@@ -106,78 +113,133 @@ void epicsSpinPerformance ()
|
||||
delay /= N * 100u; /* convert to delay per lock pair */
|
||||
delay *= 1e6; /* convert to micro seconds */
|
||||
testDiag("lock()*1/unlock()*1 takes %f microseconds", delay);
|
||||
epicsSpinDestroy(spin);
|
||||
}
|
||||
|
||||
struct verifyTryLock;
|
||||
|
||||
struct verifyTryLockEnt {
|
||||
epicsEventId done;
|
||||
struct verifyTryLock *main;
|
||||
};
|
||||
|
||||
struct verifyTryLock {
|
||||
epicsSpinId spin;
|
||||
epicsEventId done;
|
||||
int flag;
|
||||
struct verifyTryLockEnt *ents;
|
||||
};
|
||||
|
||||
static void verifyTryLockThread(void *pArg)
|
||||
{
|
||||
struct verifyTryLock *pVerify =
|
||||
(struct verifyTryLock *) pArg;
|
||||
struct verifyTryLockEnt *pVerify =
|
||||
(struct verifyTryLockEnt *) pArg;
|
||||
|
||||
while(epicsAtomicGetIntT(&pVerify->main->flag)==0) {
|
||||
int ret = epicsSpinTryLock(pVerify->main->spin);
|
||||
if(ret!=0) {
|
||||
epicsAtomicCmpAndSwapIntT(&pVerify->main->flag, 0, ret);
|
||||
break;
|
||||
} else
|
||||
epicsSpinUnlock(pVerify->main->spin);
|
||||
}
|
||||
|
||||
testOk1(epicsSpinTryLock(pVerify->spin));
|
||||
epicsEventSignal(pVerify->done);
|
||||
}
|
||||
|
||||
/* Start one thread per CPU which will all try lock
|
||||
* the same spinlock. They break as soon as one
|
||||
* fails to take the lock.
|
||||
*/
|
||||
static void verifyTryLock()
|
||||
{
|
||||
int N, i;
|
||||
struct verifyTryLock verify;
|
||||
|
||||
verify.spin = epicsSpinCreate();
|
||||
verify.done = epicsEventMustCreate(epicsEventEmpty);
|
||||
N = epicsThreadGetCPUs();
|
||||
if(N==1) {
|
||||
testSkip(1, "verifyTryLock() only for SMP systems");
|
||||
return;
|
||||
}
|
||||
|
||||
testOk1(epicsSpinTryLock(verify.spin) == 0);
|
||||
verify.flag = 0;
|
||||
verify.spin = epicsSpinMustCreate();
|
||||
|
||||
epicsThreadCreate("verifyTryLockThread", 40,
|
||||
epicsThreadGetStackSize(epicsThreadStackSmall),
|
||||
verifyTryLockThread, &verify);
|
||||
testDiag("Starting %d spinners", N);
|
||||
|
||||
testOk1(epicsEventWait(verify.done) == epicsEventWaitOK);
|
||||
verify.ents = calloc(N, sizeof(*verify.ents));
|
||||
for(i=0; i<N; i++) {
|
||||
verify.ents[i].main = &verify;
|
||||
verify.ents[i].done = epicsEventMustCreate(epicsEventEmpty);
|
||||
epicsThreadMustCreate("verifyTryLockThread", 40,
|
||||
epicsThreadGetStackSize(epicsThreadStackSmall),
|
||||
verifyTryLockThread, &verify.ents[i]);
|
||||
}
|
||||
|
||||
testDiag("All started");
|
||||
|
||||
for(i=0; i<N; i++) {
|
||||
epicsEventMustWait(verify.ents[i].done);
|
||||
epicsEventDestroy(verify.ents[i].done);
|
||||
}
|
||||
|
||||
testDiag("All done");
|
||||
|
||||
testOk(verify.flag==1, "epicsTryLock returns %d (expect 1)", verify.flag);
|
||||
|
||||
epicsSpinUnlock(verify.spin);
|
||||
epicsSpinDestroy(verify.spin);
|
||||
epicsEventDestroy(verify.done);
|
||||
free(verify.ents);
|
||||
}
|
||||
|
||||
MAIN(epicsSpinTest)
|
||||
{
|
||||
const int nthreads = 3;
|
||||
const int nrounds = 5;
|
||||
const int nrounds = 500;
|
||||
unsigned int stackSize;
|
||||
epicsThreadId *id;
|
||||
int i;
|
||||
int i, counter;
|
||||
char **name;
|
||||
void **arg;
|
||||
info **pinfo;
|
||||
epicsSpinId spin;
|
||||
|
||||
testPlan(3 + nthreads * nrounds);
|
||||
testPlan(2);
|
||||
|
||||
verifyTryLock();
|
||||
|
||||
spin = epicsSpinCreate();
|
||||
if (!spin)
|
||||
testAbort("epicsSpinCreate() returned NULL");
|
||||
|
||||
id = (epicsThreadId *) calloc(nthreads, sizeof(epicsThreadId));
|
||||
name = (char **) calloc(nthreads, sizeof(char *));
|
||||
arg = (void **) calloc(nthreads, sizeof(void *));
|
||||
pinfo = (info **) calloc(nthreads, sizeof(info *));
|
||||
stackSize = epicsThreadGetStackSize(epicsThreadStackSmall);
|
||||
counter = 0;
|
||||
for (i = 0; i < nthreads; i++) {
|
||||
name[i] = (char *) calloc(10, sizeof(char));
|
||||
sprintf(name[i],"task%d",i);
|
||||
pinfo[i] = (info *) calloc(1, sizeof(info));
|
||||
pinfo[i]->threadnum = i;
|
||||
pinfo[i]->spin = spin;
|
||||
pinfo[i]->quit = nrounds;
|
||||
arg[i] = pinfo[i];
|
||||
pinfo[i]->counter = &counter;
|
||||
pinfo[i]->rounds = nrounds;
|
||||
pinfo[i]->done = epicsEventMustCreate(epicsEventEmpty);
|
||||
id[i] = epicsThreadCreate(name[i], 40, stackSize,
|
||||
spinThread,
|
||||
arg[i]);
|
||||
pinfo[i]);
|
||||
}
|
||||
epicsThreadSleep(2.0 + nrounds);
|
||||
for (i = 0; i < nthreads; i++) {
|
||||
epicsEventMustWait(pinfo[i]->done);
|
||||
epicsEventDestroy(pinfo[i]->done);
|
||||
free(name[i]);
|
||||
free(pinfo[i]);
|
||||
}
|
||||
testOk(counter == nthreads * nrounds, "Loops run = %d (expecting %d)",
|
||||
counter, nthreads * nrounds);
|
||||
|
||||
free(pinfo);
|
||||
free(name);
|
||||
free(id);
|
||||
epicsSpinDestroy(spin);
|
||||
|
||||
epicsSpinPerformance();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user