/* * Copyright information and license terms for this software can be * found in the file LICENSE that is included with the distribution */ #include #include #include #include #include #include #include #include #include #include #include #include #define epicsExportSharedSymbols #include #include #include "pv/reftrack.h" namespace { #ifndef REFTRACK_USE_ATOMIC static inline size_t readref(const size_t *ref) { volatile const size_t *vref = ref; return *vref; } #endif typedef epicsGuard Guard; typedef epicsGuardRelease UnGuard; struct refgbl_t { epicsMutex lock; typedef std::map counters_t; counters_t counters; } *refgbl; void refgbl_init(void *) { try { refgbl = new refgbl_t; } catch(std::exception& e) { std::cerr<<"Failed to initialize global ref. counter registry :"<lock); refgbl->counters[name] = counter; } void unregisterRefCounter(const char *name, const size_t* counter) { refgbl_setup(); Guard G(refgbl->lock); refgbl_t::counters_t::iterator it(refgbl->counters.find(name)); if(it!=refgbl->counters.end() && it->second==counter) refgbl->counters.erase(it); } size_t readRefCounter(const char *name) { refgbl_setup(); Guard G(refgbl->lock); refgbl_t::counters_t::iterator it(refgbl->counters.find(name)); if(it==refgbl->counters.end()) return 0; #ifdef REFTRACK_USE_ATOMIC return atomic::get(*it->second); #else return readref(it->second); #endif } const RefSnapshot::Count& RefSnapshot::operator[](const std::string& name) const { static const Count zero; cnt_map_t::const_iterator it(counts.find(name)); return it==counts.end() ? zero : it->second; } void RefSnapshot::update() { refgbl_t::counters_t counters; { refgbl_setup(); Guard G(refgbl->lock); counters = refgbl->counters; // copy } counts.clear(); for(refgbl_t::counters_t::const_iterator it=counters.begin(), end=counters.end(); it!=end; ++it) { #ifdef REFTRACK_USE_ATOMIC size_t cnt = atomic::get(*it->second); #else size_t cnt = readref(it->second); #endif counts[it->first] = Count(cnt, 0); } } RefSnapshot RefSnapshot::operator-(const RefSnapshot& rhs) const { RefSnapshot ret; RefSnapshot::cnt_map_t::const_iterator lit = counts.begin(), lend= counts.end(), rit = rhs.counts.begin(), rend= rhs.counts.end(); while(lit!=lend || rit!=rend) { if(lit==lend || (rit!=rend && lit->first > rit->first)) { ret.counts[rit->first] = RefSnapshot::Count(0, -long(rit->second.current)); ++rit; } else if(rit==rend || lit->first < rit->first) { ret.counts[lit->first] = RefSnapshot::Count(lit->second.current, long(lit->second.current)); ++lit; } else { // !end and lit->first == rit->first ret.counts[lit->first] = RefSnapshot::Count(lit->second.current, long(lit->second.current) - long(rit->second.current)); ++lit; ++rit; } } return ret; } std::ostream& operator<<(std::ostream& strm, const RefSnapshot& snap) { for(RefSnapshot::const_iterator it = snap.begin(), end = snap.end(); it!=end; ++it) { if(it->second.delta==0) continue; strm<first<<":\t"<second.current<<" (delta "<second.delta<<")\n"; } return strm; } struct RefMonitor::Impl : public epicsThreadRunable { RefMonitor& owner; epics::auto_ptr worker; epicsMutex lock; epicsEvent wakeup; RefSnapshot prev; bool done; double period; Impl(RefMonitor* owner) :owner(*owner), done(false), period(10.0) {} virtual ~Impl() {} virtual void run() { Guard G(lock); while(!done) { RefSnapshot current, P; P = prev; // copy { UnGuard U(G); current.update(); owner.show(current-P); } prev.swap(current); { UnGuard U(G); wakeup.wait(period); } } } }; RefMonitor::RefMonitor() :impl(new Impl(this)) {} RefMonitor::~RefMonitor() { stop(); delete impl; } void RefMonitor::start(double period) { Guard G(impl->lock); if(impl->worker.get()) return; impl->done = false; impl->period = period; impl->worker.reset(new epicsThread(*impl, "RefMonitor", epicsThreadGetStackSize(epicsThreadStackBig), epicsThreadPriorityMin)); impl->worker->start(); } void RefMonitor::stop() { epics::auto_ptr W; { Guard G(impl->lock); if(!impl->worker.get()) return; epics::swap(W, impl->worker); impl->done = true; } impl->wakeup.signal(); W->exitWait(); W.reset(); } bool RefMonitor::running() const { Guard G(impl->lock); return !!impl->worker.get(); } void RefMonitor::current() { RefSnapshot current, P; current.update(); { Guard G(impl->lock); P = impl->prev; // copy } show(current-P, true); } void RefMonitor::show(const RefSnapshot &snap, bool complete) { char buf[80]; epicsTime::getCurrent().strftime(buf, sizeof(buf), "%a %b %d %Y %H:%M:%S.%f"); buf[sizeof(buf)-1] = '\0'; std::cerr<second.delta==0 && (!complete || it->second.current==0)) continue; std::cerr<first<<":\t"<second.current<<" (delta "<second.delta<<")\n"; } } } // namespace epics char* epicsRefSnapshotCurrent() { try { epics::RefSnapshot snap; snap.update(); std::ostringstream strm; strm<