errlogRemoveListeners() handle self-removal

Handle errlogRemoveListeners() during a callback.
This commit is contained in:
Michael Davidsaver
2022-11-15 07:59:22 -08:00
parent 7448a8bfa9
commit 49fddaa13e
2 changed files with 26 additions and 4 deletions

View File

@@ -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);

View File

@@ -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);