5 #define EPICS_DBCA_PRIVATE_API
6 #include <epicsGuard.h>
12 #include <initHooks.h>
14 #include <epicsExit.h>
15 #include <epicsAtomic.h>
18 #include <epicsUnitTest.h>
19 #include <epicsString.h>
21 #include <epicsStdio.h>
23 #include <pv/pvAccess.h>
24 #include <pv/clientFactory.h>
25 #include <pv/iocshelper.h>
26 #include <pv/reftrack.h>
27 #include <pva/client.h>
34 #include <epicsExport.h>
36 #if EPICS_VERSION_INT>=VERSION_INT(7,0,6,0)
37 # define HAVE_SHUTDOWN_HOOKS
43 using namespace pvalink;
48 static void shutdownStep1()
51 if(!pvaGlobal)
return;
53 pvaGlobal->queue.close();
58 static void shutdownStep2()
60 if(!pvaGlobal)
return;
63 Guard G(pvaGlobal->lock);
64 if(pvaGlobal->channels.size()) {
65 fprintf(stderr,
"pvaLink leaves %zu channels open\n",
66 pvaGlobal->channels.size());
74 #ifndef HAVE_SHUTDOWN_HOOKS
75 static void stopPVAPool(
void*)
79 }
catch(std::exception& e){
80 fprintf(stderr,
"Error while stopping PVA link pool : %s\n", e.what());
84 static void finalizePVA(
void*)
88 }
catch(std::exception& e){
89 fprintf(stderr,
"Error initializing pva link handling : %s\n", e.what());
105 void initPVALink(initHookState state)
108 if(state==initHookAfterCaLinkInit) {
113 cantProceed(
"# Missing call to testqsrvShutdownOk() and/or testqsrvCleanup()");
117 #ifndef HAVE_SHUTDOWN_HOOKS
118 static bool atexitInstalled;
119 if(!atexitInstalled) {
120 epicsAtExit(finalizePVA, NULL);
121 atexitInstalled =
true;
125 }
else if(state==initHookAfterInitDatabase) {
126 pvac::ClientProvider local(
"server:QSRV"),
128 pvaGlobal->provider_local = local;
129 pvaGlobal->provider_remote = remote;
131 }
else if(state==initHookAfterIocBuilt) {
135 #ifndef HAVE_SHUTDOWN_HOOKS
136 epicsAtExit(stopPVAPool, NULL);
139 Guard G(pvaGlobal->lock);
140 pvaGlobal->running =
true;
142 for(pvaGlobal_t::channels_t::iterator it(pvaGlobal->channels.begin()), end(pvaGlobal->channels.end());
145 std::tr1::shared_ptr<pvaLinkChannel> chan(it->second.lock());
150 #ifdef HAVE_SHUTDOWN_HOOKS
151 }
else if(state==initHookAtShutdown) {
154 }
else if(state==initHookAfterShutdown) {
158 }
catch(std::exception& e){
159 cantProceed(
"Error initializing pva link handling : %s\n", e.what());
166 void testqsrvShutdownOk(
void)
170 }
catch(std::exception& e){
171 testAbort(
"Error while stopping PVA link pool : %s\n", e.what());
175 void testqsrvCleanup(
void)
179 }
catch(std::exception& e){
180 testAbort(
"Error initializing pva link handling : %s\n", e.what());
184 void testqsrvWaitForLinkEvent(
struct link *plink)
186 std::tr1::shared_ptr<pvaLinkChannel> lchan;
190 if(plink->type!=JSON_LINK || !plink->value.json.jlink || plink->value.json.jlink->pif!=&lsetPVA) {
191 testAbort(
"Not a PVA link");
197 lchan->run_done.wait();
202 void dbpvar(
const char *precordname,
int level)
206 printf(
"PVA links not initialized\n");
210 if (!precordname || precordname[0] ==
'\0' || !strcmp(precordname,
"*")) {
212 printf(
"PVA links in all records\n\n");
214 printf(
"PVA links in record named '%s'\n\n", precordname);
217 size_t nchans = 0, nlinks = 0, nconn = 0;
219 pvaGlobal_t::channels_t channels;
221 Guard G(pvaGlobal->lock);
222 channels = pvaGlobal->channels;
225 for(pvaGlobal_t::channels_t::const_iterator it(channels.begin()), end(channels.end());
228 std::tr1::shared_ptr<pvaLinkChannel> chan(it->second.lock());
236 for(pvaLinkChannel::links_t::const_iterator it2(chan->links.begin()), end2(chan->links.end());
241 if(pval->plink && epicsStrGlobMatch(pval->plink->precord->name, precordname)) {
251 if(chan->connected_latched)
255 nlinks += chan->links.size();
260 if(level>=2 || (!chan->connected_latched && level==1)) {
261 if(chan->key.first.size()<=28) {
262 printf(
"%28s ", chan->key.first.c_str());
264 printf(
"%s\t", chan->key.first.c_str());
267 printf(
"conn=%c %zu disconnects, %zu type changes",
268 chan->connected_latched?
'T':
'F',
269 chan->num_disconnect,
270 chan->num_type_change);
271 if(chan->op_put.valid()) {
276 printf(
", provider '%s'", chan->providerName.c_str());
282 for(pvaLinkChannel::links_t::const_iterator it2(chan->links.begin()), end2(chan->links.end());
289 else if(precordname && !epicsStrGlobMatch(pval->plink->precord->name, precordname))
292 const char *fldname =
"???";
294 for(
bool done = !!dbFirstField(&rec.ent, 0); !done; done = !!dbNextField(&rec.ent, 0))
296 if(rec.ent.pfield == (
void*)pval->plink) {
297 fldname = rec.ent.pflddes->name;
302 printf(
"%*s%s.%s", 30,
"", pval->plink ? pval->plink->precord->name :
"<NULL>", fldname);
305 case pvaLinkConfig::NPP: printf(
" NPP");
break;
306 case pvaLinkConfig::Default: printf(
" Def");
break;
307 case pvaLinkConfig::PP: printf(
" PP");
break;
308 case pvaLinkConfig::CP: printf(
" CP");
break;
309 case pvaLinkConfig::CPP: printf(
" CPP");
break;
312 case pvaLinkConfig::NMS: printf(
" NMS");
break;
313 case pvaLinkConfig::MS: printf(
" MS");
break;
314 case pvaLinkConfig::MSI: printf(
" MSI");
break;
317 printf(
" Q=%u pipe=%c defer=%c time=%c retry=%c morder=%d\n",
318 unsigned(pval->queueSize),
319 pval->pipeline ?
'T' :
'F',
320 pval->defer ?
'T' :
'F',
321 pval->time ?
'T' :
'F',
322 pval->retry ?
'T' :
'F',
330 printf(
" %zu/%zu channels connected used by %zu links\n",
331 nconn, nchans, nlinks);
333 }
catch(std::exception& e) {
334 fprintf(stderr,
"Error: %s\n", e.what());
339 void installPVAAddLinkHook()
341 initHookRegister(&initPVALink);
342 epics::iocshRegister<const char*, int, &dbpvar>(
"dbpvar",
"record name",
"level");
343 epics::registerRefCounter(
"pvaLinkChannel", &pvaLinkChannel::num_instances);
344 epics::registerRefCounter(
"pvaLink", &pvaLink::num_instances);
348 epicsExportRegistrar(installPVAAddLinkHook);
349 epicsExportAddress(
jlif, lsetPVA);
350 epicsExportAddress(
int, pvaLinkDebug);
351 epicsExportAddress(
int, pvaLinkNWorkers);