diff --git a/examples/getme.cpp b/examples/getme.cpp index 0635609..21f19cb 100644 --- a/examples/getme.cpp +++ b/examples/getme.cpp @@ -17,12 +17,12 @@ #include #include #include +#include -//! [Headers] #include #include +#include #include -//! [Headers] namespace pvd = epics::pvData; namespace pva = epics::pvAccess; @@ -92,37 +92,36 @@ struct Getter : public pvac::ClientChannel::GetCallback, int main(int argc, char *argv[]) { try { + epics::RefMonitor refmon; double waitTime = -1.0; std::string providerName("pva"); typedef std::vector pvs_t; pvs_t pvs; - for(int i=1; i(argv[++i]); - } else { - std::cerr << "--timeout requires value\n"; - return 1; - } - } else { - std::cerr<<"Unknown argument: "<(optarg); + break; + case 'h': + std::cout<<"Usage: "<] [-w ] [-R] ...\n"; + return 0; + default: + std::cerr<<"Unknown argument: "< #include #include +#include #include #include +#include #include #include @@ -184,45 +186,40 @@ struct MonTracker : public pvac::ClientChannel::MonitorCallback, int main(int argc, char *argv[]) { try { + epics::RefMonitor refmon; double waitTime = -1.0; std::string providerName("pva"), requestStr("field()"); typedef std::vector pvs_t; pvs_t pvs; - for(int i=1; i(argv[++i]); - } else { - std::cout << "--timeout requires value\n"; - return 1; - } - } else if(strcmp(argv[i], "-r")==0 || strcmp(argv[i], "--request")==0) { - if(i(optarg); + break; + case 'r': + requestStr = optarg; + break; + case 'h': + std::cout<<"Usage: "<] [-w ] [-r ] [-R] ...\n"; + return 0; + default: + std::cerr<<"Unknown argument: "< #include #include +#include #include "pvutils.cpp" @@ -355,6 +356,7 @@ int main (int argc, char *argv[]) istream* inputStream = 0; ifstream ifs; bool fromStream = false; + epics::RefMonitor refmon; double timeOut = -1.0; bool explicit_timeout = false; @@ -363,7 +365,7 @@ int main (int argc, char *argv[]) // ================ Parse Arguments - while ((opt = getopt(argc, argv, ":hvr:w:tmp:qdcF:f:ni")) != -1) { + while ((opt = getopt(argc, argv, ":hvRr:w:tmp:qdcF:f:ni")) != -1) { switch (opt) { case 'h': /* Print usage */ usage(); @@ -378,6 +380,9 @@ int main (int argc, char *argv[]) fprintf(stdout, "%s\n", version.getVersionString().c_str()); return 0; } + case 'R': + refmon.start(5.0); + break; case 'w': /* Set PVA timeout value */ if((epicsScanDouble(optarg, &timeOut)) != 1 || timeOut <= 0.0) { @@ -609,6 +614,14 @@ int main (int argc, char *argv[]) } } + if(refmon.running()) { + refmon.stop(); + // drop refs to operations, but keep ref to ClientProvider + ops.clear(); + // show final counts + refmon.current(); + } + // ========================== All done now if(debugFlag) diff --git a/src/ca/caChannel.cpp b/src/ca/caChannel.cpp index c3e0077..83b20d9 100644 --- a/src/ca/caChannel.cpp +++ b/src/ca/caChannel.cpp @@ -10,7 +10,9 @@ #include #include #include +#include +#define epicsExportSharedSymbols #include "caChannel.h" #include @@ -356,6 +358,8 @@ void CAChannel::disconnected() } } +size_t CAChannel::num_instances; + CAChannel::CAChannel(std::string const & _channelName, CAChannelProvider::shared_pointer const & _channelProvider, ChannelRequester::shared_pointer const & _channelRequester) : @@ -367,6 +371,7 @@ CAChannel::CAChannel(std::string const & _channelName, elementCount(0), destroyed(false) { + REFTRACE_INCREMENT(num_instances); PVACCESS_REFCOUNT_MONITOR_CONSTRUCT(caChannel); if(CAClientFactory::getDebug()>0) { cout<< "CAChannel::CAChannel " << channelName << endl; @@ -443,6 +448,7 @@ CAChannel::~CAChannel() /* Clear CA Channel */ threadAttach(); ca_clear_channel(channelID); + REFTRACE_DECREMENT(num_instances); } @@ -652,6 +658,7 @@ static chtype getDBRType(PVStructure::shared_pointer const & pvRequest, chtype n return nativeType; } +size_t CAChannelGet::num_instances; CAChannelGet::CAChannelGet(CAChannel::shared_pointer const & channel, ChannelGetRequester::shared_pointer const & channelGetRequester, @@ -662,6 +669,7 @@ CAChannelGet::CAChannelGet(CAChannel::shared_pointer const & channel, pvRequest(pvRequest), lastRequestFlag(false) { + REFTRACE_INCREMENT(num_instances); if(CAClientFactory::getDebug()>0) { cout << "CAChannelGet::CAChannelGet() " << channel->getChannelName() << endl; } @@ -675,6 +683,7 @@ CAChannelGet::~CAChannelGet() if(caChannel) channelName = caChannel->getChannelName(); std::cout << "CAChannelGet::~CAChannelGet() " << channelName << endl; } + REFTRACE_DECREMENT(num_instances); } void CAChannelGet::activate() @@ -1193,8 +1202,10 @@ CAChannelPut::~CAChannelPut() if(caChannel) channelName = caChannel->getChannelName(); std::cout << "CAChannelPut::~CAChannelPut() " << channelName << endl; } + REFTRACE_DECREMENT(num_instances); } +size_t CAChannelPut::num_instances; CAChannelPut::CAChannelPut(CAChannel::shared_pointer const & channel, ChannelPutRequester::shared_pointer const & channelPutRequester, @@ -1206,6 +1217,7 @@ CAChannelPut::CAChannelPut(CAChannel::shared_pointer const & channel, block(false), lastRequestFlag(false) { + REFTRACE_INCREMENT(num_instances); if(CAClientFactory::getDebug()>0) { cout << "CAChannelPut::CAChannePut() " << channel->getChannelName() << endl; } @@ -1720,8 +1732,11 @@ CAChannelMonitor::~CAChannelMonitor() if(!isStarted) return; caChannel->threadAttach(); ca_clear_subscription(eventID); + REFTRACE_DECREMENT(num_instances); } +size_t CAChannelMonitor::num_instances; + CAChannelMonitor::CAChannelMonitor( CAChannel::shared_pointer const & channel, MonitorRequester::shared_pointer const & monitorRequester, @@ -1732,6 +1747,7 @@ CAChannelMonitor::CAChannelMonitor( pvRequest(pvRequest), isStarted(false) { + REFTRACE_INCREMENT(num_instances); if(CAClientFactory::getDebug()>0) { cout << "CAChannelMonitor::CAChannelMonitor() " << channel->getChannelName() << endl; } diff --git a/src/ca/caChannel.h b/src/ca/caChannel.h index 2d5cf66..8a5e95f 100644 --- a/src/ca/caChannel.h +++ b/src/ca/caChannel.h @@ -46,6 +46,8 @@ class CAChannel : public: POINTER_DEFINITIONS(CAChannel); + static size_t num_instances; + static shared_pointer create(CAChannelProvider::shared_pointer const & channelProvider, std::string const & channelName, short priority, @@ -139,6 +141,8 @@ class CAChannelGet : public: POINTER_DEFINITIONS(CAChannelGet); + static size_t num_instances; + static CAChannelGet::shared_pointer create(CAChannel::shared_pointer const & channel, ChannelGetRequester::shared_pointer const & channelGetRequester, epics::pvData::PVStructure::shared_pointer const & pvRequest); @@ -198,6 +202,8 @@ class CAChannelPut : public: POINTER_DEFINITIONS(CAChannelPut); + static size_t num_instances; + static CAChannelPut::shared_pointer create(CAChannel::shared_pointer const & channel, ChannelPutRequester::shared_pointer const & channelPutRequester, epics::pvData::PVStructure::shared_pointer const & pvRequest); @@ -267,6 +273,8 @@ class CAChannelMonitor : public: POINTER_DEFINITIONS(CAChannelMonitor); + static size_t num_instances; + static CAChannelMonitor::shared_pointer create(CAChannel::shared_pointer const & channel, MonitorRequester::shared_pointer const & monitorRequester, epics::pvData::PVStructure::shared_pointer const & pvRequest); diff --git a/src/ca/caProvider.cpp b/src/ca/caProvider.cpp index 3b9bcec..6afdb9a 100644 --- a/src/ca/caProvider.cpp +++ b/src/ca/caProvider.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #define epicsExportSharedSymbols #include @@ -30,17 +31,19 @@ using namespace epics::pvData; catch (std::exception &e) { LOG(logLevelError, "Unhandled exception caught from client code at %s:%d: %s", __FILE__, __LINE__, e.what()); } \ catch (...) { LOG(logLevelError, "Unhandled exception caught from client code at %s:%d.", __FILE__, __LINE__); } - -int CAClientFactory::debug = 1; +size_t CAChannelProvider::num_instances; +int CAClientFactory::debug = 0; CAChannelProvider::CAChannelProvider() : current_context(0) { + REFTRACE_INCREMENT(num_instances); initialize(); } CAChannelProvider::CAChannelProvider(const std::tr1::shared_ptr&) : current_context(0) { + REFTRACE_INCREMENT(num_instances); if(CAClientFactory::getDebug()>0) { std::cout<< "CAChannelProvider::CAChannelProvider\n"; } @@ -52,6 +55,7 @@ CAChannelProvider::CAChannelProvider(const std::tr1::shared_ptr&) CAChannelProvider::~CAChannelProvider() { if(CAClientFactory::getDebug()>0) std::cout << "CAChannelProvider::~CAChannelProvider()\n"; + REFTRACE_DECREMENT(num_instances); } std::string CAChannelProvider::getProviderName() @@ -151,7 +155,9 @@ void CAChannelProvider::initialize() static void ca_factory_cleanup(void*) { -std::cout << "ca_factory_cleanup\n"; + if(CAClientFactory::getDebug()>0) { + std::cout << "ca_factory_cleanup\n"; + } try { ChannelProviderRegistry::clients()->remove("ca"); ca_context_destroy(); @@ -164,6 +170,11 @@ void CAClientFactory::start() { epicsSignalInstallSigAlarmIgnore(); epicsSignalInstallSigPipeIgnore(); + registerRefCounter("CAChannelProvider", &CAChannelProvider::num_instances); + registerRefCounter("CAChannel", &CAChannel::num_instances); + registerRefCounter("CAChannelGet", &CAChannelGet::num_instances); + registerRefCounter("CAChannelPut", &CAChannelPut::num_instances); + registerRefCounter("CAChannelMonitor", &CAChannelMonitor::num_instances); if(ChannelProviderRegistry::clients()->add("ca", false)) epicsAtExit(&ca_factory_cleanup, NULL); diff --git a/src/ca/caProviderPvt.h b/src/ca/caProviderPvt.h index 8fb9a32..5f6bec1 100644 --- a/src/ca/caProviderPvt.h +++ b/src/ca/caProviderPvt.h @@ -30,6 +30,8 @@ class CAChannelProvider : public: POINTER_DEFINITIONS(CAChannelProvider); + static size_t num_instances; + CAChannelProvider(); CAChannelProvider(const std::tr1::shared_ptr&); virtual ~CAChannelProvider(); diff --git a/src/ca/caStatus.cpp b/src/ca/caStatus.cpp index 9eab588..3e9d352 100644 --- a/src/ca/caStatus.cpp +++ b/src/ca/caStatus.cpp @@ -4,13 +4,14 @@ * in file LICENSE that is included with this distribution. */ +#define epicsExportSharedSymbols #include namespace epics { namespace pvAccess { namespace ca { -std::string dbrStatus2alarmMessage[] = { +epicsShareDef std::string dbrStatus2alarmMessage[] = { "NO_ALARM", // 0 .. "READ_ALARM", "WRITE_ALARM", @@ -35,7 +36,7 @@ std::string dbrStatus2alarmMessage[] = { "WRITE_ACCESS_ALARM" // .. 21 }; -int dbrStatus2alarmStatus[] = { +epicsShareDef int dbrStatus2alarmStatus[] = { noStatus, //"NO_ALARM" driverStatus, //"READ_ALARM", driverStatus, //"WRITE_ALARM", diff --git a/src/ca/pv/caStatus.h b/src/ca/pv/caStatus.h index 5b8746b..33ba6f3 100644 --- a/src/ca/pv/caStatus.h +++ b/src/ca/pv/caStatus.h @@ -8,6 +8,7 @@ #define CASTATUS_H #include +#include namespace epics { namespace pvAccess { @@ -18,8 +19,8 @@ enum AlarmStatus { dbStatus,confStatus,undefinedStatus,clientStatus }; -extern std::string dbrStatus2alarmMessage[]; -extern int dbrStatus2alarmStatus[]; +epicsShareExtern std::string dbrStatus2alarmMessage[]; +epicsShareExtern int dbrStatus2alarmStatus[]; } } diff --git a/src/client/pv/pvAccess.h b/src/client/pv/pvAccess.h index 5e2630c..1515a4e 100644 --- a/src/client/pv/pvAccess.h +++ b/src/client/pv/pvAccess.h @@ -1056,7 +1056,10 @@ public: POINTER_DEFINITIONS(ChannelRequester); typedef Channel operation_type; - virtual ~ChannelRequester() {} + static size_t num_instances; + + ChannelRequester(); + virtual ~ChannelRequester(); /** * The request made with ChannelProvider::createChannel() is satisfied. diff --git a/src/client/pvAccess.cpp b/src/client/pvAccess.cpp index 731b752..c585ffb 100644 --- a/src/client/pvAccess.cpp +++ b/src/client/pvAccess.cpp @@ -4,6 +4,8 @@ * in file LICENSE that is included with this distribution. */ +#include + #define epicsExportSharedSymbols #include @@ -118,6 +120,19 @@ ChannelArray::shared_pointer Channel::createChannelArray( return ret; } + +size_t ChannelRequester::num_instances; + +ChannelRequester::ChannelRequester() +{ + REFTRACE_INCREMENT(num_instances); +} + +ChannelRequester::~ChannelRequester() +{ + REFTRACE_DECREMENT(num_instances); +} + std::string DefaultChannelRequester::getRequesterName() { return "DefaultChannelRequester"; } void DefaultChannelRequester::channelCreated(const epics::pvData::Status& status, Channel::shared_pointer const & channel) diff --git a/src/factory/ChannelAccessFactory.cpp b/src/factory/ChannelAccessFactory.cpp index 5b4a4f1..cd6a40d 100644 --- a/src/factory/ChannelAccessFactory.cpp +++ b/src/factory/ChannelAccessFactory.cpp @@ -12,10 +12,14 @@ #include #include #include +#include +#include #define epicsExportSharedSymbols #include #include +#include "pv/codec.h" +#include using namespace epics::pvData; using std::string; @@ -156,6 +160,9 @@ epicsThreadOnceId providerRegOnce = EPICS_THREAD_ONCE_INIT; void providerRegInit(void*) { providerRegGbl = new providerRegGbl_t; + registerRefCounter("ServerContext (PVA)", &ServerContextImpl::num_instances); + registerRefCounter("BlockingTCPTransportCodec", &detail::BlockingTCPTransportCodec::num_instances); + registerRefCounter("ChannelRequester", &ChannelRequester::num_instances); } } // namespace diff --git a/src/ioc/Makefile b/src/ioc/Makefile index 5e165b5..16b1349 100644 --- a/src/ioc/Makefile +++ b/src/ioc/Makefile @@ -7,11 +7,13 @@ pvAccessIOC_LIBS += pvAccess pvData pvAccessIOC_LIBS += $(EPICS_BASE_IOC_LIBS) INC += pv/syncChannelFind.h +INC += pv/iocshelper.h DBD += PVAServerRegister.dbd DBD += PVAClientRegister.dbd pvAccessIOC_SRCS += PVAServerRegister.cpp pvAccessIOC_SRCS += PVAClientRegister.cpp +pvAccessIOC_SRCS += reftrackioc.cpp include $(TOP)/configure/RULES diff --git a/src/ioc/PVAServerRegister.cpp b/src/ioc/PVAServerRegister.cpp index 24903aa..a7c386f 100644 --- a/src/ioc/PVAServerRegister.cpp +++ b/src/ioc/PVAServerRegister.cpp @@ -30,18 +30,19 @@ #include #include +#include #include -using std::cout; -using std::endl; namespace pvd = epics::pvData; namespace pva = epics::pvAccess; -static pvd::Mutex the_server_lock; -static pva::ServerContext::shared_pointer the_server; +namespace { -static void startitup() { +pvd::Mutex the_server_lock; +pva::ServerContext::shared_pointer the_server; + +void startitup() { the_server = pva::ServerContext::create(pva::ServerContext::Config() .config(pva::ConfigurationBuilder() // default to all providers instead of just "local" @@ -53,17 +54,9 @@ static void startitup() { .build())); } -static const iocshArg startPVAServerArg0 = { "providerNames", iocshArgString }; -static const iocshArg *startPVAServerArgs[] = { - &startPVAServerArg0}; - -static const iocshFuncDef startPVAServerFuncDef = { - "startPVAServer", 1, startPVAServerArgs -}; -static void startPVAServer(const iocshArgBuf *args) +void startPVAServer(const char *names) { try { - char *names = args[0].sval; if(names && names[0]!='\0') { printf("Warning: startPVAServer() no longer accepts provider list as argument.\n" " Instead place the following before calling startPVAServer() and iocInit()\n" @@ -81,11 +74,7 @@ static void startPVAServer(const iocshArgBuf *args) } } -static const iocshArg *stopPVAServerArgs[1] = {}; -static const iocshFuncDef stopPVAServerFuncDef = { - "stopPVAServer", 0, stopPVAServerArgs -}; -static void stopPVAServer(const iocshArgBuf *args) +void stopPVAServer() { try { pvd::Lock G(the_server_lock); @@ -99,11 +88,7 @@ static void stopPVAServer(const iocshArgBuf *args) } } -static const iocshArg *statusPVAServerArgs[1] = {}; -static const iocshFuncDef statusPVAServerFuncDef = { - "statusPVAServer", 0, statusPVAServerArgs -}; -static void statusPVAServer(const iocshArgBuf *args) +void statusPVAServer() { try { pvd::Lock G(the_server_lock); @@ -118,7 +103,7 @@ static void statusPVAServer(const iocshArgBuf *args) } } -static void initStartPVAServer(initHookState state) +void initStartPVAServer(initHookState state) { pvd::Lock G(the_server_lock); if(state==initHookAfterIocRunning && !the_server) { @@ -130,14 +115,16 @@ static void initStartPVAServer(initHookState state) } -static void registerStartPVAServer(void) +void registerStartPVAServer(void) { - iocshRegister(&startPVAServerFuncDef, startPVAServer); - iocshRegister(&stopPVAServerFuncDef, stopPVAServer); - iocshRegister(&statusPVAServerFuncDef, statusPVAServer); + epics::iocshRegister("startPVAServer", "provider names"); + epics::iocshRegister<&statusPVAServer>("statusPVAServer"); + epics::iocshRegister<&stopPVAServer>("stopPVAServer"); initHookRegister(&initStartPVAServer); } +} // namespace + extern "C" { epicsExportRegistrar(registerStartPVAServer); } diff --git a/src/ioc/PVAServerRegister.dbd b/src/ioc/PVAServerRegister.dbd index f8627bd..b065342 100644 --- a/src/ioc/PVAServerRegister.dbd +++ b/src/ioc/PVAServerRegister.dbd @@ -1 +1,2 @@ registrar("registerStartPVAServer") +registrar("refTrackRegistrar") diff --git a/src/ioc/pv/iocshelper.h b/src/ioc/pv/iocshelper.h new file mode 100644 index 0000000..b18dd91 --- /dev/null +++ b/src/ioc/pv/iocshelper.h @@ -0,0 +1,156 @@ +#ifndef IOCSHELPER_H +#define IOCSHELPER_H +/** Helper for exposing functions and variables in the IOC shell + * + * Limitations: + * - supports functions with up to 4 arguments + * - argument and variable types must be: int, double, char*, or const char* + * + @code + #include + void fn0() {} + void fn2(int a, const char *b) {} + int var; + void myRegistrar() { + epics::iocshRegister<&fn0>("fn0"); + epics::iocshRegister("fn0", "a description", "b description"); + epics::iocshVariable("var"); + } + extern "C" { + epicsExportRegistrar(myRegistrar); + } + @endcode + */ + +#include + +#include + +namespace epics { +namespace detail { + +template +struct getarg {}; +template<> struct getarg { + static int op(const iocshArgBuf& a) { return a.ival; } + enum { argtype = iocshArgInt }; +}; +template<> struct getarg { + static double op(const iocshArgBuf& a) { return a.dval; } + enum { argtype = iocshArgDouble }; +}; +template<> struct getarg { + static char* op(const iocshArgBuf& a) { return a.sval; } + enum { argtype = iocshArgString }; +}; +template<> struct getarg { + static const char* op(const iocshArgBuf& a) { return a.sval; } + enum { argtype = iocshArgString }; +}; + + +template +struct iocshFuncInfo{ + iocshFuncDef def; + std::string name; + iocshArg *argarr[N+1]; + iocshArg args[N+1]; + std::string argnames[N+1]; + iocshFuncInfo(const std::string& n) :name(n) { + def.name = name.c_str(); + def.nargs = N; + def.arg = (iocshArg**)&argarr; + for(size_t i=0; i + void set(const char *name) { + argnames[n] = name; + args[n].name = argnames[n].c_str(); + args[n].type = (iocshArgType)detail::getarg::argtype; + } +}; + +template +static void call0(const iocshArgBuf *args) +{ + fn(); +} + +template +static void call1(const iocshArgBuf *args) +{ + fn(getarg::op(args[0])); +} + +template +static void call2(const iocshArgBuf *args) +{ + fn(getarg::op(args[0]), + getarg::op(args[1])); +} + +template +static void call3(const iocshArgBuf *args) +{ + fn(getarg::op(args[0]), + getarg::op(args[1]), + getarg::op(args[2])); +} + +} // namespace detail + + +template +void iocshRegister(const char *name) +{ + static detail::iocshFuncInfo<0> info(name); + iocshRegister(&info.def, &detail::call0); +} + +template +void iocshRegister(const char *name, const char *arg1name) +{ + static detail::iocshFuncInfo<1> info(name); + info.set<0,A>(arg1name); + iocshRegister(&info.def, &detail::call1); +} + +template +void iocshRegister(const char *name, + const char *arg1name, + const char *arg2name) +{ + static detail::iocshFuncInfo<2> info(name); + info.set<0,A>(arg1name); + info.set<1,B>(arg2name); + iocshRegister(&info.def, &detail::call2); +} + +template +void iocshRegister(const char *name, + const char *arg1name, + const char *arg2name, + const char *arg3name) +{ + static detail::iocshFuncInfo<3> info(name); + info.set<0,A>(arg1name); + info.set<1,B>(arg2name); + info.set<2,C>(arg3name); + iocshRegister(&info.def, &detail::call3); +} + +template +void iocshVariable(const char *name) +{ + static iocshVarDef def[2]; + def[0].name = name; + def[0].pval = (void*)addr; + def[0].type = (iocshArgType)detail::getarg::argtype; + def[1].name = NULL; + iocshRegisterVariable(def); +} + +} // namespace epics + +#endif // IOCSHELPER_H diff --git a/src/ioc/reftrackioc.cpp b/src/ioc/reftrackioc.cpp new file mode 100644 index 0000000..979b4a6 --- /dev/null +++ b/src/ioc/reftrackioc.cpp @@ -0,0 +1,90 @@ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ + +#include + +#include +#include + +#include + +#include + +namespace { + +void showRefs(const epics::RefSnapshot& snap, int lvl, bool delta) +{ + for(epics::RefSnapshot::const_iterator it = snap.begin(), end = snap.end(); + it != end; ++it) + { + if(it->second.current==0 && it->second.delta==0 && lvl<=0) continue; + if(delta && it->second.delta==0 && lvl<=0) continue; + if(delta) { + printf(" %s : %zu (delta %zd)\n", + it->first.c_str(), it->second.current, it->second.delta); + } else { + printf(" %s : %zu\n", it->first.c_str(), it->second.current); + } + } +} + +#define CATCH() catch(std::exception& e){printf("Error %s\n", e.what());} + +void refshow(int lvl) +{ + try { + epics::RefSnapshot snap; + snap.update(); + + showRefs(snap, lvl, false); + }CATCH() +} + +// No locking. assume only interactive iocsh use +static epics::RefSnapshot savedSnap; + +void refsave() +{ + try { + epics::RefSnapshot snap; + snap.update(); + + savedSnap.swap(snap); + }CATCH() +} + +void refdiff(int lvl) +{ + epics::RefSnapshot snap; + snap.update(); + + showRefs(snap-savedSnap, lvl, true); +} + +static epics::RefMonitor gblmon; + +void refmon(double period, int lvl) +{ + if(period==0) { + gblmon.stop(); + } else if(period>0) { + gblmon.start(period); + } +} + +void refTrackRegistrar() +{ + epics::iocshRegister("refshow", "detail level"); + epics::iocshRegister<&refsave>("refsave"); + epics::iocshRegister("refdiff", "detail level"); + epics::iocshRegister("refmon", "update period", "detail level"); +} + +} // namespace + +extern "C" { + epicsExportRegistrar(refTrackRegistrar); +} diff --git a/src/remote/codec.cpp b/src/remote/codec.cpp index da7cc12..14208dc 100644 --- a/src/remote/codec.cpp +++ b/src/remote/codec.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #define epicsExportSharedSymbols #include @@ -1001,6 +1002,8 @@ bool AbstractCodec::directDeserialize(ByteBuffer *existingBuffer, char* deserial BlockingTCPTransportCodec::~BlockingTCPTransportCodec() { + REFTRACE_DECREMENT(num_instances); + waitJoin(); } @@ -1138,6 +1141,7 @@ void BlockingTCPTransportCodec::sendBufferFull(int tries) { // // +size_t BlockingTCPTransportCodec::num_instances; BlockingTCPTransportCodec::BlockingTCPTransportCodec(bool serverFlag, const Context::shared_pointer &context, SOCKET channel, const ResponseHandler::shared_pointer &responseHandler, @@ -1163,6 +1167,8 @@ BlockingTCPTransportCodec::BlockingTCPTransportCodec(bool serverFlag, const Cont ,_remoteTransportRevision(0), _priority(priority) ,_verified(false) { + REFTRACE_INCREMENT(num_instances); + _isOpen.getAndSet(true); // get remote address diff --git a/src/remote/pv/codec.h b/src/remote/pv/codec.h index afa082c..42162d2 100644 --- a/src/remote/pv/codec.h +++ b/src/remote/pv/codec.h @@ -302,6 +302,8 @@ public: POINTER_DEFINITIONS(BlockingTCPTransportCodec); + static size_t num_instances; + BlockingTCPTransportCodec( bool serverFlag, Context::shared_pointer const & context, diff --git a/src/remote/pv/remote.h b/src/remote/pv/remote.h index 9d9b7fb..5407d0e 100644 --- a/src/remote/pv/remote.h +++ b/src/remote/pv/remote.h @@ -374,15 +374,9 @@ public: epics::pvData::ByteBuffer* payloadBuffer) = 0; }; -/** - * Base (abstract) channel access response handler. - */ class AbstractResponseHandler : public ResponseHandler { public: - /** - * @param description - */ - AbstractResponseHandler(Context* context, std::string description) : + AbstractResponseHandler(Context* context, const std::string& description) : _description(description), _debugLevel(context->getConfiguration()->getPropertyAsInteger(PVACCESS_DEBUG, 0)) { } diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index ad733e1..68ac87b 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #define epicsExportSharedSymbols #include @@ -165,6 +166,9 @@ protected: return std::tr1::static_pointer_cast(P); } public: + static size_t num_instances; + static size_t num_active; + template static typename std::tr1::shared_ptr @@ -180,6 +184,7 @@ public: const_cast(internal->m_this_internal) = internal; const_cast(internal->m_this_external) = external; internal->activate(); + REFTRACE_INCREMENT(num_active); return external; } protected: @@ -197,9 +202,13 @@ protected: m_destroyed(false), m_initialized(false), m_subscribed() - {} + { + REFTRACE_INCREMENT(num_instances); + } - virtual ~BaseRequestImpl() {} + virtual ~BaseRequestImpl() { + REFTRACE_DECREMENT(num_instances); + } virtual void activate() { // register response request @@ -344,6 +353,8 @@ public: } } + + REFTRACE_DECREMENT(num_active); } virtual void timeout() OVERRIDE FINAL { @@ -396,6 +407,8 @@ public: }; +size_t BaseRequestImpl::num_instances; +size_t BaseRequestImpl::num_active; PVDataCreatePtr BaseRequestImpl::pvDataCreate = getPVDataCreate(); @@ -3248,6 +3261,11 @@ private: */ ServerGUID m_guid; + public: + static size_t num_instances; + static size_t num_active; + private: + /** * Constructor. * @param context @@ -3275,6 +3293,7 @@ private: m_serverChannelID(0xFFFFFFFF), m_issueCreateMessage(true) { + REFTRACE_INCREMENT(num_instances); PVACCESS_REFCOUNT_MONITOR_CONSTRUCT(channel); } @@ -3285,6 +3304,8 @@ private: // connect connect(); + + REFTRACE_INCREMENT(num_active); } public: @@ -3307,11 +3328,15 @@ private: virtual ~InternalChannelImpl() { + REFTRACE_DECREMENT(num_instances); + PVACCESS_REFCOUNT_MONITOR_DESTRUCT(channel); } virtual void destroy() OVERRIDE FINAL { + REFTRACE_DECREMENT(num_active); + destroy(false); } @@ -4035,6 +4060,7 @@ public: public: + static size_t num_instances; InternalClientContextImpl(const Configuration::shared_pointer& conf) : m_addressList(""), m_autoAddressList(true), m_connectionTimeout(30.0f), m_beaconPeriod(15.0f), @@ -4049,6 +4075,8 @@ public: m_configuration(conf), m_flushStrategy(DELAYED) { + REFTRACE_INCREMENT(num_instances); + PVACCESS_REFCOUNT_MONITOR_CONSTRUCT(remoteClientContext); MB_INIT; if(!m_configuration) m_configuration = ConfigurationFactory::getConfiguration("pvAccess-client"); @@ -4148,6 +4176,7 @@ public: virtual ~InternalClientContextImpl() { + REFTRACE_DECREMENT(num_instances); PVACCESS_REFCOUNT_MONITOR_DESTRUCT(remoteClientContext); } @@ -4716,6 +4745,10 @@ private: FlushStrategy m_flushStrategy; }; +size_t InternalClientContextImpl::num_instances; +size_t InternalClientContextImpl::InternalChannelImpl::num_instances; +size_t InternalClientContextImpl::InternalChannelImpl::num_active; + PVACCESS_REFCOUNT_MONITOR_DEFINE(channelGetField); class ChannelGetFieldRequestImpl : @@ -4908,6 +4941,11 @@ namespace pvAccess { ChannelProvider::shared_pointer createClientProvider(const Configuration::shared_pointer& conf) { + registerRefCounter("InternalClientContextImpl", &InternalClientContextImpl::num_instances); + registerRefCounter("InternalChannelImpl", &InternalClientContextImpl::InternalChannelImpl::num_instances); + registerRefCounter("InternalChannelImpl (Active)", &InternalClientContextImpl::InternalChannelImpl::num_active); + registerRefCounter("BaseRequestImpl", &BaseRequestImpl::num_instances); + registerRefCounter("BaseRequestImpl (Active)", &BaseRequestImpl::num_active); InternalClientContextImpl::shared_pointer internal(new InternalClientContextImpl(conf)), external(internal.get(), epics::pvAccess::Destroyable::cleaner(internal)); const_cast(internal->m_external_this) = external; diff --git a/src/server/pv/serverContextImpl.h b/src/server/pv/serverContextImpl.h index 1d63d47..c7addf9 100644 --- a/src/server/pv/serverContextImpl.h +++ b/src/server/pv/serverContextImpl.h @@ -32,6 +32,8 @@ public: typedef std::tr1::shared_ptr shared_pointer; typedef std::tr1::shared_ptr const_shared_pointer; + static size_t num_instances; + ServerContextImpl(); virtual ~ServerContextImpl(); diff --git a/src/server/serverContext.cpp b/src/server/serverContext.cpp index 08331f7..73fcb0e 100644 --- a/src/server/serverContext.cpp +++ b/src/server/serverContext.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #define epicsExportSharedSymbols #include @@ -27,6 +28,8 @@ namespace pvAccess { const Version ServerContextImpl::VERSION("pvAccess Server", "cpp", EPICS_PVA_MAJOR_VERSION, EPICS_PVA_MINOR_VERSION, EPICS_PVA_MAINTENANCE_VERSION, EPICS_PVA_DEVELOPMENT_FLAG); +size_t ServerContextImpl::num_instances; + ServerContextImpl::ServerContextImpl(): _beaconAddressList(), _ignoreAddressList(), @@ -43,6 +46,8 @@ ServerContextImpl::ServerContextImpl(): _beaconServerStatusProvider(), _startTime() { + REFTRACE_INCREMENT(num_instances); + epicsTimeGetCurrent(&_startTime); // TODO maybe there is a better place for this (when there will be some factory) @@ -63,6 +68,7 @@ ServerContextImpl::~ServerContextImpl() { std::cerr<<"Error in: ServerContextImpl::dispose: "<