rationalize osdMutex

Avoids split allocation.
Eliminates special case free-list.

win32: eliminate pre-XP
rtems-score: eliminate non-fast
This commit is contained in:
Michael Davidsaver
2023-09-30 18:03:40 -07:00
parent 1cd141c540
commit e4ad4becde
12 changed files with 306 additions and 486 deletions

View File

@ -35,8 +35,6 @@
#include "cantProceed.h"
#include "epicsExit.h"
void epicsMutexCleanup(void);
typedef struct exitNode {
ELLNODE node;
epicsExitFunc func;
@ -115,8 +113,6 @@ LIBCOM_API void epicsExitCallAtExits(void)
epicsExitCallAtExitsPvt ( pep );
destroyExitPvt ( pep );
}
/* Handle specially to avoid circular reference */
epicsMutexCleanup();
}
LIBCOM_API void epicsExitCallAtThreadExits(void)

View File

@ -26,30 +26,23 @@
#include <stdio.h>
#include <string.h>
#include "dbDefs.h"
#include "epicsStdio.h"
#include "epicsThread.h"
#include "valgrind/valgrind.h"
#include "ellLib.h"
#include "errlog.h"
#include "epicsMutex.h"
#include "epicsMutexImpl.h"
#include "epicsThread.h"
#include "cantProceed.h"
static epicsThreadOnceId epicsMutexOsiOnce = EPICS_THREAD_ONCE_INIT;
static ELLLIST mutexList;
static ELLLIST freeList;
struct epicsMutexParm {
ELLNODE node;
epicsMutexOSD * id;
# ifdef LOG_LAST_OWNER
epicsThreadId lastOwner;
# endif
const char *pFileName;
int lineno;
};
static epicsMutexOSD * epicsMutexGlobalLock;
static ELLLIST mutexList = ELLLIST_INIT;
/* Specially initialized to bootstrap initialization.
* When supported (posix and !rtems) use statically initiallized mutex.
* Otherwise, initialize via epicsMutexOsdSetup().
*/
struct epicsMutexParm epicsMutexGlobalLock = {ELLNODE_INIT, __FILE__, __LINE__};
// vxWorks 5.4 gcc fails during compile when I use std::exception
using namespace std;
@ -76,176 +69,82 @@ const char * epicsMutex::invalidMutex::what () const throw ()
return "epicsMutex::invalidMutex()";
}
static void epicsMutexOsiInit(void *) {
ellInit(&mutexList);
ellInit(&freeList);
VALGRIND_CREATE_MEMPOOL(&freeList, 0, 0);
epicsMutexGlobalLock = epicsMutexOsdCreate();
}
epicsMutexId epicsStdCall epicsMutexOsiCreate(
const char *pFileName,int lineno)
{
epicsMutexOSD * id;
epicsMutexOsdSetup();
epicsThreadOnce(&epicsMutexOsiOnce, epicsMutexOsiInit, NULL);
epicsMutexId ret = (epicsMutexId)calloc(1, sizeof(*ret));
if(ret) {
ret->pFileName = pFileName;
ret->lineno = lineno;
if(!epicsMutexOsdPrepare(ret)) {
epicsMutexMustLock(&epicsMutexGlobalLock);
ellAdd(&mutexList, &ret->node);
(void)epicsMutexUnlock(&epicsMutexGlobalLock);
} else {
free(ret);
ret = NULL;
}
id = epicsMutexOsdCreate();
if(!id) {
return 0;
}
epicsMutexLockStatus lockStat =
epicsMutexOsdLock(epicsMutexGlobalLock);
assert ( lockStat == epicsMutexLockOK );
epicsMutexParm *pmutexNode =
reinterpret_cast < epicsMutexParm * > ( ellFirst(&freeList) );
if(pmutexNode) {
ellDelete(&freeList,&pmutexNode->node);
VALGRIND_MEMPOOL_FREE(&freeList, pmutexNode);
} else {
pmutexNode = static_cast < epicsMutexParm * > ( calloc(1,sizeof(epicsMutexParm)) );
}
VALGRIND_MEMPOOL_ALLOC(&freeList, pmutexNode, sizeof(epicsMutexParm));
pmutexNode->id = id;
# ifdef LOG_LAST_OWNER
pmutexNode->lastOwner = 0;
# endif
pmutexNode->pFileName = pFileName;
pmutexNode->lineno = lineno;
ellAdd(&mutexList,&pmutexNode->node);
epicsMutexOsdUnlock(epicsMutexGlobalLock);
return(pmutexNode);
return ret;
}
epicsMutexId epicsStdCall epicsMutexOsiMustCreate(
const char *pFileName,int lineno)
{
epicsMutexId id = epicsMutexOsiCreate(pFileName,lineno);
assert(id);
return(id );
if(!id) {
cantProceed("epicsMutexOsiMustCreate() fails at %s:%d\n",
pFileName, lineno);
}
return id;
}
void epicsStdCall epicsMutexDestroy(epicsMutexId pmutexNode)
{
epicsMutexLockStatus lockStat =
epicsMutexOsdLock(epicsMutexGlobalLock);
assert ( lockStat == epicsMutexLockOK );
ellDelete(&mutexList,&pmutexNode->node);
epicsMutexOsdDestroy(pmutexNode->id);
VALGRIND_MEMPOOL_FREE(&freeList, pmutexNode);
VALGRIND_MEMPOOL_ALLOC(&freeList, &pmutexNode->node, sizeof(pmutexNode->node));
ellAdd(&freeList,&pmutexNode->node);
epicsMutexOsdUnlock(epicsMutexGlobalLock);
}
void epicsStdCall epicsMutexUnlock(epicsMutexId pmutexNode)
{
epicsMutexOsdUnlock(pmutexNode->id);
}
epicsMutexLockStatus epicsStdCall epicsMutexLock(
epicsMutexId pmutexNode)
{
epicsMutexLockStatus status =
epicsMutexOsdLock(pmutexNode->id);
# ifdef LOG_LAST_OWNER
if ( status == epicsMutexLockOK ) {
pmutexNode->lastOwner = epicsThreadGetIdSelf();
}
# endif
return status;
}
epicsMutexLockStatus epicsStdCall epicsMutexTryLock(
epicsMutexId pmutexNode)
{
epicsMutexLockStatus status =
epicsMutexOsdTryLock(pmutexNode->id);
# ifdef LOG_LAST_OWNER
if ( status == epicsMutexLockOK ) {
pmutexNode->lastOwner = epicsThreadGetIdSelf();
}
# endif
return status;
}
/* Empty the freeList.
* Called from epicsExit.c, but not via epicsAtExit()
* to avoid the possibility of a circular reference.
*/
extern "C"
void epicsMutexCleanup(void)
{
ELLNODE *cur;
epicsMutexLockStatus lockStat =
epicsMutexOsdLock(epicsMutexGlobalLock);
assert ( lockStat == epicsMutexLockOK );
while((cur=ellGet(&freeList))!=NULL) {
VALGRIND_MEMPOOL_FREE(&freeList, cur);
free(cur);
if(pmutexNode) {
epicsMutexMustLock(&epicsMutexGlobalLock);
ellDelete(&mutexList, &pmutexNode->node);
(void)epicsMutexUnlock(&epicsMutexGlobalLock);
epicsMutexOsdCleanup(pmutexNode);
free(pmutexNode);
}
epicsMutexOsdUnlock(epicsMutexGlobalLock);
}
void epicsStdCall epicsMutexShow(
epicsMutexId pmutexNode, unsigned int level)
{
# ifdef LOG_LAST_OWNER
char threadName [255];
if ( pmutexNode->lastOwner ) {
# error currently not safe to fetch name for stale thread
epicsThreadGetName ( pmutexNode->lastOwner,
threadName, sizeof ( threadName ) );
}
else {
strcpy ( threadName, "<not used>" );
}
printf("epicsMutexId %p last owner \"%s\" source %s line %d\n",
(void *)pmutexNode, threadName,
pmutexNode->pFileName, pmutexNode->lineno);
# else
printf("epicsMutexId %p source %s line %d\n",
(void *)pmutexNode, pmutexNode->pFileName,
pmutexNode->lineno);
# endif
printf("epicsMutexId %p source %s line %d\n",
(void *)pmutexNode, pmutexNode->pFileName,
pmutexNode->lineno);
if ( level > 0 ) {
epicsMutexOsdShow(pmutexNode->id,level-1);
epicsMutexOsdShow(pmutexNode,level-1);
}
}
void epicsStdCall epicsMutexShowAll(int onlyLocked,unsigned int level)
{
epicsMutexParm *pmutexNode;
epicsMutexOsdSetup();
if (epicsMutexOsiOnce == EPICS_THREAD_ONCE_INIT)
return;
printf("ellCount(&mutexList) %d ellCount(&freeList) %d\n",
ellCount(&mutexList),ellCount(&freeList));
printf("ellCount(&mutexList) %d\n", ellCount(&mutexList));
epicsMutexOsdShowAll();
epicsMutexLockStatus lockStat =
epicsMutexOsdLock(epicsMutexGlobalLock);
assert ( lockStat == epicsMutexLockOK );
pmutexNode = reinterpret_cast < epicsMutexParm * > ( ellFirst(&mutexList) );
while(pmutexNode) {
epicsMutexMustLock(&epicsMutexGlobalLock);
for(ELLNODE *cur =ellFirst(&mutexList); cur; cur = ellNext(cur)) {
epicsMutexParm *lock = CONTAINER(cur, epicsMutexParm, node);
if(onlyLocked) {
epicsMutexLockStatus status;
status = epicsMutexOsdTryLock(pmutexNode->id);
if(status==epicsMutexLockOK) {
epicsMutexOsdUnlock(pmutexNode->id);
pmutexNode =
reinterpret_cast < epicsMutexParm * >
( ellNext(&pmutexNode->node) );
continue;
// cycle through to test state
if(epicsMutexTryLock(lock)==epicsMutexLockOK) {
epicsMutexUnlock(lock);
continue; // was not locked, skip
}
}
epicsMutexShow(pmutexNode, level);
pmutexNode =
reinterpret_cast < epicsMutexParm * > ( ellNext(&pmutexNode->node) );
epicsMutexShow(lock, level);
}
epicsMutexOsdUnlock(epicsMutexGlobalLock);
epicsMutexUnlock(&epicsMutexGlobalLock);
}
#if !defined(__GNUC__) || __GNUC__<4 || (__GNUC__==4 && __GNUC_MINOR__<8)

View File

@ -247,21 +247,6 @@ LIBCOM_API void epicsStdCall epicsMutexShow(
LIBCOM_API void epicsStdCall epicsMutexShowAll(
int onlyLocked,unsigned int level);
/**@privatesection
* The following are interfaces to the OS dependent
* implementation and should NOT be called directly by
* user code.
*/
struct epicsMutexOSD * epicsMutexOsdCreate(void);
void epicsMutexOsdDestroy(struct epicsMutexOSD *);
void epicsMutexOsdUnlock(struct epicsMutexOSD *);
epicsMutexLockStatus epicsMutexOsdLock(struct epicsMutexOSD *);
epicsMutexLockStatus epicsMutexOsdTryLock(struct epicsMutexOSD *);
void epicsMutexOsdShow(struct epicsMutexOSD *,unsigned int level);
#ifdef EPICS_PRIVATE_API
void epicsMutexOsdShowAll(void);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,66 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* Copyright (c) 2023 Michael Davidsaver
* SPDX-License-Identifier: EPICS
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* Only include from osdMutex.c */
#ifndef epicsMutexImpl_H
#define epicsMutexImpl_H
#if defined(vxWorks)
# include <vxWorks.h>
# include <semLib.h>
#elif defined(_WIN32)
# define VC_EXTRALEAN
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
#elif defined(__rtems__)
# include <rtems.h>
# include <rtems/score/cpuopts.h>
#else
# include <pthread.h>
#endif
#include "ellLib.h"
#ifdef __cplusplus
extern "C" {
#endif
struct epicsMutexParm {
/* global list of mutex */
ELLNODE node;
/* location where mutex was allocated */
const char *pFileName;
int lineno;
#if defined(vxWorks)
SEM_ID osd;
#elif defined(_WIN32)
CRITICAL_SECTION osd;
#elif defined(__RTEMS_MAJOR__) && __RTEMS_MAJOR__<5
Semaphore_Control *osd;
#else
pthread_mutex_t osd;
#endif
};
void epicsMutexOsdSetup(void);
long epicsMutexOsdPrepare(struct epicsMutexParm *);
void epicsMutexOsdCleanup(struct epicsMutexParm *);
void epicsMutexOsdShow(struct epicsMutexParm *,unsigned int level);
void epicsMutexOsdShowAll(void);
extern struct epicsMutexParm epicsMutexGlobalLock;
#ifdef __cplusplus
} // extern "C
#endif
#endif // epicsMutexImpl_H

View File

@ -26,6 +26,7 @@
#include "epicsEvent.h"
#include "epicsThread.h"
#include "rtemsNamePvt.h"
#include "errlog.h"
/* #define EPICS_RTEMS_SEMAPHORE_STATS */
@ -47,12 +48,9 @@ epicsEventCreate(epicsEventInitialState initialState)
{
rtems_status_code sc;
rtems_id sid;
rtems_interrupt_level level;
static char c1 = 'a';
static char c2 = 'a';
static char c3 = 'a';
static uint32_t name;
sc = rtems_semaphore_create (rtems_build_name ('B', c3, c2, c1),
sc = rtems_semaphore_create (next_rtems_name ('B', &name),
initialState,
RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE |
RTEMS_NO_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL,
@ -62,26 +60,6 @@ epicsEventCreate(epicsEventInitialState initialState)
errlogPrintf ("Can't create binary semaphore: %s\n", rtems_status_text (sc));
return NULL;
}
rtems_interrupt_disable (level);
if (c1 == 'z') {
if (c2 == 'z') {
if (c3 == 'z') {
c3 = 'a';
}
else {
c3++;
}
c2 = 'a';
}
else {
c2++;
}
c1 = 'a';
}
else {
c1++;
}
rtems_interrupt_enable (level);
return (epicsEventId)sid;
}

View File

@ -19,6 +19,7 @@
#include <assert.h>
#include <stdio.h>
#include <errno.h>
#include <rtems.h>
#include <rtems/error.h>
@ -26,97 +27,84 @@
#include "epicsStdio.h"
#include "epicsMutex.h"
#include "epicsMutexImpl.h"
#include "rtemsNamePvt.h"
#include "epicsEvent.h"
#include "errlog.h"
#define RTEMS_FAST_MUTEX
/* #define EPICS_RTEMS_SEMAPHORE_STATS */
/*
* Some performance tuning instrumentation
*/
#ifdef EPICS_RTEMS_SEMAPHORE_STATS
unsigned long semMstat[4];
#define SEMSTAT(i) semMstat[i]++;
#else
#define SEMSTAT(i)
#endif
uint32_t next_rtems_name(char prefix, uint32_t* counter)
{
uint32_t next;
rtems_interrupt_level level;
char a, b, c;
struct epicsMutexOSD *
epicsMutexOsdCreate(void)
rtems_interrupt_disable (level);
next = *counter;
*counter = (next+1)%(26u*26u*26u);
rtems_interrupt_enable (level);
a = 'a' + (next % 26u);
next /= 26u;
b = 'a' + (next % 26u);
next /= 26u;
c = 'a' + (next % 26u); // modulo should be redundant, but ... paranoia
return rtems_build_name(prefix, a, b, c);
}
void epicsMutexOsdSetup(void)
{
// TODO: use RTEMS_SYSINIT_ITEM() ?
if(!epicsMutexGlobalLock.osd) {
epicsMutexOsdPrepare(&epicsMutexGlobalLock);
}
}
long epicsMutexOsdPrepare(struct epicsMutexParm *mutex)
{
rtems_status_code sc;
rtems_id sid;
rtems_interrupt_level level;
static char c1 = 'a';
static char c2 = 'a';
static char c3 = 'a';
static uint32_t name;
sc = rtems_semaphore_create (rtems_build_name ('M', c3, c2, c1),
sc = rtems_semaphore_create (next_rtems_name ('M', &name),
1,
RTEMS_PRIORITY|RTEMS_BINARY_SEMAPHORE|RTEMS_INHERIT_PRIORITY|RTEMS_NO_PRIORITY_CEILING|RTEMS_LOCAL,
0,
&sid);
if (sc != RTEMS_SUCCESSFUL) {
errlogPrintf ("Can't create mutex semaphore: %s\n", rtems_status_text (sc));
return NULL;
return ENOMEM;
}
rtems_interrupt_disable (level);
if (c1 == 'z') {
if (c2 == 'z') {
if (c3 == 'z') {
c3 = 'a';
}
else {
c3++;
}
c2 = 'a';
}
else {
c2++;
}
c1 = 'a';
}
else {
c1++;
}
rtems_interrupt_enable (level);
#ifdef RTEMS_FAST_MUTEX
{
Semaphore_Control *the_semaphore;
Objects_Locations location;
Objects_Locations location;
the_semaphore = _Semaphore_Get( sid, &location );
_Thread_Enable_dispatch();
mutex->osd = _Semaphore_Get( sid, &location );
_Thread_Enable_dispatch(); /* _Semaphore_Get() disables */
return (struct epicsMutexOSD *)the_semaphore;
return 0;
}
#endif
return (struct epicsMutexOSD *)sid;
}
void epicsMutexOsdDestroy(struct epicsMutexOSD * id)
void epicsMutexOsdCleanup(struct epicsMutexParm *mutex)
{
rtems_status_code sc;
rtems_id sid;
#ifdef RTEMS_FAST_MUTEX
Semaphore_Control *the_semaphore = (Semaphore_Control *)id;
Semaphore_Control *the_semaphore = mutex->osd;
sid = the_semaphore->Object.id;
#else
sid = (rtems_id)id;
#endif
sc = rtems_semaphore_delete (sid);
if (sc == RTEMS_RESOURCE_IN_USE) {
rtems_semaphore_release (sid);
sc = rtems_semaphore_delete (sid);
}
if (sc != RTEMS_SUCCESSFUL)
errlogPrintf ("Can't destroy semaphore %p (%lx): %s\n", id, (unsigned long)sid, rtems_status_text (sc));
errlogPrintf ("Can't destroy semaphore %p (%lx): %s\n",
mutex, (unsigned long)sid, rtems_status_text (sc));
}
void epicsMutexOsdUnlock(struct epicsMutexOSD * id)
void epicsMutexUnlock(struct epicsMutexParm *mutex)
{
#ifdef RTEMS_FAST_MUTEX
Semaphore_Control *the_semaphore = (Semaphore_Control *)id;
Semaphore_Control *the_semaphore = mutex->osd;
_Thread_Disable_dispatch();
_CORE_mutex_Surrender (
&the_semaphore->Core_control.mutex,
@ -124,18 +112,13 @@ void epicsMutexOsdUnlock(struct epicsMutexOSD * id)
NULL
);
_Thread_Enable_dispatch();
#else
epicsEventSignal (id);
#endif
}
epicsMutexLockStatus epicsMutexOsdLock(struct epicsMutexOSD * id)
epicsMutexLockStatus epicsMutexLock(struct epicsMutexParm *mutex)
{
#ifdef RTEMS_FAST_MUTEX
Semaphore_Control *the_semaphore = (Semaphore_Control *)id;
Semaphore_Control *the_semaphore = mutex->osd;
ISR_Level level;
SEMSTAT(0)
_ISR_Disable( level );
_CORE_mutex_Seize(
&the_semaphore->Core_control.mutex,
@ -148,19 +131,12 @@ epicsMutexLockStatus epicsMutexOsdLock(struct epicsMutexOSD * id)
return epicsMutexLockOK;
else
return epicsMutexLockError;
#else
SEMSTAT(0)
return((epicsEventWait (id) == epicsEventWaitOK)
?epicsMutexLockOK : epicsMutexLockError);
#endif
}
epicsMutexLockStatus epicsMutexOsdTryLock(struct epicsMutexOSD * id)
epicsMutexLockStatus epicsMutexTryLock(struct epicsMutexParm *mutex)
{
#ifdef RTEMS_FAST_MUTEX
Semaphore_Control *the_semaphore = (Semaphore_Control *)id;
Semaphore_Control *the_semaphore = mutex->osd;
ISR_Level level;
SEMSTAT(2)
_ISR_Disable( level );
_CORE_mutex_Seize(
&the_semaphore->Core_control.mutex,
@ -175,25 +151,12 @@ epicsMutexLockStatus epicsMutexOsdTryLock(struct epicsMutexOSD * id)
return epicsMutexLockTimeout;
else
return epicsMutexLockError;
#else
epicsEventWaitStatus status;
SEMSTAT(2)
status = epicsEventTryWait(id);
return((status==epicsEventWaitOK
? epicsMutexLockOK
: (status==epicsEventWaitTimeout)
? epicsMutexLockTimeout
: epicsMutexLockError));
#endif
}
LIBCOM_API void epicsMutexOsdShow(struct epicsMutexOSD * id,unsigned int level)
LIBCOM_API void epicsMutexOsdShow(struct epicsMutexParm *mutex,unsigned int level)
{
#ifdef RTEMS_FAST_MUTEX
Semaphore_Control *the_semaphore = (Semaphore_Control *)id;
id = (struct epicsMutexOSD *)the_semaphore->Object.id;
#endif
epicsEventShow ((epicsEventId)id,level);
Semaphore_Control *the_semaphore = mutex->osd;
epicsEventShow ((epicsEventId)the_semaphore->Object.id,level);
}
void epicsMutexOsdShowAll(void) {}

View File

@ -31,6 +31,7 @@
#include "epicsStdio.h"
#include "errlog.h"
#include "epicsMutex.h"
#include "epicsMutexImpl.h"
#include "epicsString.h"
#include "epicsThread.h"
#include "cantProceed.h"
@ -59,7 +60,7 @@ struct taskVar {
unsigned int threadVariableCapacity;
void **threadVariables;
};
static struct epicsMutexOSD *taskVarMutex;
static struct epicsMutexParm taskVarMutex = {ELLNODE_INIT, __FILE__, __LINE__};
static struct taskVar *taskVarHead;
#define RTEMS_NOTEPAD_TASKVAR 11
@ -67,15 +68,7 @@ static struct taskVar *taskVarHead;
* Support for `once-only' execution
*/
static volatile int initialized = 0; /* strictly speaking 'volatile' is not enough here, but it shouldn't hurt */
static struct epicsMutexOSD *onceMutex;
static
void epicsMutexOsdMustLock(struct epicsMutexOSD * L)
{
while(epicsMutexOsdLock(L)!=epicsMutexLockOK) {
cantProceed("epicsThreadOnce() mutex error");
}
}
static struct epicsMutexParm onceMutex = {ELLNODE_INIT, __FILE__, __LINE__};
/*
* Just map osi 0 to 99 into RTEMS 199 to 100
@ -161,13 +154,13 @@ epicsThreadGetStackSize (epicsThreadStackSizeClass size)
static void
taskVarLock (void)
{
epicsMutexOsdMustLock (taskVarMutex);
epicsMutexMustLock (&taskVarMutex);
}
static void
taskVarUnlock (void)
{
epicsMutexOsdUnlock (taskVarMutex);
epicsMutexUnlock (&taskVarMutex);
}
static
@ -243,7 +236,7 @@ setThreadInfo(rtems_id tid, const char *name, EPICSTHREADFUNC funptr,
v->threadVariables = NULL;
v->isRunning = 1;
if (joinable) {
char c[3];
char c[3] = {0,0,0};
strncpy(c, v->name, 3);
sc = rtems_barrier_create(rtems_build_name('~', c[0], c[1], c[2]),
RTEMS_BARRIER_AUTOMATIC_RELEASE | RTEMS_LOCAL,
@ -288,10 +281,8 @@ epicsThreadInit (void)
rtems_task_priority old;
rtems_task_set_priority (RTEMS_SELF, epicsThreadGetOssPriorityValue(99), &old);
onceMutex = epicsMutexOsdCreate();
taskVarMutex = epicsMutexOsdCreate();
if (!onceMutex || !taskVarMutex)
cantProceed("epicsThreadInit() can't create global mutexes\n");
epicsMutexOsdPrepare(&taskVarMutex);
epicsMutexOsdPrepare(&onceMutex);
rtems_task_ident (RTEMS_SELF, 0, &tid);
if(setThreadInfo (tid, "_main_", NULL, NULL, 0) != RTEMS_SUCCESSFUL)
cantProceed("epicsThreadInit() unable to setup _main_");
@ -317,7 +308,7 @@ epicsThreadCreateOpt (
unsigned int stackSize;
rtems_id tid;
rtems_status_code sc;
char c[4];
char c[4] = {0,0,0,0};
if (!initialized)
epicsThreadInit();
@ -612,26 +603,26 @@ void epicsThreadOnce(epicsThreadOnceId *id, void(*func)(void *), void *arg)
#define EPICS_THREAD_ONCE_DONE (epicsThreadId) 1
if (!initialized) epicsThreadInit();
epicsMutexOsdMustLock(onceMutex);
epicsMutexMustLock(&onceMutex);
if (*id != EPICS_THREAD_ONCE_DONE) {
if (*id == EPICS_THREAD_ONCE_INIT) { /* first call */
*id = epicsThreadGetIdSelf(); /* mark active */
epicsMutexOsdUnlock(onceMutex);
epicsMutexUnlock(&onceMutex);
func(arg);
epicsMutexOsdMustLock(onceMutex);
epicsMutexMustLock(&onceMutex);
*id = EPICS_THREAD_ONCE_DONE; /* mark done */
} else if (*id == epicsThreadGetIdSelf()) {
epicsMutexOsdUnlock(onceMutex);
epicsMutexUnlock(&onceMutex);
cantProceed("Recursive epicsThreadOnce() initialization\n");
} else
while (*id != EPICS_THREAD_ONCE_DONE) {
/* Another thread is in the above func(arg) call. */
epicsMutexOsdUnlock(onceMutex);
epicsMutexUnlock(&onceMutex);
epicsThreadSleep(epicsThreadSleepQuantum());
epicsMutexOsdMustLock(onceMutex);
epicsMutexMustLock(&onceMutex);
}
}
epicsMutexOsdUnlock(onceMutex);
epicsMutexUnlock(&onceMutex);
}
/*

View File

@ -0,0 +1,20 @@
/*************************************************************************\
* Copyright (c) 2023 Michael Davidsaver
* SPDX-License-Identifier: EPICS
* EPICS Base is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#ifndef RTEMSNAMEPVT_H
#define RTEMSNAMEPVT_H
#include <stdint.h>
/* Compute rtems_build_name(prefix, A, B, C) where A, B, C are the letters a-z.
* eg. "Qaaa"
*
* 'counter' is incremented atomically during each call.
*/
uint32_t next_rtems_name(char prefix, uint32_t* counter);
#endif // RTEMSNAMEPVT_H

View File

@ -20,147 +20,59 @@
#include <stdio.h>
#include <limits.h>
#define VC_EXTRALEAN
#define STRICT
#include <windows.h>
#if _WIN32_WINNT < 0x0501
# error Minimum supported is Windows XP
#endif
#define EPICS_PRIVATE_API
#include "libComAPI.h"
#include "epicsMutex.h"
#include "epicsMutexImpl.h"
#include "epicsThread.h"
#include "epicsAssert.h"
#include "epicsStdio.h"
typedef struct epicsMutexOSD {
union {
HANDLE mutex;
CRITICAL_SECTION criticalSection;
} os;
} epicsMutexOSD;
static BOOL thisIsNT = FALSE;
static LONG weHaveInitialized = 0;
/*
* epicsMutexCreate ()
*/
epicsMutexOSD * epicsMutexOsdCreate ( void )
static epicsThreadOnceId epicsMutexOsdOnce = EPICS_THREAD_ONCE_INIT;
static void epicsMutexOsdInit(void* unused)
{
epicsMutexOSD * pSem;
if ( ! weHaveInitialized ) {
BOOL status;
OSVERSIONINFO osInfo;
osInfo.dwOSVersionInfoSize = sizeof ( OSVERSIONINFO );
status = GetVersionEx ( & osInfo );
thisIsNT = status && ( osInfo.dwPlatformId == VER_PLATFORM_WIN32_NT );
weHaveInitialized = 1;
}
pSem = malloc ( sizeof (*pSem) );
if ( pSem ) {
if ( thisIsNT ) {
InitializeCriticalSection ( &pSem->os.criticalSection );
}
else {
pSem->os.mutex = CreateMutex ( NULL, FALSE, NULL );
if ( pSem->os.mutex == 0 ) {
free ( pSem );
pSem = 0;
}
}
}
return pSem;
(void)unused;
InitializeCriticalSection(&epicsMutexGlobalLock.osd);
}
/*
* epicsMutexOsdDestroy ()
*/
void epicsMutexOsdDestroy ( epicsMutexOSD * pSem )
void epicsMutexOsdSetup()
{
if ( thisIsNT ) {
DeleteCriticalSection ( &pSem->os.criticalSection );
}
else {
CloseHandle ( pSem->os.mutex );
}
free ( pSem );
epicsThreadOnce(&epicsMutexOsdOnce, &epicsMutexOsdInit, NULL);
}
/*
* epicsMutexOsdUnlock ()
*/
void epicsMutexOsdUnlock ( epicsMutexOSD * pSem )
long epicsMutexOsdPrepare(struct epicsMutexParm *mutex)
{
if ( thisIsNT ) {
LeaveCriticalSection ( &pSem->os.criticalSection );
}
else {
BOOL success = ReleaseMutex ( pSem->os.mutex );
assert ( success );
}
InitializeCriticalSection(&mutex->osd);
return 0;
}
/*
* epicsMutexOsdLock ()
*/
epicsMutexLockStatus epicsMutexOsdLock ( epicsMutexOSD * pSem )
void epicsMutexOsdCleanup(struct epicsMutexParm *mutex)
{
if ( thisIsNT ) {
EnterCriticalSection ( &pSem->os.criticalSection );
}
else {
DWORD status = WaitForSingleObject ( pSem->os.mutex, INFINITE );
if ( status != WAIT_OBJECT_0 ) {
return epicsMutexLockError;
}
}
DeleteCriticalSection(&mutex->osd);
}
void epicsStdCall epicsMutexUnlock ( struct epicsMutexParm *mutex )
{
LeaveCriticalSection ( &mutex->osd );
}
epicsMutexLockStatus epicsStdCall epicsMutexLock ( struct epicsMutexParm *mutex )
{
EnterCriticalSection ( &mutex->osd );
return epicsMutexLockOK;
}
/*
* epicsMutexOsdTryLock ()
*/
epicsMutexLockStatus epicsMutexOsdTryLock ( epicsMutexOSD * pSem )
epicsMutexLockStatus epicsStdCall epicsMutexTryLock ( struct epicsMutexParm *mutex )
{
if ( thisIsNT ) {
if ( TryEnterCriticalSection ( &pSem->os.criticalSection ) ) {
return epicsMutexLockOK;
}
else {
return epicsMutexLockTimeout;
}
}
else {
DWORD status = WaitForSingleObject ( pSem->os.mutex, 0 );
if ( status != WAIT_OBJECT_0 ) {
if (status == WAIT_TIMEOUT) {
return epicsMutexLockTimeout;
}
else {
return epicsMutexLockError;
}
}
}
return epicsMutexLockOK;
return TryEnterCriticalSection ( &mutex->osd ) ? epicsMutexLockOK : epicsMutexLockTimeout;
}
/*
* epicsMutexOsdShow ()
*/
void epicsMutexOsdShow ( epicsMutexOSD * pSem, unsigned level )
void epicsMutexOsdShow ( struct epicsMutexParm *mutex, unsigned level )
{
if ( thisIsNT ) {
printf ("epicsMutex: win32 critical section at %p\n",
(void * ) & pSem->os.criticalSection );
}
else {
printf ( "epicsMutex: win32 mutex at %p\n",
( void * ) pSem->os.mutex );
}
(void)level;
printf ("epicsMutex: win32 critical section at %p\n",
(void * ) & mutex->osd );
}
void epicsMutexOsdShowAll(void) {}

View File

@ -25,14 +25,15 @@
#include <pthread.h>
#define EPICS_PRIVATE_API
#define epicsStdioStdStreams
#define epicsStdioStdPrintfEtc
#include "epicsMutex.h"
#include "epicsMutexImpl.h"
#include "osdPosixMutexPriv.h"
#include "cantProceed.h"
#include "epicsTime.h"
#include "errlog.h"
#include "epicsStdio.h"
#include "epicsAssert.h"
#define checkStatus(status,message) \
if((status)) { \
@ -119,62 +120,62 @@ static int mutexLock(pthread_mutex_t *id)
return status;
}
typedef struct epicsMutexOSD {
pthread_mutex_t lock;
} epicsMutexOSD;
/* used if OS does not support statically allocated mutex */
static pthread_once_t epicsMutexOsdOnce = PTHREAD_ONCE_INIT;
epicsMutexOSD * epicsMutexOsdCreate(void) {
epicsMutexOSD *pmutex;
int status;
pmutex = calloc(1, sizeof(*pmutex));
if(!pmutex)
return NULL;
status = osdPosixMutexInit(&pmutex->lock, PTHREAD_MUTEX_RECURSIVE);
if (!status)
return pmutex;
free(pmutex);
return NULL;
static void epicsMutexOsdInit(void)
{
int ret = pthread_mutex_init(&epicsMutexGlobalLock.osd, NULL);
if(ret) {
/* something has gone wrong early. Not much can be done...*/
fprintf(stderr, "osdMutex early init failure %d.\n", ret);
abort();
}
}
void epicsMutexOsdDestroy(struct epicsMutexOSD * pmutex)
void epicsMutexOsdSetup()
{
int status;
int ret = pthread_once(&epicsMutexOsdOnce, &epicsMutexOsdInit);
if(ret) {
/* ditto...*/
fprintf(stderr, "osdMutex early once failure %d.\n", ret);
abort();
}
}
status = pthread_mutex_destroy(&pmutex->lock);
long epicsMutexOsdPrepare(struct epicsMutexParm *pmutex) {
return osdPosixMutexInit(&pmutex->osd, PTHREAD_MUTEX_RECURSIVE);
}
void epicsMutexOsdCleanup(struct epicsMutexParm *pmutex)
{
int status = pthread_mutex_destroy(&pmutex->osd);
checkStatus(status, "pthread_mutex_destroy");
free(pmutex);
}
void epicsMutexOsdUnlock(struct epicsMutexOSD * pmutex)
void epicsMutexUnlock(struct epicsMutexParm * pmutex)
{
int status;
status = pthread_mutex_unlock(&pmutex->lock);
int status = pthread_mutex_unlock(&pmutex->osd);
checkStatus(status, "pthread_mutex_unlock epicsMutexOsdUnlock");
}
epicsMutexLockStatus epicsMutexOsdLock(struct epicsMutexOSD * pmutex)
epicsMutexLockStatus epicsMutexLock(struct epicsMutexParm * pmutex)
{
int status;
status = mutexLock(&pmutex->lock);
int status = mutexLock(&pmutex->osd);
if (status == EINVAL) return epicsMutexLockError;
if(status) {
errlogMessage("epicsMutex pthread_mutex_lock failed: error epicsMutexOsdLock\n");
errlogMessage("epicsMutex pthread_mutex_lock failed: error epicsMutexLock\n");
return epicsMutexLockError;
}
return epicsMutexLockOK;
}
epicsMutexLockStatus epicsMutexOsdTryLock(struct epicsMutexOSD * pmutex)
epicsMutexLockStatus epicsMutexTryLock(struct epicsMutexParm * pmutex)
{
int status;
if (!pmutex) return epicsMutexLockError;
status = pthread_mutex_trylock(&pmutex->lock);
status = pthread_mutex_trylock(&pmutex->osd);
if (status == EINVAL) return epicsMutexLockError;
if (status == EBUSY) return epicsMutexLockTimeout;
if(status) {
@ -184,12 +185,13 @@ epicsMutexLockStatus epicsMutexOsdTryLock(struct epicsMutexOSD * pmutex)
return epicsMutexLockOK;
}
void epicsMutexOsdShow(struct epicsMutexOSD * pmutex, unsigned int level)
void epicsMutexOsdShow(struct epicsMutexParm * pmutex, unsigned int level)
{
(void)level;
/* GLIBC w/ NTPL is passing the &lock.__data.__lock as the first argument (UADDR)
* of the futex() syscall. __lock is at offset 0 of the enclosing structures.
*/
printf(" pthread_mutex_t* uaddr=%p\n", &pmutex->lock);
epicsStdoutPrintf(" pthread_mutex_t* uaddr=%p\n", &pmutex->osd);
}
void epicsMutexOsdShowAll(void)
@ -198,11 +200,11 @@ void epicsMutexOsdShowAll(void)
int proto = -1;
int ret = pthread_mutexattr_getprotocol(&globalAttrRecursive, &proto);
if(ret) {
printf("PI maybe not enabled: %d\n", ret);
epicsStdoutPrintf("PI maybe not enabled: %d\n", ret);
} else {
printf("PI is%s enabled\n", proto==PTHREAD_PRIO_INHERIT ? "" : " not");
epicsStdoutPrintf("PI is%s enabled\n", proto==PTHREAD_PRIO_INHERIT ? "" : " not");
}
#else
printf("PI not supported\n");
epicsStdoutPrintf("PI not supported\n");
#endif
}

View File

@ -13,6 +13,7 @@
#include <vxWorks.h>
#include <semLib.h>
#include <errno.h>
#include <time.h>
#include <objLib.h>
#include <sysLib.h>
@ -23,30 +24,47 @@ int sysClkRateGet(void);
#define EPICS_PRIVATE_API
#include "epicsMutex.h"
struct epicsMutexOSD * epicsMutexOsdCreate(void)
#include "epicsMutexImpl.h"
void epicsMutexOsdSetup(void)
{
return((struct epicsMutexOSD *)
semMCreate(SEM_DELETE_SAFE|SEM_INVERSION_SAFE|SEM_Q_PRIORITY));
if(!epicsMutexGlobalLock.osd) {
epicsMutexOsdPrepare(&epicsMutexGlobalLock);
}
}
void epicsMutexOsdDestroy(struct epicsMutexOSD * id)
long epicsMutexOsdPrepare(struct epicsMutexParm *mutex)
{
semDelete((SEM_ID)id);
mutex->osd = semMCreate(SEM_DELETE_SAFE|SEM_INVERSION_SAFE|SEM_Q_PRIORITY);
return mutex->osd ? 0 : ENOMEM;
}
epicsMutexLockStatus epicsMutexOsdTryLock(struct epicsMutexOSD * id)
void epicsMutexOsdCleanup(struct epicsMutexParm *mutex)
{
int status;
status = semTake((SEM_ID)id,NO_WAIT);
semDelete(mutex->osd);
}
epicsMutexLockStatus epicsMutexLock(struct epicsMutexParm *mutex)
{
return semTake(mutex->osd,WAIT_FOREVER)==OK ? epicsMutexLockOK : epicsMutexLockError;
}
epicsMutexLockStatus epicsMutexTryLock(struct epicsMutexParm *mutex)
{
int status = semTake(mutex->osd,NO_WAIT);
if(status==OK) return(epicsMutexLockOK);
if(errno==S_objLib_OBJ_UNAVAILABLE) return(epicsMutexLockTimeout);
return(epicsMutexLockError);
}
void epicsMutexOsdShow(struct epicsMutexOSD * id,unsigned int level)
void epicsMutexUnlock(struct epicsMutexParm *mutex)
{
semShow((SEM_ID)id,level);
semGive(mutex->osd);
}
void epicsMutexOsdShow(struct epicsMutexParm *mutex,unsigned int level)
{
semShow(mutex->osd,level);
}
void epicsMutexOsdShowAll(void) {}

View File

@ -13,13 +13,3 @@
#include <vxWorks.h>
#include <semLib.h>
/* If the macro is replaced by inline it is necessary to say
static __inline__
but then a warning message appears everywhere osdMutex.h is included
*/
#define epicsMutexOsdUnlock(ID) semGive((SEM_ID)(ID))
#define epicsMutexOsdLock(ID) \
(semTake((SEM_ID)(ID),WAIT_FOREVER)==OK ? epicsMutexLockOK : epicsMutexLockError)