Skip to content

Commit

Permalink
Merge d475c63 into b41787b
Browse files Browse the repository at this point in the history
  • Loading branch information
mdavidsaver committed Oct 27, 2023
2 parents b41787b + d475c63 commit 89cbc1f
Showing 1 changed file with 34 additions and 17 deletions.
51 changes: 34 additions & 17 deletions modules/database/src/ioc/db/dbEvent.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,10 @@ struct event_que {
struct event_user {
struct event_que firstque; /* the first event que */

ELLLIST waiters; /* event_waiter::node */

epicsMutexId lock;
epicsEventId ppendsem; /* Wait while empty */
epicsEventId pflush_sem; /* wait for flush */
epicsEventId pexitsem; /* wait for event task to join */

EXTRALABORFUNC *extralabor_sub;/* off load to event task */
Expand All @@ -101,6 +102,11 @@ struct event_user {
epicsThreadId init_func_arg;
};

typedef struct {
ELLNODE node; /* event_user::waiters */
epicsEventId wake;
} event_waiter;

/*
* Reliable intertask communication requires copying the current value of the
* channel for later queuing so 3 stepper motor steps of 10 each do not turn
Expand Down Expand Up @@ -306,9 +312,6 @@ dbEventCtx db_init_events (void)
evUser->ppendsem = epicsEventCreate(epicsEventEmpty);
if (!evUser->ppendsem)
goto fail;
evUser->pflush_sem = epicsEventCreate(epicsEventEmpty);
if (!evUser->pflush_sem)
goto fail;
evUser->lock = epicsMutexCreate();
if (!evUser->lock)
goto fail;
Expand All @@ -326,8 +329,6 @@ dbEventCtx db_init_events (void)
epicsMutexDestroy (evUser->firstque.writelock);
if(evUser->ppendsem)
epicsEventDestroy (evUser->ppendsem);
if(evUser->pflush_sem)
epicsEventDestroy (evUser->pflush_sem);
if(evUser->pexitsem)
epicsEventDestroy (evUser->pexitsem);
freeListFree(dbevEventUserFreeList,evUser);
Expand Down Expand Up @@ -391,7 +392,6 @@ void db_close_events (dbEventCtx ctx)

epicsEventDestroy(evUser->pexitsem);
epicsEventDestroy(evUser->ppendsem);
epicsEventDestroy(evUser->pflush_sem);
epicsMutexDestroy(evUser->lock);

epicsMutexUnlock (stopSync);
Expand Down Expand Up @@ -592,23 +592,33 @@ void db_cancel_event (dbEventSubscription event)
UNLOCKEVQUE (que);

if(sync) {
/* wait for worker to cycle */
/* cycle through worker */
struct event_user *evUser = que->evUser;
epicsUInt32 curSeq;
event_waiter wait;
wait.wake = epicsEventCreate(epicsEventEmpty); /* may fail */

epicsMutexMustLock ( evUser->lock );
ellAdd(&evUser->waiters, &wait.node);
/* grab current cycle counter, then wait for it to change */
curSeq = evUser->pflush_seq;
do {
epicsMutexUnlock( evUser->lock );
epicsEventMustWait(evUser->pflush_sem);
/* The complexity needed to track the # of waiters does not seem
* worth it for the relatively rare situation of concurrent cancel.
* So uncondtionally re-trigger. This will result in one spurious
* wakeup for each cancellation.
*/
epicsEventTrigger(evUser->pflush_sem);
/* ensure worker will cycle at least once */
epicsEventMustTrigger(evUser->ppendsem);

if(wait.wake) {
epicsEventMustWait(wait.wake);
} else {
epicsThreadSleep(0.01); /* ick. but better than cantProceed() */
}

epicsMutexMustLock ( evUser->lock );
} while(curSeq == evUser->pflush_seq);
ellDelete(&evUser->waiters, &wait.node);
/* destroy under lock to ensure epicsEventMustTrigger() has returned */
if(wait.wake)
epicsEventDestroy(wait.wake);
epicsMutexUnlock( evUser->lock );
}
}
Expand Down Expand Up @@ -1041,11 +1051,18 @@ static void event_task (void *pParm)
pendexit = evUser->pendexit;

evUser->pflush_seq++;
if(ellCount(&evUser->waiters)) {
/* hold lock throughout to avoid race between event trigger and destroy */
ELLNODE *cur;
for(cur = ellFirst(&evUser->waiters); cur; cur = ellNext(cur)) {
event_waiter *w = CONTAINER(cur, event_waiter, node);
if(w->wake)
epicsEventMustTrigger(w->wake);
}
}

epicsMutexUnlock ( evUser->lock );

epicsEventSignal(evUser->pflush_sem);

} while( ! pendexit );

epicsMutexDestroy(evUser->firstque.writelock);
Expand Down

0 comments on commit 89cbc1f

Please sign in to comment.