Skip to content

Commit

Permalink
rationalize osdMutex
Browse files Browse the repository at this point in the history
Avoids split allocation.
Eliminates special case free-list.

win32: eliminate pre-XP
rtems-score: eliminate non-fast
  • Loading branch information
mdavidsaver committed Dec 30, 2024
1 parent 1cd141c commit e4ad4be
Show file tree
Hide file tree
Showing 12 changed files with 304 additions and 484 deletions.
4 changes: 0 additions & 4 deletions modules/libcom/src/misc/epicsExit.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@
#include "cantProceed.h"
#include "epicsExit.h"

void epicsMutexCleanup(void);

typedef struct exitNode {
ELLNODE node;
epicsExitFunc func;
Expand Down Expand Up @@ -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)
Expand Down
203 changes: 51 additions & 152 deletions modules/libcom/src/osi/epicsMutex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

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)
Expand Down
15 changes: 0 additions & 15 deletions modules/libcom/src/osi/epicsMutex.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
66 changes: 66 additions & 0 deletions modules/libcom/src/osi/epicsMutexImpl.h
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit e4ad4be

Please sign in to comment.