Got epicsSpin from EPICS 7.0 for use in in ring buffers

This commit is contained in:
2020-05-12 12:11:18 +02:00
parent 751059eea2
commit c951229511
6 changed files with 520 additions and 0 deletions
+3
View File
@@ -18,6 +18,7 @@ epicsReadline_INCLUDES += $(INCLUDES_$(COMMANDLINE_LIBRARY))
#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))
#epicsVersion is created by this Makefile
INC += epicsVersion.h
@@ -160,6 +161,7 @@ INC += osdInterrupt.h
INC += epicsMutex.h
INC += osdMutex.h
INC += epicsSpin.h
INC += epicsEvent.h
INC += osdEvent.h
INC += epicsMath.h
@@ -224,6 +226,7 @@ SRCS += osdStdio.c
SRCS += osdThread.c
SRCS += osdMutex.c
SRCS += osdSpin.c
SRCS += osdEvent.c
SRCS += osdTime.cpp
SRCS += osdProcess.c
+32
View File
@@ -0,0 +1,32 @@
/*************************************************************************\
* 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(void);
epicsShareFunc epicsSpinId epicsSpinMustCreate(void);
epicsShareFunc void epicsSpinDestroy(epicsSpinId);
epicsShareFunc void epicsSpinLock(epicsSpinId);
epicsShareFunc int epicsSpinTryLock(epicsSpinId);
epicsShareFunc void epicsSpinUnlock(epicsSpinId);
#ifdef __cplusplus
}
#endif
#endif /* epicsSpinh */
+106
View File
@@ -0,0 +1,106 @@
/*************************************************************************\
* 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.
\*************************************************************************/
/*
* Authors: Ralph Lange <Ralph.Lange@gmx.de>
* Andrew Johnson <anj@aps.anl.gov>
* Michael Davidsaver <mdavidsaver@bnl.gov>
*
* Inspired by Linux UP spinlocks implemention
* include/linux/spinlock_api_up.h
*/
/*
* RTEMS (single CPU): LOCK INTERRUPT and DISABLE PREEMPTION
*
* CAVEAT:
* 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(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_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) {
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_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();
}
+84
View File
@@ -0,0 +1,84 @@
/*************************************************************************\
* 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 <Ralph.Lange@gmx.de>
*/
#include <stdlib.h>
#define epicsExportSharedSymbols
#include "cantProceed.h"
#include "errlog.h"
#include "epicsMutex.h"
#include "epicsSpin.h"
/*
* Default: EPICS MUTEX IMPLEMENTATION
*/
typedef struct epicsSpin {
epicsMutexId lock;
} epicsSpin;
epicsSpinId epicsSpinCreate(void) {
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;
}
epicsSpinId epicsSpinMustCreate(void)
{
epicsSpinId ret = epicsSpinCreate();
if(!ret)
cantProceed("epicsSpinMustCreate: epicsSpinCreate failed.");
return ret;
}
void epicsSpinDestroy(epicsSpinId spin) {
epicsMutexDestroy(spin->lock);
free(spin);
}
void epicsSpinLock(epicsSpinId spin) {
epicsMutexLockStatus status;
status = epicsMutexLock(spin->lock);
if (status != epicsMutexLockOK) {
errlogPrintf("epicsSpinLock(%p): epicsMutexLock returned %s\n", spin,
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("epicsSpinTryLock(%p): epicsMutexTryLock returned epicsMutexLockError\n", spin);
return 2;
}
void epicsSpinUnlock(epicsSpinId spin) {
epicsMutexUnlock(spin->lock);
}
+180
View File
@@ -0,0 +1,180 @@
/*************************************************************************\
* 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 <Ralph.Lange@gmx.de>
*/
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#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 > 0)
# define USE_PSPIN
#endif
#endif
#define checkStatus(status,message) \
if ((status)) { \
errlogPrintf("epicsSpin %s failed: error %s\n", \
(message), strerror((status))); \
}
#ifdef USE_PSPIN
/*
* POSIX SPIN LOCKS IMPLEMENTATION
*/
typedef struct epicsSpin {
pthread_spinlock_t lock;
} epicsSpin;
epicsSpinId epicsSpinCreate(void) {
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");
if (status)
cantProceed(NULL);
}
int epicsSpinTryLock(epicsSpinId spin) {
int status;
status = pthread_spin_trylock(&spin->lock);
if (status == EBUSY)
return 1;
checkStatus(status, "pthread_spin_trylock");
return status;
}
void epicsSpinUnlock(epicsSpinId spin) {
int status;
status = pthread_spin_unlock(&spin->lock);
checkStatus(status, "pthread_spin_unlock");
}
#else /* USE_PSPIN */
/*
* POSIX MUTEX IMPLEMENTATION
*/
typedef struct epicsSpin {
pthread_mutex_t lock;
} epicsSpin;
epicsSpinId epicsSpinCreate(void) {
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");
if (status)
cantProceed(NULL);
}
int epicsSpinTryLock(epicsSpinId spin) {
int status;
status = pthread_mutex_trylock(&spin->lock);
if (status == EBUSY)
return 1;
checkStatus(status, "pthread_mutex_trylock");
return status;
}
void epicsSpinUnlock(epicsSpinId spin) {
int status;
status = pthread_mutex_unlock(&spin->lock);
checkStatus(status, "pthread_mutex_unlock");
}
#endif /* USE_PSPIN */
epicsSpinId epicsSpinMustCreate(void)
{
epicsSpinId ret = epicsSpinCreate();
if(!ret)
cantProceed("epicsSpinMustCreate: epicsSpinCreate failed.");
return ret;
}
+115
View File
@@ -0,0 +1,115 @@
/*************************************************************************\
* 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.
\*************************************************************************/
/*
* Authors: Ralph Lange <Ralph.Lange@gmx.de>
* Andrew Johnson <anj@aps.anl.gov>
* Michael Davidsaver <mdavidsaver@bnl.gov>
*
* Inspired by Linux UP spinlocks implemention
* include/linux/spinlock_api_up.h
*/
/*
* vxWorks (single CPU): LOCK INTERRUPT and DISABLE PREEMPTION
*
* CAVEAT:
* This implementation will not compile on vxWorks SMP architectures.
* These architectures provide spinlocks, which must be used instead.
*
*/
/* 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(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) {
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) {
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) {
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();
}