Experimental Physics and Industrial Control System
Subject: |
[Merge] lp:~epics-core/epics-base/ioc-shutdown2 into lp:epics-base |
From: |
mdavidsaver <[email protected]> |
To: |
[email protected] |
Date: |
Mon, 23 Jun 2014 20:40:31 -0000 |
mdavidsaver has proposed merging lp:~epics-core/epics-base/ioc-shutdown2 into lp:epics-base.
Requested reviews:
EPICS Core Developers (epics-core)
For more details, see:
https://code.launchpad.net/~epics-core/epics-base/ioc-shutdown2/+merge/224213
As discussed, I re-based the changes from ioc-shutdown with some additional cleanup, and removed the epicsThreadOnceReset function.
--
https://code.launchpad.net/~epics-core/epics-base/ioc-shutdown2/+merge/224213
Your team EPICS Core Developers is requested to review the proposed merge of lp:~epics-core/epics-base/ioc-shutdown2 into lp:epics-base.
=== modified file 'src/Makefile'
--- src/Makefile 2012-06-22 23:16:26 +0000
+++ src/Makefile 2014-06-23 20:39:40 +0000
@@ -62,7 +62,7 @@
ioc_DEPEND_DIRS = libCom ca/client
DIRS += ioc/db/test
-ioc/db/test_DEPEND_DIRS = ioc libCom/RTEMS
+ioc/db/test_DEPEND_DIRS = ioc std libCom/RTEMS
DIRS += ioc/dbtemplate/test
ioc/dbtemplate/test_DEPEND_DIRS = ioc
=== modified file 'src/ioc/as/asDbLib.c'
--- src/ioc/as/asDbLib.c 2012-10-01 05:54:10 +0000
+++ src/ioc/as/asDbLib.c 2014-06-23 20:39:40 +0000
@@ -152,6 +152,15 @@
return(asInitCommon());
}
+int asShutdown(void) {
+ volatile ASBASE *pbase = pasbase;
+ pasbase = NULL;
+ firstTime = TRUE;
+ if(pbase)
+ asFreeAll((ASBASE*)pbase);
+ return 0;
+}
+
static void wdCallback(void *arg)
{
ASDBCALLBACK *pcallback = (ASDBCALLBACK *)arg;
=== modified file 'src/ioc/as/asDbLib.h'
--- src/ioc/as/asDbLib.h 2012-07-15 21:08:50 +0000
+++ src/ioc/as/asDbLib.h 2014-06-23 20:39:40 +0000
@@ -32,6 +32,7 @@
epicsShareFunc int asSetSubstitutions(const char *substitutions);
epicsShareFunc int asInit(void);
epicsShareFunc int asInitAsyn(ASDBCALLBACK *pcallback);
+epicsShareFunc int asShutdown(void);
epicsShareFunc int asDbGetAsl(struct dbChannel *chan);
epicsShareFunc void * asDbGetMemberPvt(struct dbChannel *chan);
epicsShareFunc int asdbdump(void);
=== modified file 'src/ioc/db/Makefile'
--- src/ioc/db/Makefile 2012-11-29 18:53:21 +0000
+++ src/ioc/db/Makefile 2014-06-23 20:39:40 +0000
@@ -37,6 +37,7 @@
INC += dbState.h
INC += db_access_routines.h
INC += db_convert.h
+INC += dbUnitTest.h
# Generate menuGlobal.dbd automatically
DBD += menuGlobal.dbd
@@ -86,4 +87,4 @@
dbCore_SRCS += dbIocRegister.c
dbCore_SRCS += chfPlugin.c
dbCore_SRCS += dbState.c
-
+dbCore_SRCS += dbUnitTest.c
=== modified file 'src/ioc/db/callback.c'
--- src/ioc/db/callback.c 2012-05-04 22:34:48 +0000
+++ src/ioc/db/callback.c 2014-06-23 20:39:40 +0000
@@ -43,7 +43,6 @@
#include "callback.h"
-static epicsThreadOnceId callbackOnceFlag = EPICS_THREAD_ONCE_INIT;
static int callbackQueueSize = 2000;
static epicsEventId callbackSem[NUM_CALLBACK_PRIORITIES];
static epicsRingPointerId callbackQ[NUM_CALLBACK_PRIORITIES];
@@ -53,6 +52,8 @@
static epicsTimerQueueId timerQueue;
/* Shutdown handling */
+enum ctl {ctlInit, ctlRun, ctlPause, ctlExit};
+static volatile enum ctl cbCtl;
static epicsEventId startStopEvent;
static void *exitCallback;
@@ -70,7 +71,7 @@
int callbackSetQueueSize(int size)
{
- if (callbackOnceFlag != EPICS_THREAD_ONCE_INIT) {
+ if (startStopEvent) {
errlogPrintf("Callback system already initialized\n");
return -1;
}
@@ -101,24 +102,36 @@
epicsEventSignal(startStopEvent);
}
-static void callbackShutdown(void *arg)
+void callbackShutdown(void)
{
int i;
+ if (cbCtl == ctlExit) return;
+ cbCtl = ctlExit;
+
for (i = 0; i < NUM_CALLBACK_PRIORITIES; i++) {
int lockKey = epicsInterruptLock();
int ok = epicsRingPointerPush(callbackQ[i], &exitCallback);
epicsInterruptUnlock(lockKey);
epicsEventSignal(callbackSem[i]);
if (ok) epicsEventWait(startStopEvent);
+ epicsEventDestroy(callbackSem[i]);
+ epicsRingPointerDelete(callbackQ[i]);
}
+ epicsTimerQueueRelease(timerQueue);
+ epicsEventDestroy(startStopEvent);
+ startStopEvent = NULL;
}
-static void callbackInitOnce(void *arg)
+void callbackInit(void)
{
int i;
+ if(startStopEvent)
+ return;
+
startStopEvent = epicsEventMustCreate(epicsEventEmpty);
+ cbCtl = ctlRun;
timerQueue = epicsTimerQueueAllocate(0,epicsThreadPriorityScanHigh);
for (i = 0; i < NUM_CALLBACK_PRIORITIES; i++) {
epicsThreadId tid;
@@ -137,12 +150,6 @@
else
epicsEventWait(startStopEvent);
}
- epicsAtExit(callbackShutdown, NULL);
-}
-
-void callbackInit(void)
-{
- epicsThreadOnce(&callbackOnceFlag, callbackInitOnce, NULL);
}
/* This routine can be called from interrupt context */
=== modified file 'src/ioc/db/callback.h'
--- src/ioc/db/callback.h 2010-10-05 19:27:37 +0000
+++ src/ioc/db/callback.h 2014-06-23 20:39:40 +0000
@@ -57,6 +57,7 @@
epicsShareFunc void callbackInit(void);
epicsShareFunc void callbackRequest(CALLBACK *pCallback);
+epicsShareFunc void callbackShutdown(void);
epicsShareFunc void callbackSetProcess(
CALLBACK *pcallback, int Priority, void *pRec);
epicsShareFunc void callbackRequestProcessCallback(
=== modified file 'src/ioc/db/dbBkpt.c'
--- src/ioc/db/dbBkpt.c 2014-06-04 19:18:43 +0000
+++ src/ioc/db/dbBkpt.c 2014-06-23 20:39:40 +0000
@@ -61,6 +61,7 @@
#include "errMdef.h"
#include "recSup.h"
#include "special.h"
+#include "epicsExit.h"
#define epicsExportSharedSymbols
#include "dbAddr.h"
#include "dbAccessDefs.h"
@@ -250,7 +251,11 @@
return(0);
}
-
+static void dbBkptExit(void *junk) {
+ epicsMutexDestroy(bkpt_stack_sem);
+ bkpt_stack_sem = NULL;
+}
+
/*
* Initialise the breakpoint stack
*/
@@ -259,6 +264,7 @@
if (! bkpt_stack_sem) {
bkpt_stack_sem = epicsMutexMustCreate();
lset_stack_count = 0;
+ epicsAtExit(dbBkptExit, NULL);
}
}
=== modified file 'src/ioc/db/dbCa.c'
--- src/ioc/db/dbCa.c 2014-06-04 19:18:43 +0000
+++ src/ioc/db/dbCa.c 2014-06-23 20:39:40 +0000
@@ -173,15 +173,22 @@
dbScanUnlock(pdbCommon);
}
-static void dbCaShutdown(void *arg)
+void dbCaShutdown(void)
{
- if (dbCaCtl == ctlRun) {
+ if (dbCaCtl == ctlRun || dbCaCtl == ctlPause) {
dbCaCtl = ctlExit;
epicsEventSignal(workListEvent);
epicsEventMustWait(startStopEvent);
+ epicsEventDestroy(startStopEvent);
+ epicsEventDestroy(workListEvent);
}
}
+static void dbCaExit(void *arg)
+{
+ dbCaShutdown();
+}
+
void dbCaLinkInit(void)
{
dbServiceIOInit();
@@ -194,19 +201,23 @@
epicsThreadGetStackSize(epicsThreadStackBig),
dbCaTask, NULL);
epicsEventMustWait(startStopEvent);
- epicsAtExit(dbCaShutdown, NULL);
+ epicsAtExit(dbCaExit, NULL);
}
void dbCaRun(void)
{
- dbCaCtl = ctlRun;
- epicsEventSignal(workListEvent);
+ if (dbCaCtl == ctlPause) {
+ dbCaCtl = ctlRun;
+ epicsEventSignal(workListEvent);
+ }
}
void dbCaPause(void)
{
- dbCaCtl = ctlPause;
- epicsEventSignal(workListEvent);
+ if (dbCaCtl == ctlRun) {
+ dbCaCtl = ctlPause;
+ epicsEventSignal(workListEvent);
+ }
}
void dbCaAddLinkCallback(struct link *plink,
=== modified file 'src/ioc/db/dbCa.h'
--- src/ioc/db/dbCa.h 2012-04-27 17:21:47 +0000
+++ src/ioc/db/dbCa.h 2014-06-23 20:39:40 +0000
@@ -26,6 +26,7 @@
epicsShareFunc void dbCaLinkInit(void);
epicsShareFunc void dbCaRun(void);
epicsShareFunc void dbCaPause(void);
+epicsShareFunc void dbCaShutdown(void);
epicsShareFunc void dbCaAddLinkCallback(struct link *plink,
dbCaCallback connect, dbCaCallback monitor, void *userPvt);
=== modified file 'src/ioc/db/dbChannel.c'
--- src/ioc/db/dbChannel.c 2014-06-04 13:56:51 +0000
+++ src/ioc/db/dbChannel.c 2014-06-23 20:39:40 +0000
@@ -20,6 +20,7 @@
#include "cantProceed.h"
#include "epicsAssert.h"
#include "epicsString.h"
+#include "epicsExit.h"
#include "errlog.h"
#include "freeList.h"
#include "gpHash.h"
@@ -52,16 +53,23 @@
static void *chFilterFreeList;
static void *dbchStringFreeList;
+static void dbChannelExit(void* junk)
+{
+ freeListCleanup(dbChannelFreeList);
+ freeListCleanup(chFilterFreeList);
+ freeListCleanup(dbchStringFreeList);
+ dbChannelFreeList = chFilterFreeList = dbchStringFreeList = NULL;
+}
+
void dbChannelInit (void)
{
- static int done = 0;
+ if(dbChannelFreeList)
+ return;
- if (!done) {
- done = 1;
- freeListInitPvt(&dbChannelFreeList, sizeof(dbChannel), 128);
- freeListInitPvt(&chFilterFreeList, sizeof(chFilter), 64);
- freeListInitPvt(&dbchStringFreeList, sizeof(epicsOldString), 128);
- }
+ freeListInitPvt(&dbChannelFreeList, sizeof(dbChannel), 128);
+ freeListInitPvt(&chFilterFreeList, sizeof(chFilter), 64);
+ freeListInitPvt(&dbchStringFreeList, sizeof(epicsOldString), 128);
+ epicsAtExit(dbChannelExit, NULL);
}
static void chf_value(parseContext *parser, parse_result *presult)
=== modified file 'src/ioc/db/dbLock.c'
--- src/ioc/db/dbLock.c 2012-07-15 21:08:50 +0000
+++ src/ioc/db/dbLock.c 2014-06-23 20:39:40 +0000
@@ -54,6 +54,7 @@
#include "epicsMutex.h"
#include "epicsThread.h"
#include "epicsAssert.h"
+#include "epicsExit.h"
#include "cantProceed.h"
#include "ellLib.h"
#define epicsExportSharedSymbols
@@ -107,7 +108,16 @@
lockSet *plockSet;
dbCommon *precord;
} lockRecord;
-
+
+static void dbLockExit(void *junk)
+{
+ epicsMutexDestroy(globalLock);
+ epicsMutexDestroy(lockSetModifyLock);
+ globalLock = NULL;
+ lockSetModifyLock = NULL;
+ dbLockIsInitialized = FALSE;
+}
+
/*private routines */
static void dbLockInitialize(void)
{
@@ -118,6 +128,7 @@
globalLock = epicsMutexMustCreate();
lockSetModifyLock = epicsMutexMustCreate();
dbLockIsInitialized = TRUE;
+ epicsAtExit(dbLockExit,NULL);
}
static lockSet * allocLockSet(
@@ -377,7 +388,23 @@
}
}
}
-
+
+void dbLockCleanupRecords(dbBase *pdbbase)
+{
+ DBENTRY ent;
+ long status;
+
+ dbInitEntry(pdbbase, &ent);
+ for(status=dbFirstRecordType(&ent); !status; status=dbNextRecordType(&ent)) {
+ for(status=dbFirstRecord(&ent); !status; status=dbNextRecord(&ent)) {
+ dbCommon *prec = ent.precnode->precord;
+ free(prec->lset);
+ }
+ }
+
+ dbFinishEntry(&ent);
+}
+
void dbLockSetMerge(dbCommon *pfirst,dbCommon *psecond)
{
lockRecord *p1lockRecord = pfirst->lset;
=== modified file 'src/ioc/db/dbLock.h'
--- src/ioc/db/dbLock.h 2012-07-15 21:08:50 +0000
+++ src/ioc/db/dbLock.h 2014-06-23 20:39:40 +0000
@@ -28,6 +28,7 @@
struct dbCommon *precord);
epicsShareFunc void dbLockInitRecords(struct dbBase *pdbbase);
+epicsShareFunc void dbLockCleanupRecords(struct dbBase *pdbbase);
epicsShareFunc void dbLockSetMerge(
struct dbCommon *pfirst,struct dbCommon *psecond);
epicsShareFunc void dbLockSetSplit(struct dbCommon *psource);
=== modified file 'src/ioc/db/dbNotify.c'
--- src/ioc/db/dbNotify.c 2012-07-15 21:08:50 +0000
+++ src/ioc/db/dbNotify.c 2014-06-23 20:39:40 +0000
@@ -44,6 +44,7 @@
#include "recGbl.h"
#include "dbNotify.h"
#include "epicsTime.h"
+#include "epicsExit.h"
#include "cantProceed.h"
/*notify state values */
@@ -298,6 +299,14 @@
callDone(precord, ppn);
}
+static void dbProcessNotifyExit(void* junk)
+{
+ assert(ellCount(&pnotifyGlobal->freeList)==0);
+ epicsMutexDestroy(pnotifyGlobal->lock);
+ free(pnotifyGlobal);
+ pnotifyGlobal = NULL;
+}
+
void dbProcessNotifyInit(void)
{
if (pnotifyGlobal)
@@ -305,6 +314,7 @@
pnotifyGlobal = dbCalloc(1,sizeof(notifyGlobal));
pnotifyGlobal->lock = epicsMutexMustCreate();
ellInit(&pnotifyGlobal->freeList);
+ epicsAtExit(dbProcessNotifyExit, NULL);
}
void dbProcessNotify(processNotify *ppn)
=== modified file 'src/ioc/db/dbScan.c'
--- src/ioc/db/dbScan.c 2013-12-17 18:54:04 +0000
+++ src/ioc/db/dbScan.c 2014-06-23 20:39:40 +0000
@@ -3,6 +3,8 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
+* Copyright (c) 2013 Helmholtz-Zentrum Berlin
+* für Materialien und Energie GmbH.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
@@ -132,6 +134,7 @@
static void initOnce(void);
static void periodicTask(void *arg);
static void initPeriodic(void);
+static void deletePeriodic(void);
static void spawnPeriodic(int ind);
static void initEvent(void);
static void eventCallback(CALLBACK *pcallback);
@@ -142,10 +145,13 @@
static void addToList(struct dbCommon *precord, scan_list *psl);
static void deleteFromList(struct dbCommon *precord, scan_list *psl);
-static void scanShutdown(void *arg)
+void scanShutdown(void)
{
int i;
+ if (scanCtl == ctlExit) return;
+ scanCtl = ctlExit;
+
interruptAccept = FALSE;
for (i = 0; i < nPeriodic; i++) {
@@ -156,6 +162,18 @@
scanOnce((dbCommon *)&exitOnce);
epicsEventWait(startStopEvent);
+
+ deletePeriodic();
+
+ epicsRingPointerDelete(onceQ);
+
+ epicsEventDestroy(startStopEvent);
+ epicsEventDestroy(onceSem);
+ onceSem = startStopEvent = NULL;
+
+ free(periodicTaskId);
+ papPeriodic = NULL;
+ periodicTaskId = NULL;
}
long scanInit(void)
@@ -172,7 +190,6 @@
for (i = 0; i < nPeriodic; i++)
spawnPeriodic(i);
- epicsAtExit(scanShutdown, NULL);
return 0;
}
@@ -696,6 +713,22 @@
}
}
+static void deletePeriodic(void)
+{
+ int i;
+
+ for (i = 0; i < nPeriodic; i++) {
+ periodic_scan_list *ppsl = papPeriodic[i];
+ ellFree(&ppsl->scan_list.list);
+ epicsEventDestroy(ppsl->loopEvent);
+ epicsMutexDestroy(ppsl->scan_list.lock);
+ free(ppsl);
+ }
+
+ free(papPeriodic);
+ papPeriodic = NULL;
+}
+
static void spawnPeriodic(int ind)
{
periodic_scan_list *ppsl;
@@ -802,23 +835,25 @@
{
dbRecordType *pdbRecordType;
- /*Look for first record*/
for (pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
pdbRecordType;
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
dbRecordNode *pdbRecordNode;
+
for (pdbRecordNode = (dbRecordNode *)ellFirst(&pdbRecordType->recList);
pdbRecordNode;
pdbRecordNode = (dbRecordNode *)ellNext(&pdbRecordNode->node)) {
dbCommon *precord = pdbRecordNode->precord;
+
if (!precord->name[0] ||
pdbRecordNode->flags & DBRN_FLAGS_ISALIAS)
continue;
+
scanAdd(precord);
}
}
}
-
+
static void addToList(struct dbCommon *precord, scan_list *psl)
{
scan_element *pse, *ptemp;
=== modified file 'src/ioc/db/dbScan.h'
--- src/ioc/db/dbScan.h 2012-04-10 22:10:50 +0000
+++ src/ioc/db/dbScan.h 2014-06-23 20:39:40 +0000
@@ -44,6 +44,7 @@
epicsShareFunc long scanInit(void);
epicsShareFunc void scanRun(void);
epicsShareFunc void scanPause(void);
+epicsShareFunc void scanShutdown(void);
epicsShareFunc EVENTPVT eventNameToHandle(const char* event);
epicsShareFunc void postEvent(EVENTPVT epvt);
=== added file 'src/ioc/db/dbUnitTest.c'
--- src/ioc/db/dbUnitTest.c 1970-01-01 00:00:00 +0000
+++ src/ioc/db/dbUnitTest.c 2014-06-23 20:39:40 +0000
@@ -0,0 +1,123 @@
+/*************************************************************************\
+* Copyright (c) 2013 Brookhaven National Laboratory.
+* Copyright (c) 2013 ITER Organization.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+ \*************************************************************************/
+
+/*
+ * Author: Michael Davidsaver <[email protected]>
+ * Ralph Lange <[email protected]>
+ */
+
+#include <string.h>
+
+#include "epicsUnitTest.h"
+#include "osiFileName.h"
+#include "dbmf.h"
+#include "registry.h"
+#define epicsExportSharedSymbols
+#include "iocInit.h"
+#include "initHooks.h"
+#include "dbBase.h"
+#include "dbAccess.h"
+#include "dbStaticLib.h"
+
+#include "dbUnitTest.h"
+
+void testdbPrepare(void)
+{
+ /* No-op at the moment */
+}
+
+void testdbReadDatabase(const char* file,
+ const char* path,
+ const char* substitutions)
+{
+ if(!path)
+ path = "." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR
+ "../O.Common" OSI_PATH_LIST_SEPARATOR "O.Common";
+ if(dbReadDatabase(&pdbbase, file, path, substitutions))
+ testAbort("Failed to load test database\ndbReadDatabase(%s,%s,%s)",
+ file, path, substitutions);
+}
+
+int testiocInit(void)
+{
+ return iocBuildNoCA() || iocRun();
+}
+
+int testiocShutdown(void)
+{
+ return iocShutdown();
+}
+
+void testdbCleanup(void)
+{
+ dbFreeBase(pdbbase);
+ initHookFree();
+ registryFree();
+ pdbbase = NULL;
+ dbmfFreeChunks();
+}
+
+long testdbPutField(const char* pv, short dbrType, ...)
+{
+ long ret;
+ va_list ap;
+ va_start(ap, dbrType);
+ ret = testVdbPutField(pv, dbrType, ap);
+ va_end(ap);
+ return ret;
+}
+
+union anybuf {
+ epicsAny val;
+ char bytes[sizeof(epicsAny)];
+};
+
+long testVdbPutField(const char* pv, short dbrType, va_list ap)
+{
+ DBADDR addr;
+ union anybuf pod;
+
+ if(dbNameToAddr(pv, &addr))
+ testAbort("Missing PV %s", pv);
+
+ switch(dbrType) {
+ case DBR_STRING: {
+ const char *uarg = va_arg(ap,char*);
+ epicsOldString buffer;
+ strncpy(buffer, uarg, sizeof(buffer));
+ buffer[sizeof(buffer)-1] = '\0';
+ return dbPutField(&addr, dbrType, buffer, 1);
+ }
+
+#define OP(DBR,Type,mem) case DBR: {pod.val.mem = va_arg(ap,Type); break;}
+ OP(DBR_CHAR, int, int8);
+ OP(DBR_UCHAR, int, uInt8);
+ OP(DBR_SHORT, int, int16);
+ OP(DBR_USHORT, int, uInt16);
+ OP(DBR_LONG, int, int32);
+ OP(DBR_ULONG, unsigned int, uInt32);
+ OP(DBR_FLOAT, double, float32);
+ OP(DBR_DOUBLE, double, float64);
+ OP(DBR_ENUM, int, enum16);
+#undef OP
+ default:
+ testAbort("invalid DBR: dbPutField(%s, %d, ...)",
+ addr.precord->name, dbrType);
+ }
+
+ return dbPutField(&addr, dbrType, pod.bytes, 1);
+}
+
+dbCommon* testGetRecord(const char* pv)
+{
+ DBADDR addr;
+
+ if(dbNameToAddr(pv, &addr))
+ testAbort("Missing PV %s", pv);
+
+ return addr.precord;
+}
=== added file 'src/ioc/db/dbUnitTest.h'
--- src/ioc/db/dbUnitTest.h 1970-01-01 00:00:00 +0000
+++ src/ioc/db/dbUnitTest.h 2014-06-23 20:39:40 +0000
@@ -0,0 +1,54 @@
+/*************************************************************************\
+* Copyright (c) 2013 Brookhaven National Laboratory.
+* Copyright (c) 2013 ITER Organization.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+ \*************************************************************************/
+
+/*
+ * Author: Michael Davidsaver <[email protected]>
+ * Ralph Lange <[email protected]>
+ */
+
+#ifndef EPICSUNITTESTDB_H
+#define EPICSUNITTESTDB_H
+
+#include <stdarg.h>
+
+#include "epicsUnitTest.h"
+#include "dbAddr.h"
+#include "dbCommon.h"
+
+#include "shareLib.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+epicsShareFunc void testdbPrepare(void);
+epicsShareFunc void testdbReadDatabase(const char* file,
+ const char* path,
+ const char* substitutions);
+epicsShareFunc int testiocInit(void);
+epicsShareFunc int testiocShutdown(void);
+epicsShareFunc void testdbCleanup(void);
+
+/* Scalar only version.
+ *
+ * Remember to use the correct argument type!s
+ *
+ * int for DBR_UCHAR, DBR_CHAR, DBR_USHORT, DBR_SHORT, DBR_LONG
+ * unsigned int for DBR_ULONG
+ * double for DBR_FLOAT and DBR_DOUBLE
+ * const char* for DBR_STRING
+ */
+epicsShareFunc long testdbPutField(const char* pv, short dbrType, ...);
+epicsShareFunc long testVdbPutField(const char* pv, short dbrType, va_list ap);
+
+epicsShareFunc dbCommon* testGetRecord(const char* pv);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // EPICSUNITTESTDB_H
=== modified file 'src/ioc/db/initHooks.c'
--- src/ioc/db/initHooks.c 2010-10-05 19:27:37 +0000
+++ src/ioc/db/initHooks.c 2014-06-23 20:39:40 +0000
@@ -93,6 +93,14 @@
}
}
+void initHookFree(void)
+{
+ initHookInit();
+ epicsMutexMustLock(listLock);
+ ellFree(&functionList);
+ epicsMutexUnlock(listLock);
+}
+
/*
* Call any time you want to print out a state name.
*/
=== modified file 'src/ioc/db/initHooks.h'
--- src/ioc/db/initHooks.h 2010-10-05 19:27:37 +0000
+++ src/ioc/db/initHooks.h 2014-06-23 20:39:40 +0000
@@ -60,6 +60,7 @@
epicsShareFunc int initHookRegister(initHookFunction func);
epicsShareFunc void initHookAnnounce(initHookState state);
epicsShareFunc const char *initHookName(int state);
+epicsShareFunc void initHookFree(void);
#ifdef __cplusplus
}
=== modified file 'src/ioc/db/test/Makefile'
--- src/ioc/db/test/Makefile 2014-06-13 19:37:12 +0000
+++ src/ioc/db/test/Makefile 2014-06-23 20:39:40 +0000
@@ -16,11 +16,23 @@
PROD_LIBS = xRec dbCore ca Com
+<<<<<<< TREE
TESTPROD_HOST += testdbConvert
testdbConvert_SRCS += testdbConvert.c
testHarness_SRCS += testdbConvert.c
TESTS += testdbConvert
+=======
+TESTPROD_HOST += dbShutdownTest
+TARGETS += $(COMMON_DIR)/dbShutdownTest.dbd
+dbShutdownTest_SRCS += dbShutdownTest.c
+dbShutdownTest_SRCS += dbShutdownTest_registerRecordDeviceDriver.cpp
+dbShutdownTest_LIBS += $(EPICS_BASE_IOC_LIBS)
+dbShutdownTest_DBD += base.dbd
+TESTFILES += $(COMMON_DIR)/dbShutdownTest.dbd ../sRecord.db
+TESTS += dbShutdownTest
+
+>>>>>>> MERGE-SOURCE
TESTPROD_HOST += callbackTest
callbackTest_SRCS += callbackTest.c
testHarness_SRCS += callbackTest.c
=== added file 'src/ioc/db/test/dbShutdownTest.c'
--- src/ioc/db/test/dbShutdownTest.c 1970-01-01 00:00:00 +0000
+++ src/ioc/db/test/dbShutdownTest.c 2014-06-23 20:39:40 +0000
@@ -0,0 +1,94 @@
+/*************************************************************************\
+* Copyright (c) 2013 Brookhaven National Laboratory.
+* Copyright (c) 2013 ITER Organization.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+ \*************************************************************************/
+
+/*
+ * Author: Michael Davidsaver <[email protected]>
+ * Ralph Lange <[email protected]>
+ */
+
+#include <string.h>
+
+#include "dbUnitTest.h"
+#include "epicsThread.h"
+#include "iocInit.h"
+#include "dbBase.h"
+#include "dbAccess.h"
+#include "registry.h"
+#include "dbStaticLib.h"
+#include "osiFileName.h"
+#include "dbmf.h"
+
+#include "testMain.h"
+
+void dbShutdownTest_registerRecordDeviceDriver(struct dbBase *);
+
+static struct threadItem {
+ char *name;
+ char found;
+} commonThreads[] = {
+ { "errlog", 0 },
+ { "taskwd", 0 },
+ { "timerQueue", 0 },
+ { "cbLow", 0 },
+ { "scanOnce", 0 },
+ { NULL, 0 }
+};
+
+static
+void findCommonThread (epicsThreadId id) {
+ struct threadItem *thr;
+ char name[32];
+
+ epicsThreadGetName(id, name, 32);
+
+ for (thr = commonThreads; thr->name; thr++) {
+ if (strcasecmp(thr->name, name) == 0) {
+ thr->found = 1;
+ }
+ }
+}
+
+static
+void checkCommonThreads (void) {
+ struct threadItem *thr;
+
+ for (thr = commonThreads; thr->name; thr++) {
+ testOk(thr->found, "Thread %s is running", thr->name);
+ thr->found = 0;
+ }
+}
+
+static
+void cycle(void) {
+
+ testdbPrepare();
+
+ testdbReadDatabase("dbShutdownTest.dbd", NULL, NULL);
+
+ dbShutdownTest_registerRecordDeviceDriver(pdbbase);
+
+ testdbReadDatabase("sRecord.db", NULL, NULL);
+
+ testOk1(!testiocInit());
+
+ epicsThreadMap(findCommonThread);
+ checkCommonThreads();
+
+ testOk1(testiocShutdown()==0);
+
+ testdbCleanup();
+}
+
+MAIN(dbShutdownTest)
+{
+ testPlan(14);
+
+ cycle();
+ cycle();
+
+ return testDone();
+}
=== added file 'src/ioc/db/test/sRecord.db'
--- src/ioc/db/test/sRecord.db 1970-01-01 00:00:00 +0000
+++ src/ioc/db/test/sRecord.db 2014-06-23 20:39:40 +0000
@@ -0,0 +1,1 @@
+record(ai, "somename") {}
=== modified file 'src/ioc/misc/dbCore.dbd'
--- src/ioc/misc/dbCore.dbd 2013-12-17 18:54:04 +0000
+++ src/ioc/misc/dbCore.dbd 2014-06-23 20:39:40 +0000
@@ -5,6 +5,9 @@
# This file provides iocsh access to variables that control some lesser-used
# and debugging features of the IOC database code.
+# show epicsAtExit callbacks as they are run
+variable(atExitDebug,int)
+
# Access security subroutines
variable(asCaDebug,int)
=== modified file 'src/ioc/misc/iocInit.c'
--- src/ioc/misc/iocInit.c 2013-05-30 20:00:37 +0000
+++ src/ioc/misc/iocInit.c 2014-06-23 20:39:40 +0000
@@ -3,6 +3,8 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
+* Copyright (c) 2013 Helmholtz-Zentrum Berlin
+* für Materialien und Energie GmbH.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
@@ -31,6 +33,7 @@
#include "errMdef.h"
#include "taskwd.h"
#include "caeventmask.h"
+#include "iocsh.h"
#define epicsExportSharedSymbols
#include "alarm.h"
@@ -88,12 +91,13 @@
return iocBuild() || iocRun();
}
-int iocBuild(void)
+static int iocBuild_1(void)
{
- if (iocState != iocVirgin) {
- errlogPrintf("iocBuild: IOC can only be initialized once\n");
+ if (iocState != iocVirgin && iocState != iocStopped) {
+ errlogPrintf("iocBuild: IOC can only be initialized from uninitialized or stopped state\n");
return -1;
}
+ errlogInit(0);
initHookAnnounce(initHookAtIocBuild);
if (!epicsThreadIsOkToBlock()) {
@@ -109,14 +113,17 @@
initHookAnnounce(initHookAtBeginning);
coreRelease();
- /* After this point, further calls to iocInit() are disallowed. */
iocState = iocBuilding;
taskwdInit();
callbackInit();
initHookAnnounce(initHookAfterCallbackInit);
- dbCaLinkInit();
+ return 0;
+}
+
+static int iocBuild_2(void)
+{
initHookAnnounce(initHookAfterCaLinkInit);
initDrvSup();
@@ -147,9 +154,11 @@
initialProcess();
initHookAnnounce(initHookAfterInitialProcess);
+ return 0;
+}
- /* Start CA server threads */
- rsrv_init();
+static int iocBuild_3(void)
+{
initHookAnnounce(initHookAfterCaServerInit);
iocState = iocBuilt;
@@ -157,6 +166,39 @@
return 0;
}
+int iocBuild(void)
+{
+ int status;
+
+ status = iocBuild_1();
+ if (status) return status;
+
+ dbCaLinkInit();
+
+ status = iocBuild_2();
+ if (status) return status;
+
+ /* Start CA server threads */
+ rsrv_init();
+
+ status = iocBuild_3();
+ return status;
+}
+
+int iocBuildNoCA(void)
+{
+ int status;
+
+ status = iocBuild_1();
+ if (status) return status;
+
+ status = iocBuild_2();
+ if (status) return status;
+
+ status = iocBuild_3();
+ return status;
+}
+
int iocRun(void)
{
if (iocState != iocPaused && iocState != iocBuilt) {
@@ -599,8 +641,31 @@
}
}
-static void exitDatabase(void *dummy)
-{
+static void doFreeRecord(dbRecordType *pdbRecordType, dbCommon *precord,
+ void *user)
+{
+ struct rset *prset = pdbRecordType->prset;
+
+ if (!prset) return; /* unlikely */
+
+ epicsMutexDestroy(precord->mlok);
+}
+
+int iocShutdown(void)
+{
+ if (iocState == iocVirgin || iocState == iocStopped) return 0;
iterateRecords(doCloseLinks, NULL);
+ scanShutdown();
+ callbackShutdown();
+ iterateRecords(doFreeRecord, NULL);
+ dbLockCleanupRecords(pdbbase);
+ asShutdown();
+ iocshFree();
iocState = iocStopped;
+ return 0;
+}
+
+static void exitDatabase(void *dummy)
+{
+ iocShutdown();
}
=== modified file 'src/ioc/misc/iocInit.h'
--- src/ioc/misc/iocInit.h 2009-06-10 20:19:32 +0000
+++ src/ioc/misc/iocInit.h 2014-06-23 20:39:40 +0000
@@ -19,8 +19,10 @@
epicsShareFunc int iocInit(void);
epicsShareFunc int iocBuild(void);
+epicsShareFunc int iocBuildNoCA(void);
epicsShareFunc int iocRun(void);
epicsShareFunc int iocPause(void);
+epicsShareFunc int iocShutdown(void);
#ifdef __cplusplus
}
=== modified file 'src/libCom/as/asLib.h'
--- src/libCom/as/asLib.h 2010-12-17 16:50:52 +0000
+++ src/libCom/as/asLib.h 2014-06-23 20:39:40 +0000
@@ -222,6 +222,7 @@
/*following is "friend" function*/
epicsShareFunc void * epicsShareAPI asCalloc(size_t nobj,size_t size);
epicsShareFunc char * epicsShareAPI asStrdup(unsigned char *str);
+epicsShareFunc void asFreeAll(ASBASE *pasbase);
#ifdef __cplusplus
}
#endif
=== modified file 'src/libCom/as/asLibRoutines.c'
--- src/libCom/as/asLibRoutines.c 2012-07-07 18:50:55 +0000
+++ src/libCom/as/asLibRoutines.c 2014-06-23 20:39:40 +0000
@@ -51,7 +51,6 @@
static long asComputeAllAsgPvt(void);
static long asComputeAsgPvt(ASG *pasg);
static long asComputePvt(ASCLIENTPVT asClientPvt);
-static void asFreeAll(ASBASE *pasbase);
static UAG *asUagAdd(const char *uagName);
static long asUagAddUser(UAG *puag,const char *user);
static HAG *asHagAdd(const char *hagName);
@@ -1015,7 +1014,7 @@
return(0);
}
-static void asFreeAll(ASBASE *pasbase)
+void asFreeAll(ASBASE *pasbase)
{
UAG *puag;
UAGNAME *puagname;
=== modified file 'src/libCom/error/errlog.c'
--- src/libCom/error/errlog.c 2013-06-28 17:35:43 +0000
+++ src/libCom/error/errlog.c 2014-06-23 20:39:40 +0000
@@ -41,7 +41,7 @@
/*Declare storage for errVerbose */
epicsShareDef int errVerbose = 0;
-static void exitHandler(void *);
+static void errlogExitHandler(void *);
static void errlogThread(void);
static char *msgbufGetFree(int noConsoleMessage);
@@ -70,8 +70,8 @@
epicsEventId waitForFlush; /*errlogFlush waits for this*/
epicsEventId flush; /*errlogFlush sets errlogThread does a Try*/
epicsMutexId flushLock;
- epicsEventId waitForExit; /*exitHandler waits for this*/
- int atExit; /*TRUE when exitHandler is active*/
+ epicsEventId waitForExit; /*errlogExitHandler waits for this*/
+ int atExit; /*TRUE when errlogExitHandler is active*/
ELLLIST listenerList;
ELLLIST msgQueue;
msgNode *pnextSend;
@@ -447,7 +447,7 @@
}
-static void exitHandler(void *pvt)
+static void errlogExitHandler(void *pvt)
{
pvtData.atExit = 1;
epicsEventSignal(pvtData.waitForWork);
@@ -561,7 +561,7 @@
int noConsoleMessage;
char *pmessage;
- epicsAtExit(exitHandler,0);
+ epicsAtExit(errlogExitHandler,0);
while (TRUE) {
epicsEventMustWait(pvtData.waitForWork);
while ((pmessage = msgbufGetSend(&noConsoleMessage))) {
=== modified file 'src/libCom/iocsh/iocsh.cpp'
--- src/libCom/iocsh/iocsh.cpp 2014-02-07 23:19:28 +0000
+++ src/libCom/iocsh/iocsh.cpp 2014-06-23 20:39:40 +0000
@@ -203,20 +203,22 @@
*/
void epicsShareAPI iocshFree(void)
{
- struct iocshCommand *pc, *nc;
- struct iocshVariable *pv, *nv;
+ struct iocshCommand *pc;
+ struct iocshVariable *pv;
iocshTableLock ();
for (pc = iocshCommandHead ; pc != NULL ; ) {
- nc = pc->next;
+ struct iocshCommand * nc = pc->next;
free (pc);
pc = nc;
}
for (pv = iocshVariableHead ; pv != NULL ; ) {
- nv = pv->next;
+ struct iocshVariable *nv = pv->next;
free (pv);
pv = nv;
}
+ iocshCommandHead = NULL;
+ iocshVariableHead = NULL;
iocshTableUnlock ();
}
=== modified file 'src/libCom/misc/epicsExit.c'
--- src/libCom/misc/epicsExit.c 2013-12-17 18:54:04 +0000
+++ src/libCom/misc/epicsExit.c 2014-06-23 20:39:40 +0000
@@ -23,7 +23,9 @@
*/
#include <stdlib.h>
+#include <stdio.h>
#include <errno.h>
+#include <string.h>
#define epicsExportSharedSymbols
#include "ellLib.h"
@@ -36,12 +38,15 @@
ELLNODE node;
epicsExitFunc func;
void *arg;
+ char name[1];
}exitNode;
typedef struct exitPvt {
ELLLIST list;
} exitPvt;
+int atExitDebug = 0;
+
static epicsThreadOnceId exitPvtOnce = EPICS_THREAD_ONCE_INIT;
static exitPvt * pExitPvtPerProcess = 0;
static epicsMutexId exitPvtLock = 0;
@@ -66,15 +71,23 @@
{
exitPvtPerThread = epicsThreadPrivateCreate ();
assert ( exitPvtPerThread );
- pExitPvtPerProcess = createExitPvt ();
- assert ( pExitPvtPerProcess );
exitPvtLock = epicsMutexMustCreate ();
}
+static void epicsExitInit(void)
+{
+ epicsThreadOnce ( & exitPvtOnce, exitPvtOnceFunc, 0 );
+}
+
static void epicsExitCallAtExitsPvt(exitPvt *pep)
{
exitNode *pexitNode;
+
while ( ( pexitNode = (exitNode *) ellLast ( & pep->list ) ) ) {
+ if (atExitDebug && pexitNode->name[0])
+ fprintf(stderr, "atExit %s(%p)\n", pexitNode->name, pexitNode->arg);
+ else if(atExitDebug)
+ fprintf(stderr, "atExit %p(%p)\n", pexitNode->func, pexitNode->arg);
pexitNode->func ( pexitNode->arg );
ellDelete ( & pep->list, & pexitNode->node );
free ( pexitNode );
@@ -84,7 +97,8 @@
epicsShareFunc void epicsExitCallAtExits(void)
{
exitPvt * pep = 0;
- epicsThreadOnce ( & exitPvtOnce, exitPvtOnceFunc, 0 );
+
+ epicsExitInit ();
epicsMutexMustLock ( exitPvtLock );
if ( pExitPvtPerProcess ) {
pep = pExitPvtPerProcess;
@@ -100,7 +114,8 @@
epicsShareFunc void epicsExitCallAtThreadExits(void)
{
exitPvt * pep;
- epicsThreadOnce ( & exitPvtOnce, exitPvtOnceFunc, 0 );
+
+ epicsExitInit ();
pep = epicsThreadPrivateGet ( exitPvtPerThread );
if ( pep ) {
epicsExitCallAtExitsPvt ( pep );
@@ -109,14 +124,16 @@
}
}
-static int epicsAtExitPvt(exitPvt *pep, epicsExitFunc func, void *arg)
+static int epicsAtExitPvt(exitPvt *pep, epicsExitFunc func, void *arg, const char *name)
{
int status = -1;
- exitNode * pExitNode
- = calloc ( 1, sizeof( *pExitNode ) );
+ exitNode * pExitNode = calloc ( 1, sizeof( *pExitNode ) + (name?strlen(name):0) );
+
if ( pExitNode ) {
pExitNode->func = func;
pExitNode->arg = arg;
+ if(name)
+ strcpy(pExitNode->name, name);
ellAdd ( & pep->list, & pExitNode->node );
status = 0;
}
@@ -126,7 +143,8 @@
epicsShareFunc int epicsAtThreadExit(epicsExitFunc func, void *arg)
{
exitPvt * pep;
- epicsThreadOnce ( & exitPvtOnce, exitPvtOnceFunc, 0 );
+
+ epicsExitInit ();
pep = epicsThreadPrivateGet ( exitPvtPerThread );
if ( ! pep ) {
pep = createExitPvt ();
@@ -135,16 +153,20 @@
}
epicsThreadPrivateSet ( exitPvtPerThread, pep );
}
- return epicsAtExitPvt ( pep, func, arg );
+ return epicsAtExitPvt ( pep, func, arg, NULL );
}
-epicsShareFunc int epicsAtExit(epicsExitFunc func, void *arg)
+epicsShareFunc int epicsAtExit3(epicsExitFunc func, void *arg, const char* name)
{
int status = -1;
- epicsThreadOnce ( & exitPvtOnce, exitPvtOnceFunc, 0 );
+
+ epicsExitInit ();
epicsMutexMustLock ( exitPvtLock );
+ if ( !pExitPvtPerProcess ) {
+ pExitPvtPerProcess = createExitPvt ();
+ }
if ( pExitPvtPerProcess ) {
- status = epicsAtExitPvt ( pExitPvtPerProcess, func, arg );
+ status = epicsAtExitPvt ( pExitPvtPerProcess, func, arg, name );
}
epicsMutexUnlock ( exitPvtLock );
return status;
@@ -153,6 +175,10 @@
epicsShareFunc void epicsExit(int status)
{
epicsExitCallAtExits();
- epicsThreadSleep(1.0);
+ epicsThreadSleep(0.1);
exit(status);
}
+
+#include "epicsExport.h"
+
+epicsExportAddress(int,atExitDebug);
=== modified file 'src/libCom/misc/epicsExit.h'
--- src/libCom/misc/epicsExit.h 2013-12-17 18:54:04 +0000
+++ src/libCom/misc/epicsExit.h 2014-06-23 20:39:40 +0000
@@ -19,7 +19,8 @@
epicsShareFunc void epicsExit(int status);
epicsShareFunc void epicsExitCallAtExits(void);
-epicsShareFunc int epicsAtExit(epicsExitFunc func, void *arg);
+epicsShareFunc int epicsAtExit3(epicsExitFunc func, void *arg, const char* name);
+#define epicsAtExit(F,A) epicsAtExit3(F,A,#F)
epicsShareFunc void epicsExitCallAtThreadExits(void);
epicsShareFunc int epicsAtThreadExit(epicsExitFunc func, void *arg);
=== modified file 'src/libCom/test/epicsExitTest.c'
--- src/libCom/test/epicsExitTest.c 2009-04-08 22:39:27 +0000
+++ src/libCom/test/epicsExitTest.c 2014-06-23 20:39:40 +0000
@@ -59,12 +59,20 @@
testDiag("%s starting", pinfo->name);
pinfo->terminate = epicsEventMustCreate(epicsEventEmpty);
pinfo->terminated = epicsEventMustCreate(epicsEventEmpty);
- epicsAtExit(atExit, pinfo);
- epicsAtThreadExit(atThreadExit, pinfo);
+ testOk(!epicsAtExit(atExit, pinfo), "Registered atExit(%p)", pinfo);
+ testOk(!epicsAtThreadExit(atThreadExit, pinfo),
+ "Registered atThreadExit(%p)", pinfo);
testDiag("%s waiting for atExit", pinfo->name);
epicsEventMustWait(pinfo->terminate);
}
+int count;
+
+static void counter(void *pvt)
+{
+ count++;
+}
+
static void mainExit(void *pvt)
{
testPass("Reached mainExit");
@@ -77,16 +85,23 @@
info *pinfoA = (info *)calloc(1, sizeof(info));
info *pinfoB = (info *)calloc(1, sizeof(info));
- testPlan(7);
-
- epicsAtExit(mainExit, NULL);
+ testPlan(15);
+
+ testOk(!epicsAtExit(counter, NULL), "Registered counter()");
+ count = 0;
+ epicsExitCallAtExits();
+ testOk(count == 1, "counter() called once");
+ epicsExitCallAtExits();
+ testOk(count == 1, "unregistered counter() not called");
+
+ testOk(!epicsAtExit(mainExit, NULL), "Registered mainExit()");
epicsThreadCreate("threadA", 50, stackSize, thread, pinfoA);
epicsThreadSleep(0.1);
epicsThreadCreate("threadB", 50, stackSize, thread, pinfoB);
epicsThreadSleep(1.0);
- testDiag("Calling epicsExit\n");
+ testDiag("Calling epicsExit");
epicsExit(0);
return 0;
}
- Replies:
- Re: [Merge] lp:~epics-core/epics-base/ioc-shutdown2 into lp:epics-base Andrew Johnson
- Re: [Merge] lp:~epics-core/epics-base/ioc-shutdown2 into lp:epics-base Andrew Johnson
- Re: [Merge] lp:~epics-core/epics-base/ioc-shutdown2 into lp:epics-base mdavidsaver
- Re: [Merge] lp:~epics-core/epics-base/ioc-shutdown2 into lp:epics-base Andrew Johnson
- Re: [Merge] lp:~epics-core/epics-base/ioc-shutdown2 into lp:epics-base mdavidsaver
- Re: [Merge] lp:~epics-core/epics-base/ioc-shutdown2 into lp:epics-base mdavidsaver
- Navigate by Date:
- Prev:
Jenkins build is back to normal : epics-base-3.15-win64s #14 APS Jenkins
- Next:
epicsThreadShowAll Benjamin Franksen
- Index:
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
<2014>
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
- Navigate by Thread:
- Prev:
Jenkins build is back to normal : epics-base-3.15-win64s #14 APS Jenkins
- Next:
Re: [Merge] lp:~epics-core/epics-base/ioc-shutdown2 into lp:epics-base Andrew Johnson
- Index:
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
<2014>
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024