/** * Copyright - See the COPYRIGHT that is included with this distribution. * pvAccessCPP is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. */ #define epicsExportSharedSymbols #include #include namespace pvd = epics::pvData; namespace epics { namespace pvAccess { bool TransportRegistry::Key::operator<(const Key& o) const { if(addr.sa.sa_familyo.addr.sa.sa_family) return false; if(addr.ia.sin_addr.s_addro.addr.ia.sin_addr.s_addr) return false; if(addr.ia.sin_porto.addr.ia.sin_port) return false; if(prio_mutex); std::tr1::shared_ptr& lock = owner->locks[key]; // fetch or alloc if(!lock) lock.reset(new pvd::Mutex()); mutex = lock; } mutex->lock(); } TransportRegistry::Reservation::~Reservation() { mutex->unlock(); pvd::Lock G(owner->_mutex); assert(mutex.use_count()>=2); if(mutex.use_count()==2) { // no other concurrent connect(), so can drop this lock owner->locks.erase(key); } assert(mutex.use_count()==1); } TransportRegistry::~TransportRegistry() { pvd::Lock G(_mutex); if(!transports.empty()) LOG(logLevelWarn, "TransportRegistry destroyed while not empty"); } Transport::shared_pointer TransportRegistry::get(const osiSockAddr& address, epics::pvData::int16 prio) { const Key key(address, prio); pvd::Lock G(_mutex); transports_t::iterator it(transports.find(key)); if(it!=transports.end()) { return it->second; } return Transport::shared_pointer(); } void TransportRegistry::install(const Transport::shared_pointer& ptr) { const Key key(ptr->getRemoteAddress(), ptr->getPriority()); pvd::Lock G(_mutex); std::pair itpair(transports.insert(std::make_pair(key, ptr))); if(!itpair.second) THROW_EXCEPTION2(std::logic_error, "Refuse to insert dup"); } Transport::shared_pointer TransportRegistry::remove(Transport::shared_pointer const & transport) { assert(!!transport); const Key key(transport->getRemoteAddress(), transport->getPriority()); Transport::shared_pointer ret; pvd::Lock guard(_mutex); transports_t::iterator it(transports.find(key)); if(it!=transports.end()) { ret.swap(it->second); transports.erase(it); } return ret; } #define LEAK_CHECK(PTR, NAME) if((PTR) && !(PTR).unique()) { std::cerr<<"Leaking Transport " NAME " use_count="<<(PTR).use_count()<<"\n"<second->close(); } for(transports_t::iterator it(temp.begin()), end(temp.end()); it != end; ++it) { const Transport::shared_pointer& transport = it->second; transport->waitJoin(); LEAK_CHECK(transport, "tcp transport") if(!transport.unique()) { LOG(logLevelError, "Closed transport %s still has use_count=%u", transport->getRemoteName().c_str(), (unsigned)transport.use_count()); } } } size_t TransportRegistry::size() { pvd::Lock guard(_mutex); return transports.size(); } void TransportRegistry::toArray(transportVector_t & transportArray, const osiSockAddr *dest) { pvd::Lock guard(_mutex); transportArray.reserve(transportArray.size() + transports.size()); for(transports_t::const_iterator it(transports.begin()), end(transports.end()); it != end; ++it) { const Key& key = it->first; const Transport::shared_pointer& tr = it->second; if(!dest || sockAddrAreIdentical(dest, &key.addr)) transportArray.push_back(tr); } } } }