diff --git a/modules/libcom/src/error/errlog.c b/modules/libcom/src/error/errlog.c index 79361e42a..6ae267323 100644 --- a/modules/libcom/src/error/errlog.c +++ b/modules/libcom/src/error/errlog.c @@ -66,6 +66,8 @@ typedef struct listenerNode{ ELLNODE node; errlogListener listener; void *pPrivate; + unsigned active:1; + unsigned removed:1; } listenerNode; typedef struct { @@ -442,9 +444,15 @@ int errlogRemoveListeners(errlogListener listener, void *pPrivate) listenerNode *pnext = (listenerNode *)ellNext(&plistenerNode->node); if (plistenerNode->listener == listener && - plistenerNode->pPrivate == pPrivate) { - ellDelete(&pvt.listenerList, &plistenerNode->node); - free(plistenerNode); + plistenerNode->pPrivate == pPrivate) + { + if(plistenerNode->active) { /* callback removing itself */ + plistenerNode->removed = 1; + + } else { + ellDelete(&pvt.listenerList, &plistenerNode->node); + free(plistenerNode); + } ++count; } plistenerNode = pnext; @@ -674,8 +682,19 @@ static void errlogThread(void) epicsMutexMustLock(pvt.listenerLock); plistenerNode = (listenerNode *)ellFirst(&pvt.listenerList); while (plistenerNode) { + listenerNode *next; + + plistenerNode->active = 1; (*plistenerNode->listener)(plistenerNode->pPrivate, base+1u); - plistenerNode = (listenerNode *)ellNext(&plistenerNode->node); + plistenerNode->active = 0; + + next = (listenerNode *)ellNext(&plistenerNode->node); + if(plistenerNode->removed) { + /* listener() called errlogRemoveListeners() */ + ellDelete(&pvt.listenerList, &plistenerNode->node); + free(plistenerNode); + } + plistenerNode = next; } epicsMutexUnlock(pvt.listenerLock); diff --git a/modules/libcom/src/error/errlog.h b/modules/libcom/src/error/errlog.h index 133fe8be7..7cec39653 100644 --- a/modules/libcom/src/error/errlog.h +++ b/modules/libcom/src/error/errlog.h @@ -178,6 +178,9 @@ LIBCOM_API void errlogAddListener(errlogListener listener, void *pPrivate); * * \param listener Function pointer of type ::errlogListener * \param pPrivate This will be passed as the first argument of listener() + * + * \since UNRELEASED Safe to call from a listener callback. + * \until UNRELEASED Self-removal from a listener callback caused corruption. */ LIBCOM_API int errlogRemoveListeners(errlogListener listener, void *pPrivate);