From 3b7e348a8c7f01d8a7a17a2f604819c65f89cc3c Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 14 May 2018 10:35:16 -0700 Subject: [PATCH] dbUnitTest.h add callback sync. and global mutex Add testSyncCallback() to wait for in queued and in-progress callbacks to complete. Also add testGlobalLock() to help tests avoid use after free when destroying sync. primitives. --- src/ioc/db/callback.c | 84 +++++++++++++++++++++++++++++++++++++++++ src/ioc/db/dbUnitTest.c | 24 ++++++++++++ src/ioc/db/dbUnitTest.h | 59 +++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+) diff --git a/src/ioc/db/callback.c b/src/ioc/db/callback.c index 903ca3f43..b805c1c16 100644 --- a/src/ioc/db/callback.c +++ b/src/ioc/db/callback.c @@ -46,6 +46,7 @@ #include "epicsExport.h" #include "link.h" #include "recSup.h" +#include "dbUnitTest.h" /* for testSyncCallback() */ static int callbackQueueSize = 2000; @@ -353,3 +354,86 @@ void callbackRequestProcessCallbackDelayed(CALLBACK *pcallback, callbackSetProcess(pcallback, Priority, pRec); callbackRequestDelayed(pcallback, seconds); } + +/* Sync. process of testSyncCallback() + * + * 1. For each priority, make a call to callbackRequest() for each worker. + * 2. Wait until all callbacks are concurrently being executed + * 3. Last worker to begin executing signals success and begins waking up other workers + * 4. Last worker to wake signals testSyncCallback() to complete + */ +typedef struct { + epicsEventId wait_phase2, wait_phase4; + int nphase2, nphase3; + epicsCallback cb; +} sync_helper; + +static void sync_callback(epicsCallback *cb) +{ + sync_helper *helper; + callbackGetUser(helper, cb); + + testGlobalLock(); + + assert(helper->nphase2 > 0); + if(--helper->nphase2!=0) { + /* we are _not_ the last to start. */ + testGlobalUnlock(); + epicsEventMustWait(helper->wait_phase2); + testGlobalLock(); + } + + /* we are either the last to start, or have been + * woken by the same and must pass the wakeup along + */ + epicsEventMustTrigger(helper->wait_phase2); + + assert(helper->nphase2 == 0); + assert(helper->nphase3 > 0); + + if(--helper->nphase3==0) { + /* we are the last to wake up. wake up testSyncCallback() */ + epicsEventMustTrigger(helper->wait_phase4); + } + + testGlobalUnlock(); +} + +void testSyncCallback(void) +{ + sync_helper helper[NUM_CALLBACK_PRIORITIES]; + unsigned i; + + testDiag("Begin testSyncCallback()"); + + for(i=0; i