diff --git a/examples/getme.cpp b/examples/getme.cpp index 21f19cb..fdf2632 100644 --- a/examples/getme.cpp +++ b/examples/getme.cpp @@ -114,7 +114,7 @@ int main(int argc, char *argv[]) { std::cout<<"Usage: "<] [-w ] [-R] ...\n"; return 0; default: - std::cerr<<"Unknown argument: "<] [-w ] [-r ] [-R] ...\n"; return 0; default: - std::cerr<<"Unknown argument: "<createFieldBuilder() + ->setId("epics:nt/NTScalar:1.0") ->add("value", pvd::pvInt) ->createStructure()); diff --git a/pvtoolsSrc/pvput.cpp b/pvtoolsSrc/pvput.cpp index 8a36926..db5ae9a 100644 --- a/pvtoolsSrc/pvput.cpp +++ b/pvtoolsSrc/pvput.cpp @@ -269,6 +269,8 @@ struct Putter : public pvac::ClientChannel::PutCallback shared_vector jarr; + PVStructure::const_shared_pointer current; + virtual void putBuild(const epics::pvData::StructureConstPtr& build, Args& args) { if(debug) std::cerr<<"Server defined structure\n"<(fld.get())); PVScalar* idxfld(sfld->getSubFieldT("index").get()); - PVStringArray::const_svector choices(sfld->getSubFieldT("choices")->view()); + PVStringArray::const_svector choices(current->getSubFieldT("value.choices")->view()); bool found=false; for(size_t i=0; iputFrom(i); found=true; + break; } } @@ -615,9 +618,11 @@ int main (int argc, char *argv[]) pvac::ClientChannel chan(ctxt.connect(pvName)); + thework.current = chan.get(timeOut, pvRequest); + if (mode != TerseMode && !quiet) { std::cout << "Old : "; - printValue(pvName, chan.get(timeOut, pvRequest)); + printValue(pvName, thework.current); } { diff --git a/src/client/clientMonitor.cpp b/src/client/clientMonitor.cpp index 2a7c321..8b7debd 100644 --- a/src/client/clientMonitor.cpp +++ b/src/client/clientMonitor.cpp @@ -196,16 +196,29 @@ bool Monitor::poll() Guard G(impl->mutex); if(!impl->done && impl->last.next()) { - root = impl->last->pvStructurePtr; + const epics::pvData::PVStructurePtr& ptr = impl->last->pvStructurePtr; changed = *impl->last->changedBitSet; overrun = *impl->last->overrunBitSet; + /* copy the exposed PVStructure for two reasons. + * 1. Prevent accidental use of shared container after release() + * 2. Allows caller to cache results of getSubField() until root.get() changes. + */ + if(!root || (void*)root->getField().get()!=(void*)ptr->getField().get()) { + // initial connection, or new type + root = pvd::getPVDataCreate()->createPVStructure(ptr); // also calls copyUnchecked() + } else { + // same type + const_cast(*root).copyUnchecked(*ptr, changed); + } + + impl->seenEmpty = false; } else { - root.reset(); changed.clear(); overrun.clear(); + impl->seenEmpty = true; } - return impl->seenEmpty = !!root; + return !impl->seenEmpty; } bool Monitor::complete() const diff --git a/src/client/pva/client.h b/src/client/pva/client.h index e9b6897..21f6b3a 100644 --- a/src/client/pva/client.h +++ b/src/client/pva/client.h @@ -104,13 +104,31 @@ struct epicsShareClass Monitor void cancel(); /** updates root, changed, overrun * - * @return true if root!=NULL + * @return true if a new update was extracted from the queue. + * @note This method does not block. * @note MonitorEvent::Data will not be repeated until poll()==false. + * @post root!=NULL (after version 6.0.0) + * @post root!=NULL iff poll()==true (In version 6.0.0) */ bool poll(); //! true if all events received. //! Check after poll()==false bool complete() const; + /** Monitor update data. + * + * After version 6.0.0 + * + * Initially NULL, becomes !NULL the first time poll()==true. + * The PVStructure pointed to be root will presist until + * Monitor reconnect w/ type change. This can be detected + * by comparing `root.get()`. references to root may be cached + * subject to this test. + * + * In version 6.0.0 + * + * NULL except after poll()==true. poll()==false sets root=NULL. + * references to root should not be stored between calls to poll(). + */ epics::pvData::PVStructure::const_shared_pointer root; epics::pvData::BitSet changed, overrun; diff --git a/src/ioc/PVAServerRegister.cpp b/src/ioc/PVAServerRegister.cpp index 6360914..fbee91f 100644 --- a/src/ioc/PVAServerRegister.cpp +++ b/src/ioc/PVAServerRegister.cpp @@ -46,7 +46,7 @@ void startitup() { the_server = pva::ServerContext::create(pva::ServerContext::Config() .config(pva::ConfigurationBuilder() // default to all providers instead of just "local" - .add("EPICS_PVAS_PROVIDER_NAMES", PVACCESS_ALL_PROVIDERS) + .add("EPICS_PVAS_PROVIDER_NAMES", pva::PVACCESS_ALL_PROVIDERS) .push_map() // prefer to use EPICS_PVAS_PROVIDER_NAMES // from environment diff --git a/src/pva/pv/pvaConstants.h b/src/pva/pv/pvaConstants.h index 408d96f..9ee652d 100644 --- a/src/pva/pv/pvaConstants.h +++ b/src/pva/pv/pvaConstants.h @@ -67,19 +67,19 @@ const epics::pvData::int16 PVA_DEFAULT_PRIORITY = 0; const epics::pvData::uint32 MAX_CHANNEL_NAME_LENGTH = 500; /** Invalid data type. */ -const epics::pvData::int16 INVALID_DATA_TYPE = static_cast(0xFFFF); +const epics::pvData::int16 INVALID_DATA_TYPE = 0xFFFF; /** Invalid IOID. */ const epics::pvData::int32 INVALID_IOID = 0; /** Default PVA provider name. */ -#define PVACCESS_DEFAULT_PROVIDER "local" +const std::string PVACCESS_DEFAULT_PROVIDER; /** "All-providers registered" PVA provider name. */ -#define PVACCESS_ALL_PROVIDERS "" +const std::string PVACCESS_ALL_PROVIDERS; /** Name of the system env. variable to turn on debugging. */ -#define PVACCESS_DEBUG "EPICS_PVA_DEBUG" +const std::string PVACCESS_DEBUG; } } diff --git a/src/pva/pvaVersion.cpp b/src/pva/pvaVersion.cpp index b925442..f196242 100644 --- a/src/pva/pvaVersion.cpp +++ b/src/pva/pvaVersion.cpp @@ -15,6 +15,10 @@ using std::string; namespace epics { namespace pvAccess { +const std::string PVACCESS_DEFAULT_PROVIDER = "local"; +const std::string PVACCESS_ALL_PROVIDERS = ""; +const std::string PVACCESS_DEBUG = "EPICS_PVA_DEBUG"; + Version::Version(std::string const & productName, std::string const & implementationLangugage, int majorVersion, int minorVersion, diff --git a/src/remote/codec.cpp b/src/remote/codec.cpp index 3ed6b93..cd45e83 100644 --- a/src/remote/codec.cpp +++ b/src/remote/codec.cpp @@ -337,7 +337,7 @@ void AbstractCodec::processReadSegmented() { " %s:%d: %s, disconnecting...", __FILE__, __LINE__, inetAddressToString(*getLastReadBufferSocketAddress()).c_str()); invalidDataStreamHandler(); - throw new invalid_data_stream_exception( + throw invalid_data_stream_exception( "not-a-first segmented message expected"); } @@ -1586,11 +1586,11 @@ void BlockingServerTCPTransportCodec::destroyAllChannels() { _socketName.c_str(), _channels.size()); } - std::map::iterator it = _channels.begin(); - for(; it!=_channels.end(); it++) - it->second->destroy(); + _channels_t temp; + temp.swap(_channels); - _channels.clear(); + for(_channels_t::iterator it(temp.begin()), end(temp.end()); it!=end; ++it) + it->second->destroy(); } void BlockingServerTCPTransportCodec::internalClose(bool force) { diff --git a/src/remote/transportRegistry.cpp b/src/remote/transportRegistry.cpp index 62dfb45..952a0fa 100644 --- a/src/remote/transportRegistry.cpp +++ b/src/remote/transportRegistry.cpp @@ -74,28 +74,6 @@ TransportRegistry::~TransportRegistry() if(!transports.empty()) LOG(logLevelWarn, "TransportRegistry destroyed while not empty"); } -/* -void -TransportRegistry::get(const osiSockAddr* address, transportVector_t& output) -{ - pvd::Lock guard(_mutex); - transportsMap_t::iterator transportsIter = _transports.find(address); - if(transportsIter != _transports.end()) - { - prioritiesMapSharedPtr_t& priorities = transportsIter->second; - - size_t i = output.size(); - output.resize(output.size() + priorities->size()); - - for(prioritiesMap_t::iterator prioritiesIter = priorities->begin(); - prioritiesIter != priorities->end(); - prioritiesIter++, i++) - { - output[i] = prioritiesIter->second; - } - } -} -*/ Transport::shared_pointer TransportRegistry::get(const osiSockAddr& address, epics::pvData::int16 prio) { @@ -124,19 +102,14 @@ void TransportRegistry::install(const Transport::shared_pointer& ptr) 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); - for(transports_t::iterator it(transports.begin()), end(transports.end()); - it != end; ++it) - { - Transport::shared_pointer& tr = it->second; - - if(transport.get() == tr.get()) { - ret.swap(it->second); - transports.erase(it); - break; - } + transports_t::iterator it(transports.find(key)); + if(it!=transports.end()) { + ret.swap(it->second); + transports.erase(it); } return ret; } diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 3800503..18ce6b1 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -3828,7 +3828,9 @@ public: for(size_t i=0, N=ops.size(); igetRequester()->channelDisconnect(connectionState==Channel::DESTROYED);) + ChannelBaseRequester::shared_pointer req(R->getRequester()); + if(!req) continue; + EXCEPTION_GUARD(req->channelDisconnect(connectionState==Channel::DESTROYED);) } } } diff --git a/src/server/responseHandlers.cpp b/src/server/responseHandlers.cpp index f666994..8267292 100644 --- a/src/server/responseHandlers.cpp +++ b/src/server/responseHandlers.cpp @@ -2035,7 +2035,7 @@ void ServerMonitorRequesterImpl::destroy() // hold a reference to channelMonitor so that _channelMonitor.reset() // does not call ~Monitor (external code) while we are holding a lock - Monitor::shared_pointer monitor = _channelMonitor; + Monitor::shared_pointer monitor(_channelMonitor); { Lock guard(_mutex); _channel->unregisterRequest(_ioid); diff --git a/src/server/serverContext.cpp b/src/server/serverContext.cpp index 3d7a969..3ba9364 100644 --- a/src/server/serverContext.cpp +++ b/src/server/serverContext.cpp @@ -362,13 +362,6 @@ void ServerContextImpl::shutdown() void ServerContextImpl::destroyAllTransports() { - TransportRegistry::transportVector_t transports; - _transportRegistry.toArray(transports); - - size_t size = transports.size(); - if (size == 0) - return; - // now clear all (release) _transportRegistry.clear(); } diff --git a/src/utils/pv/fairQueue.h b/src/utils/pv/fairQueue.h index b3c30df..20447ff 100644 --- a/src/utils/pv/fairQueue.h +++ b/src/utils/pv/fairQueue.h @@ -72,9 +72,7 @@ public: } enode; unsigned Qcnt; value_type holder; -#ifndef NDEBUG fair_queue *owner; -#endif friend class fair_queue; @@ -82,9 +80,7 @@ public: entry& operator=(const entry&); public: entry() :Qcnt(0), holder() -#ifndef NDEBUG , owner(NULL) -#endif { enode.node.next = enode.node.previous = NULL; enode.self = this; @@ -92,9 +88,8 @@ public: ~entry() { // nodes should be removed from the list before deletion assert(!enode.node.next && !enode.node.previous); -#ifndef NDEBUG + assert(Qcnt==0 && !holder); assert(!owner); -#endif } }; @@ -144,6 +139,7 @@ public: bool pop_front_try(value_type& ret) { + ret.reset(); guard_t G(mutex); ELLNODE *cur = ellGet(&list); // pop_front @@ -165,7 +161,6 @@ public: } return true; } else { - ret.reset(); return false; } }