diff --git a/modules/libcom/src/misc/epicsExit.c b/modules/libcom/src/misc/epicsExit.c index 4e22fd81d5..a7e1e47577 100644 --- a/modules/libcom/src/misc/epicsExit.c +++ b/modules/libcom/src/misc/epicsExit.c @@ -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) diff --git a/modules/libcom/src/osi/epicsMutex.cpp b/modules/libcom/src/osi/epicsMutex.cpp index 0a63a6f33d..a97de60674 100644 --- a/modules/libcom/src/osi/epicsMutex.cpp +++ b/modules/libcom/src/osi/epicsMutex.cpp @@ -26,30 +26,23 @@ #include #include +#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, "" ); - } - 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; - - if (epicsMutexOsiOnce == EPICS_THREAD_ONCE_INIT) - return; + epicsMutexOsdSetup(); - 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) diff --git a/modules/libcom/src/osi/epicsMutex.h b/modules/libcom/src/osi/epicsMutex.h index 41f73a4bce..117767a488 100644 --- a/modules/libcom/src/osi/epicsMutex.h +++ b/modules/libcom/src/osi/epicsMutex.h @@ -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 diff --git a/modules/libcom/src/osi/epicsMutexImpl.h b/modules/libcom/src/osi/epicsMutexImpl.h new file mode 100644 index 0000000000..91079e8c52 --- /dev/null +++ b/modules/libcom/src/osi/epicsMutexImpl.h @@ -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 +# include +#elif defined(_WIN32) +# define VC_EXTRALEAN +# define WIN32_LEAN_AND_MEAN +# include +#elif defined(__rtems__) +# include +# include +#else +# include +#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 diff --git a/modules/libcom/src/osi/os/RTEMS-score/osdEvent.c b/modules/libcom/src/osi/os/RTEMS-score/osdEvent.c index 277e7882f4..e91db8a90f 100644 --- a/modules/libcom/src/osi/os/RTEMS-score/osdEvent.c +++ b/modules/libcom/src/osi/os/RTEMS-score/osdEvent.c @@ -26,6 +26,7 @@ #include "epicsEvent.h" #include "epicsThread.h" +#include "rtemsNamePvt.h" #include "errlog.h" /* #define EPICS_RTEMS_SEMAPHORE_STATS */ @@ -48,11 +49,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 +61,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; } diff --git a/modules/libcom/src/osi/os/RTEMS-score/osdMutex.c b/modules/libcom/src/osi/os/RTEMS-score/osdMutex.c index 44adf2f6ea..74fad8f814 100644 --- a/modules/libcom/src/osi/os/RTEMS-score/osdMutex.c +++ b/modules/libcom/src/osi/os/RTEMS-score/osdMutex.c @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -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 - -struct epicsMutexOSD * -epicsMutexOsdCreate(void) +uint32_t next_rtems_name(char prefix, uint32_t* counter) +{ + uint32_t next; + rtems_interrupt_level level; + char a, b, c; + + 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) {} diff --git a/modules/libcom/src/osi/os/RTEMS-score/osdThread.c b/modules/libcom/src/osi/os/RTEMS-score/osdThread.c index 7d37bbe481..e34717a365 100644 --- a/modules/libcom/src/osi/os/RTEMS-score/osdThread.c +++ b/modules/libcom/src/osi/os/RTEMS-score/osdThread.c @@ -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); } /* diff --git a/modules/libcom/src/osi/os/RTEMS-score/rtemsNamePvt.h b/modules/libcom/src/osi/os/RTEMS-score/rtemsNamePvt.h new file mode 100644 index 0000000000..436728902f --- /dev/null +++ b/modules/libcom/src/osi/os/RTEMS-score/rtemsNamePvt.h @@ -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 + +/* 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 diff --git a/modules/libcom/src/osi/os/WIN32/osdMutex.c b/modules/libcom/src/osi/os/WIN32/osdMutex.c index b18e849f49..ce2c615ebe 100644 --- a/modules/libcom/src/osi/os/WIN32/osdMutex.c +++ b/modules/libcom/src/osi/os/WIN32/osdMutex.c @@ -20,147 +20,59 @@ #include #include -#define VC_EXTRALEAN -#define STRICT -#include -#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; + (void)unused; + InitializeCriticalSection(&epicsMutexGlobalLock.osd); +} - if ( ! weHaveInitialized ) { - BOOL status; - OSVERSIONINFO osInfo; - osInfo.dwOSVersionInfoSize = sizeof ( OSVERSIONINFO ); - status = GetVersionEx ( & osInfo ); - thisIsNT = status && ( osInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ); - weHaveInitialized = 1; - } +void epicsMutexOsdSetup() +{ + epicsThreadOnce(&epicsMutexOsdOnce, &epicsMutexOsdInit, NULL); +} - 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; +long epicsMutexOsdPrepare(struct epicsMutexParm *mutex) +{ + InitializeCriticalSection(&mutex->osd); + return 0; } -/* - * epicsMutexOsdDestroy () - */ -void epicsMutexOsdDestroy ( epicsMutexOSD * pSem ) +void epicsMutexOsdCleanup(struct epicsMutexParm *mutex) { - if ( thisIsNT ) { - DeleteCriticalSection ( &pSem->os.criticalSection ); - } - else { - CloseHandle ( pSem->os.mutex ); - } - free ( pSem ); + DeleteCriticalSection(&mutex->osd); } -/* - * epicsMutexOsdUnlock () - */ -void epicsMutexOsdUnlock ( epicsMutexOSD * pSem ) +void epicsStdCall epicsMutexUnlock ( struct epicsMutexParm *mutex ) { - if ( thisIsNT ) { - LeaveCriticalSection ( &pSem->os.criticalSection ); - } - else { - BOOL success = ReleaseMutex ( pSem->os.mutex ); - assert ( success ); - } + LeaveCriticalSection ( &mutex->osd ); } -/* - * epicsMutexOsdLock () - */ -epicsMutexLockStatus epicsMutexOsdLock ( epicsMutexOSD * pSem ) +epicsMutexLockStatus epicsStdCall epicsMutexLock ( struct epicsMutexParm *mutex ) { - if ( thisIsNT ) { - EnterCriticalSection ( &pSem->os.criticalSection ); - } - else { - DWORD status = WaitForSingleObject ( pSem->os.mutex, INFINITE ); - if ( status != WAIT_OBJECT_0 ) { - return epicsMutexLockError; - } - } + 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) {} diff --git a/modules/libcom/src/osi/os/posix/osdMutex.c b/modules/libcom/src/osi/os/posix/osdMutex.c index 85040c5f40..4bd87cf880 100644 --- a/modules/libcom/src/osi/os/posix/osdMutex.c +++ b/modules/libcom/src/osi/os/posix/osdMutex.c @@ -25,14 +25,15 @@ #include #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; +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(); + } +} - status = osdPosixMutexInit(&pmutex->lock, PTHREAD_MUTEX_RECURSIVE); - if (!status) - return pmutex; +void epicsMutexOsdSetup() +{ + int ret = pthread_once(&epicsMutexOsdOnce, &epicsMutexOsdInit); + if(ret) { + /* ditto...*/ + fprintf(stderr, "osdMutex early once failure %d.\n", ret); + abort(); + } +} - free(pmutex); - return NULL; +long epicsMutexOsdPrepare(struct epicsMutexParm *pmutex) { + return osdPosixMutexInit(&pmutex->osd, PTHREAD_MUTEX_RECURSIVE); } -void epicsMutexOsdDestroy(struct epicsMutexOSD * pmutex) +void epicsMutexOsdCleanup(struct epicsMutexParm *pmutex) { - int status; - - status = pthread_mutex_destroy(&pmutex->lock); + 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 } diff --git a/modules/libcom/src/osi/os/vxWorks/osdMutex.c b/modules/libcom/src/osi/os/vxWorks/osdMutex.c index d772bf2dd2..680f9e6632 100644 --- a/modules/libcom/src/osi/os/vxWorks/osdMutex.c +++ b/modules/libcom/src/osi/os/vxWorks/osdMutex.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -23,30 +24,47 @@ int sysClkRateGet(void); #define EPICS_PRIVATE_API #include "epicsMutex.h" - -struct epicsMutexOSD * epicsMutexOsdCreate(void) +#include "epicsMutexImpl.h" + +void epicsMutexOsdSetup(void) +{ + if(!epicsMutexGlobalLock.osd) { + epicsMutexOsdPrepare(&epicsMutexGlobalLock); + } +} + +long epicsMutexOsdPrepare(struct epicsMutexParm *mutex) +{ + mutex->osd = semMCreate(SEM_DELETE_SAFE|SEM_INVERSION_SAFE|SEM_Q_PRIORITY); + return mutex->osd ? 0 : ENOMEM; +} + +void epicsMutexOsdCleanup(struct epicsMutexParm *mutex) { - return((struct epicsMutexOSD *) - semMCreate(SEM_DELETE_SAFE|SEM_INVERSION_SAFE|SEM_Q_PRIORITY)); + semDelete(mutex->osd); } -void epicsMutexOsdDestroy(struct epicsMutexOSD * id) +epicsMutexLockStatus epicsMutexLock(struct epicsMutexParm *mutex) { - semDelete((SEM_ID)id); + return semTake(mutex->osd,WAIT_FOREVER)==OK ? epicsMutexLockOK : epicsMutexLockError; } -epicsMutexLockStatus epicsMutexOsdTryLock(struct epicsMutexOSD * id) +epicsMutexLockStatus epicsMutexTryLock(struct epicsMutexParm *mutex) { - int status; - status = semTake((SEM_ID)id,NO_WAIT); + 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) +{ + semGive(mutex->osd); +} + +void epicsMutexOsdShow(struct epicsMutexParm *mutex,unsigned int level) { - semShow((SEM_ID)id,level); + semShow(mutex->osd,level); } void epicsMutexOsdShowAll(void) {} diff --git a/modules/libcom/src/osi/os/vxWorks/osdMutex.h b/modules/libcom/src/osi/os/vxWorks/osdMutex.h index 2eb8b1ba29..f3f6636228 100644 --- a/modules/libcom/src/osi/os/vxWorks/osdMutex.h +++ b/modules/libcom/src/osi/os/vxWorks/osdMutex.h @@ -13,13 +13,3 @@ #include #include - -/* 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)