fix pvalink shutdown during tests

This commit is contained in:
Michael Davidsaver
2018-04-17 17:45:07 -07:00
parent 520ac5a0b5
commit c55d50c158
4 changed files with 96 additions and 13 deletions

View File

@ -85,3 +85,4 @@ include $(TOP)/configure/RULES
$(EXPAND_TOOL) $(EXPANDFLAGS) $($@_EXPANDFLAGS) $< $@
qsrv$(DEP): ../O.Common/pv/qsrvVersionNum.h
pvalink$(DEP): ../O.Common/pv/qsrvVersionNum.h

View File

@ -25,6 +25,34 @@ epicsShareExtern unsigned qsrvVersion(void);
/** returns QSRV_ABI_VERSION_INT captured at compilation time */
epicsShareExtern unsigned qsrvABIVersion(void);
/** Call before testIocShutdownOk()
@code
testdbPrepare();
...
testIocInitOk();
...
testqsrvShutdownOk();
testIocShutdownOk();
testqsrvCleanup();
testdbCleanup();
@endcode
*/
epicsShareExtern void testqsrvShutdownOk(void);
/** Call after testIocShutdownOk() and before testdbCleanup()
@code
testdbPrepare();
...
testIocInitOk();
...
testqsrvShutdownOk();
testIocShutdownOk();
testqsrvCleanup();
testdbCleanup();
@endcode
*/
epicsShareExtern void testqsrvCleanup(void);
#ifdef __cplusplus
}
#endif

View File

@ -16,6 +16,8 @@
#include <epicsAtomic.h>
#include <link.h>
#include <dbJLink.h>
#include <epicsUnitTest.h>
#include <epicsStdio.h> /* redirects stdout/stderr */
#include <pv/pvAccess.h>
@ -26,6 +28,7 @@
#define epicsExportSharedSymbols
#include <shareLib.h>
#include "pv/qsrv.h"
#include "helper.h"
#include "pvif.h"
#include "pvalink.h"
@ -39,30 +42,53 @@ using namespace pvalink;
namespace {
// halt, and clear, scan workers before dbCloseLinks() (cf. iocShutdown())
static void shutdownStep1()
{
// no locking here as we assume that shutdown doesn't race startup
if(!pvaGlobal) return;
pvaGlobal->queue.close();
}
// Cleanup pvaGlobal, including PVA client and QSRV providers ahead of PDB cleanup
// specifically QSRV provider must be free'd prior to db_cleanup_events()
static void shutdownStep2()
{
if(!pvaGlobal) return;
{
Guard G(pvaGlobal->lock);
if(pvaGlobal->channels.size()) {
fprintf(stderr, "pvaLink leaves %zu channels open\n",
pvaGlobal->channels.size());
}
}
delete pvaGlobal;
pvaGlobal = NULL;
}
static void stopPVAPool(void*)
{
pvaGlobal->queue.close();
try {
shutdownStep1();
}catch(std::exception& e){
fprintf(stderr, "Error while stopping PVA link pool : %s\n", e.what());
}
}
static void finalizePVA(void*)
{
try {
{
Guard G(pvaGlobal->lock);
if(pvaGlobal->channels.size()) {
fprintf(stderr, "pvaLink leaves %zu channels open\n",
pvaGlobal->channels.size());
}
}
delete pvaGlobal;
pvaGlobal = NULL;
shutdownStep2();
}catch(std::exception& e){
fprintf(stderr, "Error initializing pva link handling : %s\n", e.what());
}
}
bool atexitInstalled;
void initPVALink(initHookState state)
{
if(state==initHookAfterCaLinkInit) {
@ -70,9 +96,15 @@ void initPVALink(initHookState state)
// so hook registered here will be run after iocShutdown()
// which closes links
try {
if(pvaGlobal) {
cantProceed("# Missing call to testqsrvShutdownOk() and/or testqsrvCleanup()");
}
pvaGlobal = new pvaGlobal_t;
epicsAtExit(finalizePVA, NULL);
if(!atexitInstalled) {
epicsAtExit(finalizePVA, NULL);
atexitInstalled = true;
}
}catch(std::exception& e){
cantProceed("Error initializing pva link handling : %s\n", e.what());
@ -87,6 +119,25 @@ void initPVALink(initHookState state)
} // namespace
// halt, and clear, scan workers before dbCloseLinks() (cf. iocShutdown())
void testqsrvShutdownOk(void)
{
try {
shutdownStep1();
}catch(std::exception& e){
testAbort("Error while stopping PVA link pool : %s\n", e.what());
}
}
void testqsrvCleanup(void)
{
try {
shutdownStep2();
}catch(std::exception& e){
testAbort("Error initializing pva link handling : %s\n", e.what());
}
}
static
void installPVAAddLinkHook()
{

View File

@ -2,6 +2,7 @@
#include <dbUnitTest.h>
#include <testMain.h>
#include <pv/qsrv.h>
#include "utilities.h"
#include "pvalink.h"
@ -70,7 +71,9 @@ MAIN(testpvalink)
IOC.init();
testGet();
testPut();
testqsrvShutdownOk();
IOC.shutdown();
testqsrvCleanup();
}catch(std::exception& e){
testFail("Unexpected exception: %s", e.what());