From 568054ce6898b860f5e00995cfa827843f44f1dd Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 10 May 2017 15:34:18 -0400 Subject: [PATCH 001/189] add virtual dtors being pedantic... --- src/client/pv/pvAccess.h | 41 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/src/client/pv/pvAccess.h b/src/client/pv/pvAccess.h index d8430f7..ced7d53 100644 --- a/src/client/pv/pvAccess.h +++ b/src/client/pv/pvAccess.h @@ -134,6 +134,8 @@ class epicsShareClass ChannelRequest : public epics::pvData::Destroyable, public public: POINTER_DEFINITIONS(ChannelRequest); + virtual ~ChannelRequest() {} + /** * Get a channel instance this request belongs to. * @return the channel instance. @@ -166,6 +168,8 @@ public: POINTER_DEFINITIONS(ChannelArray); typedef ChannelArrayRequester requester_type; + virtual ~ChannelArray() {} + /** * put to the remote array. * @param putArray array to put. @@ -205,6 +209,8 @@ public: POINTER_DEFINITIONS(ChannelArrayRequester); typedef ChannelArray operation_type; + virtual ~ChannelArrayRequester() {} + /** * The client and server have both completed the createChannelArray request. * @param status Completion status. @@ -266,6 +272,8 @@ public: POINTER_DEFINITIONS(ChannelFind); typedef ChannelFindRequester requester_type; + virtual ~ChannelFind() {} + virtual std::tr1::shared_ptr getChannelProvider() = 0; virtual void cancel() = 0; }; @@ -278,7 +286,7 @@ public: POINTER_DEFINITIONS(ChannelFindRequester); typedef ChannelFind operation_type; - virtual ~ChannelFindRequester() {}; + virtual ~ChannelFindRequester() {} /** * @param status Completion status. @@ -297,7 +305,7 @@ public: POINTER_DEFINITIONS(ChannelListRequester); typedef ChannelFind operation_type; - virtual ~ChannelListRequester() {}; + virtual ~ChannelListRequester() {} /** * @param status Completion status. @@ -317,6 +325,8 @@ public: POINTER_DEFINITIONS(ChannelGet); typedef ChannelGetRequester requester_type; + virtual ~ChannelGet() {} + /** * Get data from the channel. * Completion status is reported by calling ChannelGetRequester.getDone() callback. @@ -333,6 +343,8 @@ public: POINTER_DEFINITIONS(ChannelGetRequester); typedef ChannelGet operation_type; + virtual ~ChannelGetRequester() {} + /** * The client and server have both completed the createChannelGet request. * @param status Completion status. @@ -367,6 +379,8 @@ public: POINTER_DEFINITIONS(ChannelProcess); typedef ChannelProcessRequester requester_type; + virtual ~ChannelProcess() {} + /** * Issue a process request. * Completion status is reported by calling ChannelProcessRequester.processDone() callback. @@ -383,6 +397,8 @@ public: POINTER_DEFINITIONS(ChannelProcessRequester); typedef ChannelProcess operation_type; + virtual ~ChannelProcessRequester() {} + /** * The client and server have both completed the createChannelProcess request. * @param status Completion status. @@ -412,6 +428,8 @@ public: POINTER_DEFINITIONS(ChannelPut); typedef ChannelPutRequester requester_type; + virtual ~ChannelPut() {} + /** * Put data to a channel. * Completion status is reported by calling ChannelPutRequester.putDone() callback. @@ -437,6 +455,8 @@ public: POINTER_DEFINITIONS(ChannelPutRequester); typedef ChannelPut operation_type; + virtual ~ChannelPutRequester() {} + /** * The client and server have both processed the createChannelPut request. * @param status Completion status. @@ -481,6 +501,8 @@ public: POINTER_DEFINITIONS(ChannelPutGet); typedef ChannelPutGetRequester requester_type; + virtual ~ChannelPutGet() {} + /** * Issue a put/get request. If process was requested when the ChannelPutGet was created this is a put, process, get. * Completion status is reported by calling ChannelPutGetRequester.putGetDone() callback. @@ -514,6 +536,8 @@ public: POINTER_DEFINITIONS(ChannelPutGetRequester); typedef ChannelPutGet operation_type; + virtual ~ChannelPutGetRequester() {} + /** * The client and server have both completed the createChannelPutGet request. * @param status Completion status. @@ -576,6 +600,8 @@ public: POINTER_DEFINITIONS(ChannelRPC); typedef ChannelRPCRequester requester_type; + virtual ~ChannelRPC() {} + /** * Issue an RPC request to the channel. * Completion status is reported by calling ChannelRPCRequester.requestDone() callback. @@ -593,6 +619,8 @@ public: POINTER_DEFINITIONS(ChannelRPCRequester); typedef ChannelRPC operation_type; + virtual ~ChannelRPCRequester() {} + /** * The client and server have both completed the createChannelGet request. * @param status Completion status. @@ -622,6 +650,8 @@ class epicsShareClass GetFieldRequester : virtual public Requester { public: POINTER_DEFINITIONS(GetFieldRequester); + virtual ~GetFieldRequester() {} + /** * The client and server have both completed the getStructure request. * @param status Completion status. @@ -667,7 +697,6 @@ public: * @return The channel provider. */ virtual std::tr1::shared_ptr getProvider() = 0; -// virtual ChannelProvider::shared_pointer getProvider() = 0; /** * Returns the channel's remote address, signal name, etc... @@ -828,6 +857,8 @@ public: POINTER_DEFINITIONS(ChannelRequester); typedef Channel operation_type; + virtual ~ChannelRequester() {} + /** * A channel has been created. This may be called multiple times if there are multiple providers. * @param status Completion status. @@ -871,6 +902,8 @@ public: /** OPI priority. */ static const short PRIORITY_OPI = PRIORITY_MIN; + virtual ~ChannelProvider() {} + /** * Get the provider name. * @return The name. @@ -927,7 +960,7 @@ class epicsShareClass ChannelProviderFactory : private epics::pvData::NoDefaultM public: POINTER_DEFINITIONS(ChannelProviderFactory); - virtual ~ChannelProviderFactory() {}; + virtual ~ChannelProviderFactory() {} /** * Get factory name (i.e. name of the provider). From d404769133080137bdaecc4a46a66c3b5cca7beb Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 10 May 2017 15:35:37 -0400 Subject: [PATCH 002/189] add default for first Channel::createChannel() default for first form which calls the second --- src/client/pv/pvAccess.h | 2 +- src/factory/ChannelAccessFactory.cpp | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/client/pv/pvAccess.h b/src/client/pv/pvAccess.h index ced7d53..79ac738 100644 --- a/src/client/pv/pvAccess.h +++ b/src/client/pv/pvAccess.h @@ -934,7 +934,7 @@ public: * @return Channel instance. If channel does not exist null is returned and channelRequester notified. */ virtual Channel::shared_pointer createChannel(std::string const & channelName,ChannelRequester::shared_pointer const & channelRequester, - short priority = PRIORITY_DEFAULT) = 0; + short priority = PRIORITY_DEFAULT); /** * Create a channel. diff --git a/src/factory/ChannelAccessFactory.cpp b/src/factory/ChannelAccessFactory.cpp index 97f0a8d..f1700fb 100644 --- a/src/factory/ChannelAccessFactory.cpp +++ b/src/factory/ChannelAccessFactory.cpp @@ -115,6 +115,14 @@ epicsShareFunc void unregisterAllChannelProviderFactory() } +Channel::shared_pointer +ChannelProvider::createChannel(std::string const & channelName, + ChannelRequester::shared_pointer const & channelRequester, + short priority) +{ + return createChannel(channelName, channelRequester, priority, ""); +} + } } From 5428b1ed2d2cd0a6968915b1db9ec90cf84fa360 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 15 May 2017 16:07:55 -0400 Subject: [PATCH 003/189] codec.h: add virtual and decorate w/ OVERRIDE/FINAL Mark where inheritance is actually happening, and where it ends. --- src/remote/pv/codec.h | 223 +++++++++++++++++++++++------------------- 1 file changed, 124 insertions(+), 99 deletions(-) diff --git a/src/remote/pv/codec.h b/src/remote/pv/codec.h index 3257f7c..13ac168 100644 --- a/src/remote/pv/codec.h +++ b/src/remote/pv/codec.h @@ -39,6 +39,31 @@ #include #include +/* C++11 keywords + @code + struct Base { + virtual void foo(); + }; + struct Class : public Base { + virtual void foo() OVERRIDE FINAL FINAL; + }; + @endcode + */ +#ifndef FINAL +# if __cplusplus>=201103L +# define FINAL final +# else +# define FINAL +# endif +#endif +#ifndef OVERRIDE +# if __cplusplus>=201103L +# define OVERRIDE override +# else +# define OVERRIDE +# endif +#endif + namespace epics { namespace pvAccess { @@ -174,41 +199,41 @@ public: { } - void alignBuffer(std::size_t alignment); - void ensureData(std::size_t size); - void alignData(std::size_t alignment); - void startMessage( - epics::pvData::int8 command, - std::size_t ensureCapacity = 0, - epics::pvData::int32 payloadSize = 0); + virtual void alignBuffer(std::size_t alignment) OVERRIDE FINAL; + virtual void ensureData(std::size_t size) OVERRIDE FINAL; + virtual void alignData(std::size_t alignment) OVERRIDE FINAL; + virtual void startMessage( + epics::pvData::int8 command, + std::size_t ensureCapacity = 0, + epics::pvData::int32 payloadSize = 0) OVERRIDE FINAL; void putControlMessage( - epics::pvData::int8 command, - epics::pvData::int32 data); - void endMessage(); - void ensureBuffer(std::size_t size); - void flushSerializeBuffer(); - void flush(bool lastMessageCompleted); + epics::pvData::int8 command, + epics::pvData::int32 data); + virtual void endMessage() OVERRIDE FINAL; + virtual void ensureBuffer(std::size_t size) OVERRIDE FINAL; + virtual void flushSerializeBuffer() OVERRIDE FINAL; + virtual void flush(bool lastMessageCompleted) OVERRIDE FINAL; void processWrite(); void processRead(); void processSendQueue(); - void enqueueSendRequest(TransportSender::shared_pointer const & sender); + virtual void enqueueSendRequest(TransportSender::shared_pointer const & sender) OVERRIDE FINAL; void enqueueSendRequest(TransportSender::shared_pointer const & sender, std::size_t requiredBufferSize); void setSenderThread(); - void setRecipient(osiSockAddr const & sendTo); - void setByteOrder(int byteOrder); + virtual void setRecipient(osiSockAddr const & sendTo) OVERRIDE FINAL; + virtual void setByteOrder(int byteOrder) OVERRIDE FINAL; static std::size_t alignedValue(std::size_t value, std::size_t alignment); - bool directSerialize( - epics::pvData::ByteBuffer * /*existingBuffer*/, - const char* /*toSerialize*/, - std::size_t /*elementCount*/, std::size_t /*elementSize*/); + virtual bool directSerialize( + epics::pvData::ByteBuffer * /*existingBuffer*/, + const char* /*toSerialize*/, + std::size_t /*elementCount*/, std::size_t /*elementSize*/) OVERRIDE; - bool directDeserialize(epics::pvData::ByteBuffer * /*existingBuffer*/, - char* /*deserializeTo*/, - std::size_t /*elementCount*/, std::size_t /*elementSize*/); + virtual bool directDeserialize(epics::pvData::ByteBuffer * /*existingBuffer*/, + char* /*deserializeTo*/, + std::size_t /*elementCount*/, std::size_t /*elementSize*/) OVERRIDE; bool sendQueueEmpty() const { return _sendQueue.empty(); @@ -284,13 +309,13 @@ public: int32_t socketSendBufferSize); virtual ~BlockingAbstractCodec(); - void readPollOne(); - void writePollOne(); - void scheduleSend() {} - void sendCompleted() {} - void close(); - bool terminated(); - bool isOpen(); + virtual void readPollOne() OVERRIDE FINAL; + virtual void writePollOne() OVERRIDE FINAL; + virtual void scheduleSend() OVERRIDE FINAL {} + virtual void sendCompleted() OVERRIDE FINAL {} + virtual void close() OVERRIDE FINAL; + virtual bool terminated() OVERRIDE FINAL; + virtual bool isOpen() OVERRIDE FINAL; void start(); private: @@ -298,7 +323,7 @@ private: void sendThread(); protected: - void sendBufferFull(int tries); + virtual void sendBufferFull(int tries) OVERRIDE FINAL; virtual void internalDestroy() = 0; /** @@ -334,17 +359,17 @@ public: int32_t sendBufferSize, int32_t receiveBufferSize); - int read(epics::pvData::ByteBuffer* dst); - int write(epics::pvData::ByteBuffer* src); - const osiSockAddr* getLastReadBufferSocketAddress() { + virtual int read(epics::pvData::ByteBuffer* dst) OVERRIDE FINAL; + virtual int write(epics::pvData::ByteBuffer* src) OVERRIDE FINAL; + virtual const osiSockAddr* getLastReadBufferSocketAddress() OVERRIDE FINAL { return &_socketAddress; } - void invalidDataStreamHandler(); - std::size_t getSocketReceiveBufferSize() const; + virtual void invalidDataStreamHandler() OVERRIDE FINAL; + virtual std::size_t getSocketReceiveBufferSize() const OVERRIDE FINAL; protected: - void internalDestroy(); + virtual void internalDestroy() OVERRIDE; SOCKET _channel; osiSockAddr _socketAddress; @@ -360,22 +385,22 @@ class BlockingTCPTransportCodec : public: - std::string getType() const { + virtual std::string getType() const OVERRIDE FINAL { return std::string("tcp"); } - void internalDestroy() { + virtual void internalDestroy() OVERRIDE FINAL { BlockingSocketAbstractCodec::internalDestroy(); Transport::shared_pointer thisSharedPtr = this->shared_from_this(); _context->getTransportRegistry()->remove(thisSharedPtr); } - void changedTransport() {} + virtual void changedTransport() OVERRIDE {} - void processControlMessage() { + virtual void processControlMessage() OVERRIDE FINAL { if (_command == 2) { // check 7-th bit @@ -384,71 +409,71 @@ public: } - void processApplicationMessage() { + virtual void processApplicationMessage() OVERRIDE FINAL { _responseHandler->handleResponse(&_socketAddress, shared_from_this(), _version, _command, _payloadSize, _socketBuffer.get()); } - const osiSockAddr* getRemoteAddress() const { + virtual const osiSockAddr* getRemoteAddress() const OVERRIDE FINAL { return &_socketAddress; } - const std::string& getRemoteName() const { + virtual const std::string& getRemoteName() const OVERRIDE FINAL { return _socketName; } - epics::pvData::int8 getRevision() const { + virtual epics::pvData::int8 getRevision() const OVERRIDE FINAL { return PVA_PROTOCOL_REVISION; } - std::size_t getReceiveBufferSize() const { + virtual std::size_t getReceiveBufferSize() const OVERRIDE FINAL { return _socketBuffer->getSize(); } - epics::pvData::int16 getPriority() const { + virtual epics::pvData::int16 getPriority() const OVERRIDE FINAL { return _priority; } - void setRemoteRevision(epics::pvData::int8 revision) { + virtual void setRemoteRevision(epics::pvData::int8 revision) OVERRIDE FINAL { _remoteTransportRevision = revision; } - void setRemoteTransportReceiveBufferSize( - std::size_t remoteTransportReceiveBufferSize) { + virtual void setRemoteTransportReceiveBufferSize( + std::size_t remoteTransportReceiveBufferSize) OVERRIDE FINAL { _remoteTransportReceiveBufferSize = remoteTransportReceiveBufferSize; } - void setRemoteTransportSocketReceiveBufferSize( - std::size_t socketReceiveBufferSize) { + virtual void setRemoteTransportSocketReceiveBufferSize( + std::size_t socketReceiveBufferSize) OVERRIDE FINAL { _remoteTransportSocketReceiveBufferSize = socketReceiveBufferSize; } std::tr1::shared_ptr - cachedDeserialize(epics::pvData::ByteBuffer* buffer) + virtual cachedDeserialize(epics::pvData::ByteBuffer* buffer) OVERRIDE FINAL { return _incomingIR.deserialize(buffer, this); } - void cachedSerialize( + virtual void cachedSerialize( const std::tr1::shared_ptr& field, - epics::pvData::ByteBuffer* buffer) + epics::pvData::ByteBuffer* buffer) OVERRIDE FINAL { _outgoingIR.serialize(field, buffer, this); } - void flushSendQueue() { }; + virtual void flushSendQueue() OVERRIDE FINAL { }; - bool isClosed() { + virtual bool isClosed() OVERRIDE FINAL { return !isOpen(); } @@ -460,22 +485,22 @@ public: start(); } - bool verify(epics::pvData::int32 timeoutMs); + virtual bool verify(epics::pvData::int32 timeoutMs) OVERRIDE; - void verified(epics::pvData::Status const & status); + virtual void verified(epics::pvData::Status const & status) OVERRIDE; bool isVerified() const { return _verified; // TODO sync } - std::tr1::shared_ptr getSecuritySession() const { + virtual std::tr1::shared_ptr getSecuritySession() const OVERRIDE FINAL { // TODO sync return _securitySession; } - void authNZMessage(epics::pvData::PVField::shared_pointer const & data); + virtual void authNZMessage(epics::pvData::PVField::shared_pointer const & data) OVERRIDE FINAL; - void sendSecurityPluginMessage(epics::pvData::PVField::shared_pointer const & data); + virtual void sendSecurityPluginMessage(epics::pvData::PVField::shared_pointer const & data) OVERRIDE FINAL; protected: @@ -496,7 +521,7 @@ protected: { } - virtual void internalClose(bool force); + virtual void internalClose(bool force) OVERRIDE; Context::shared_pointer _context; @@ -554,38 +579,38 @@ public: public: - bool acquire(std::tr1::shared_ptr const & /*client*/) + virtual bool acquire(std::tr1::shared_ptr const & /*client*/) OVERRIDE FINAL { return false; } - void release(pvAccessID /*clientId*/) {} + virtual void release(pvAccessID /*clientId*/) OVERRIDE FINAL {} - pvAccessID preallocateChannelSID(); + virtual pvAccessID preallocateChannelSID() OVERRIDE FINAL; - void depreallocateChannelSID(pvAccessID /*sid*/) { + virtual void depreallocateChannelSID(pvAccessID /*sid*/) OVERRIDE FINAL { // noop } - void registerChannel( - pvAccessID sid, - ServerChannel::shared_pointer const & channel); + virtual void registerChannel( + pvAccessID sid, + ServerChannel::shared_pointer const & channel) OVERRIDE FINAL; - void unregisterChannel(pvAccessID sid); + virtual void unregisterChannel(pvAccessID sid) OVERRIDE FINAL; - ServerChannel::shared_pointer getChannel(pvAccessID sid); + virtual ServerChannel::shared_pointer getChannel(pvAccessID sid) OVERRIDE FINAL; - int getChannelCount(); + virtual int getChannelCount() OVERRIDE FINAL; - void lock() { + virtual void lock() OVERRIDE FINAL { // noop } - void unlock() { + virtual void unlock() OVERRIDE FINAL { // noop } - bool verify(epics::pvData::int32 timeoutMs) { + virtual bool verify(epics::pvData::int32 timeoutMs) OVERRIDE FINAL { TransportSender::shared_pointer transportSender = std::tr1::dynamic_pointer_cast(shared_from_this()); @@ -598,30 +623,30 @@ public: return verifiedStatus; } - void verified(epics::pvData::Status const & status) { + virtual void verified(epics::pvData::Status const & status) OVERRIDE FINAL { _verificationStatusMutex.lock(); _verificationStatus = status; _verificationStatusMutex.unlock(); BlockingTCPTransportCodec::verified(status); } - void aliveNotification() { + virtual void aliveNotification() OVERRIDE FINAL { // noop on server-side } - void authNZInitialize(void *); + virtual void authNZInitialize(void *) OVERRIDE FINAL; - void authenticationCompleted(epics::pvData::Status const & status); + virtual void authenticationCompleted(epics::pvData::Status const & status) OVERRIDE FINAL; - void send(epics::pvData::ByteBuffer* buffer, - TransportSendControl* control); + virtual void send(epics::pvData::ByteBuffer* buffer, + TransportSendControl* control) OVERRIDE FINAL; - virtual ~BlockingServerTCPTransportCodec(); + virtual ~BlockingServerTCPTransportCodec() OVERRIDE FINAL; protected: void destroyAllChannels(); - virtual void internalClose(bool force); + virtual void internalClose(bool force) OVERRIDE FINAL; private: @@ -695,41 +720,41 @@ public: void start(); - virtual ~BlockingClientTCPTransportCodec(); + virtual ~BlockingClientTCPTransportCodec() OVERRIDE FINAL; - virtual void timerStopped() { + virtual void timerStopped() OVERRIDE FINAL { // noop } - virtual void callback(); + virtual void callback() OVERRIDE FINAL; - bool acquire(TransportClient::shared_pointer const & client); + virtual bool acquire(TransportClient::shared_pointer const & client) OVERRIDE FINAL; - void release(pvAccessID clientId); + virtual void release(pvAccessID clientId) OVERRIDE FINAL; - void changedTransport(); + virtual void changedTransport() OVERRIDE FINAL; - void lock() { + virtual void lock() OVERRIDE FINAL { // noop } - void unlock() { + virtual void unlock() OVERRIDE FINAL { // noop } - void aliveNotification(); + virtual void aliveNotification() OVERRIDE FINAL; - void send(epics::pvData::ByteBuffer* buffer, - TransportSendControl* control); + virtual void send(epics::pvData::ByteBuffer* buffer, + TransportSendControl* control) OVERRIDE FINAL; - void authNZInitialize(void *); + virtual void authNZInitialize(void *) OVERRIDE FINAL; - void authenticationCompleted(epics::pvData::Status const & status); + virtual void authenticationCompleted(epics::pvData::Status const & status) OVERRIDE FINAL; protected: - virtual void internalClose(bool force); - virtual void internalPostClose(bool force); + virtual void internalClose(bool force) OVERRIDE FINAL; + virtual void internalPostClose(bool force) OVERRIDE FINAL; private: From e47124aa3046bfaa632420188efece4f0aa0e610 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 15 May 2017 16:26:56 -0400 Subject: [PATCH 004/189] collapse BlockingAbstractCodec into BlockingSocketAbstractCodec --- src/remote/codec.cpp | 73 +++++++++++++++++++------------------------ src/remote/pv/codec.h | 58 +++++++++++++--------------------- 2 files changed, 54 insertions(+), 77 deletions(-) diff --git a/src/remote/codec.cpp b/src/remote/codec.cpp index 15f6c2e..6d4b3eb 100644 --- a/src/remote/codec.cpp +++ b/src/remote/codec.cpp @@ -1047,42 +1047,24 @@ bool AbstractCodec::directDeserialize(ByteBuffer *existingBuffer, char* deserial // // -BlockingAbstractCodec::BlockingAbstractCodec( - bool serverFlag, - std::tr1::shared_ptr const & receiveBuffer, - std::tr1::shared_ptr const & sendBuffer, - int32_t socketSendBufferSize) - :AbstractCodec(serverFlag, receiveBuffer, sendBuffer, socketSendBufferSize, true) - ,_readThread(epics::pvData::Thread::Config(this, &BlockingAbstractCodec::receiveThread) - .prio(epicsThreadPriorityCAServerLow) - .name("TCP-rx") - .autostart(false)) - ,_sendThread(epics::pvData::Thread::Config(this, &BlockingAbstractCodec::sendThread) - .prio(epicsThreadPriorityCAServerLow) - .name("TCP-tx") - .autostart(false)) -{ - _isOpen.getAndSet(true); -} - -BlockingAbstractCodec::~BlockingAbstractCodec() +BlockingSocketAbstractCodec::~BlockingSocketAbstractCodec() { assert(!_isOpen.get()); _sendThread.exitWait(); _readThread.exitWait(); } -void BlockingAbstractCodec::readPollOne() { +void BlockingSocketAbstractCodec::readPollOne() { throw std::logic_error("should not be called for blocking IO"); } -void BlockingAbstractCodec::writePollOne() { +void BlockingSocketAbstractCodec::writePollOne() { throw std::logic_error("should not be called for blocking IO"); } -void BlockingAbstractCodec::close() { +void BlockingSocketAbstractCodec::close() { if (_isOpen.getAndSet(false)) { @@ -1101,26 +1083,26 @@ void BlockingAbstractCodec::close() { } } -void BlockingAbstractCodec::internalClose(bool /*force*/) +void BlockingSocketAbstractCodec::internalClose(bool /*force*/) { this->internalDestroy(); } -void BlockingAbstractCodec::internalPostClose(bool /*force*/) { +void BlockingSocketAbstractCodec::internalPostClose(bool /*force*/) { } -bool BlockingAbstractCodec::terminated() { +bool BlockingSocketAbstractCodec::terminated() { return !isOpen(); } -bool BlockingAbstractCodec::isOpen() { +bool BlockingSocketAbstractCodec::isOpen() { return _isOpen.get(); } // NOTE: must not be called from constructor (e.g. needs shared_from_this()) -void BlockingAbstractCodec::start() { +void BlockingSocketAbstractCodec::start() { _readThread.start(); @@ -1129,7 +1111,7 @@ void BlockingAbstractCodec::start() { } -void BlockingAbstractCodec::receiveThread() +void BlockingSocketAbstractCodec::receiveThread() { Transport::shared_pointer ptr = this->shared_from_this(); @@ -1152,7 +1134,7 @@ void BlockingAbstractCodec::receiveThread() } -void BlockingAbstractCodec::sendThread() +void BlockingSocketAbstractCodec::sendThread() { Transport::shared_pointer ptr = this->shared_from_this(); @@ -1178,7 +1160,7 @@ void BlockingAbstractCodec::sendThread() } -void BlockingAbstractCodec::sendBufferFull(int tries) { +void BlockingSocketAbstractCodec::sendBufferFull(int tries) { // TODO constants epicsThreadSleep(std::max(tries * 0.1, 1)); } @@ -1196,17 +1178,28 @@ BlockingSocketAbstractCodec::BlockingSocketAbstractCodec( bool serverFlag, SOCKET channel, int32_t sendBufferSize, - int32_t receiveBufferSize): - BlockingAbstractCodec( - serverFlag, - std::tr1::shared_ptr(new ByteBuffer((std::max((std::size_t)( - MAX_TCP_RECV + MAX_ENSURE_DATA_BUFFER_SIZE), receiveBufferSize) + - (PVA_ALIGNMENT - 1)) & (~(PVA_ALIGNMENT - 1)))), - std::tr1::shared_ptr(new ByteBuffer((std::max((std::size_t)( MAX_TCP_RECV + - MAX_ENSURE_DATA_BUFFER_SIZE), receiveBufferSize) + (PVA_ALIGNMENT - 1)) - & (~(PVA_ALIGNMENT - 1)))), sendBufferSize), - _channel(channel) + int32_t receiveBufferSize) + :AbstractCodec( + serverFlag, + std::tr1::shared_ptr(new ByteBuffer((std::max((std::size_t)( + MAX_TCP_RECV + MAX_ENSURE_DATA_BUFFER_SIZE), receiveBufferSize) + + (PVA_ALIGNMENT - 1)) & (~(PVA_ALIGNMENT - 1)))), + std::tr1::shared_ptr(new ByteBuffer((std::max((std::size_t)( MAX_TCP_RECV + + MAX_ENSURE_DATA_BUFFER_SIZE), receiveBufferSize) + (PVA_ALIGNMENT - 1)) + & (~(PVA_ALIGNMENT - 1)))), sendBufferSize, + true) + ,_readThread(epics::pvData::Thread::Config(this, &BlockingSocketAbstractCodec::receiveThread) + .prio(epicsThreadPriorityCAServerLow) + .name("TCP-rx") + .autostart(false)) + ,_sendThread(epics::pvData::Thread::Config(this, &BlockingSocketAbstractCodec::sendThread) + .prio(epicsThreadPriorityCAServerLow) + .name("TCP-tx") + .autostart(false)) + ,_channel(channel) { + _isOpen.getAndSet(true); + // get remote address osiSocklen_t saSize = sizeof(sockaddr); int retval = getpeername(_channel, &(_socketAddress.sa), &saSize); diff --git a/src/remote/pv/codec.h b/src/remote/pv/codec.h index 13ac168..6c69b63 100644 --- a/src/remote/pv/codec.h +++ b/src/remote/pv/codec.h @@ -293,21 +293,23 @@ private: }; -class epicsShareClass BlockingAbstractCodec: +/////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class epicsShareClass BlockingSocketAbstractCodec: public AbstractCodec, - public std::tr1::enable_shared_from_this + public std::tr1::enable_shared_from_this { public: - POINTER_DEFINITIONS(BlockingAbstractCodec); + POINTER_DEFINITIONS(BlockingSocketAbstractCodec); - BlockingAbstractCodec( - bool serverFlag, - std::tr1::shared_ptr const & receiveBuffer, - std::tr1::shared_ptr const & sendBuffer, - int32_t socketSendBufferSize); - virtual ~BlockingAbstractCodec(); + BlockingSocketAbstractCodec( + bool serverFlag, + SOCKET channel, + int32_t sendBufferSize, + int32_t receiveBufferSize); + virtual ~BlockingSocketAbstractCodec(); virtual void readPollOne() OVERRIDE FINAL; virtual void writePollOne() OVERRIDE FINAL; @@ -318,13 +320,21 @@ public: virtual bool isOpen() OVERRIDE FINAL; void start(); + virtual int read(epics::pvData::ByteBuffer* dst) OVERRIDE FINAL; + virtual int write(epics::pvData::ByteBuffer* src) OVERRIDE FINAL; + virtual const osiSockAddr* getLastReadBufferSocketAddress() OVERRIDE FINAL { + return &_socketAddress; + } + virtual void invalidDataStreamHandler() OVERRIDE FINAL; + virtual std::size_t getSocketReceiveBufferSize() const OVERRIDE FINAL; + private: void receiveThread(); void sendThread(); protected: virtual void sendBufferFull(int tries) OVERRIDE FINAL; - virtual void internalDestroy() = 0; + virtual void internalDestroy(); /** * Called to any resources just before closing transport @@ -344,39 +354,12 @@ private: AtomicValue _isOpen; epics::pvData::Thread _readThread, _sendThread; epics::pvData::Event _shutdownEvent; -}; - - -class epicsShareClass BlockingSocketAbstractCodec: - public BlockingAbstractCodec -{ - -public: - - BlockingSocketAbstractCodec( - bool serverFlag, - SOCKET channel, - int32_t sendBufferSize, - int32_t receiveBufferSize); - - virtual int read(epics::pvData::ByteBuffer* dst) OVERRIDE FINAL; - virtual int write(epics::pvData::ByteBuffer* src) OVERRIDE FINAL; - virtual const osiSockAddr* getLastReadBufferSocketAddress() OVERRIDE FINAL { - return &_socketAddress; - } - virtual void invalidDataStreamHandler() OVERRIDE FINAL; - virtual std::size_t getSocketReceiveBufferSize() const OVERRIDE FINAL; - protected: - - virtual void internalDestroy() OVERRIDE; - SOCKET _channel; osiSockAddr _socketAddress; std::string _socketName; }; - class BlockingTCPTransportCodec : public BlockingSocketAbstractCodec, public SecurityPluginControl @@ -543,6 +526,7 @@ private: }; +/////////////////////////////////////////////////////////////////////////////////////////////////////////// class epicsShareClass BlockingServerTCPTransportCodec : public BlockingTCPTransportCodec, From ab4f0b7e3ad529c89e43919fbdb548bc57348c71 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 15 May 2017 16:50:26 -0400 Subject: [PATCH 005/189] collapse BlockingSocketAbstractCodec -> BlockingTCPTransportCodec --- src/remote/codec.cpp | 80 +++++++++++++++--------------- src/remote/pv/codec.h | 112 ++++++++++++++---------------------------- 2 files changed, 78 insertions(+), 114 deletions(-) diff --git a/src/remote/codec.cpp b/src/remote/codec.cpp index 6d4b3eb..fd70ed8 100644 --- a/src/remote/codec.cpp +++ b/src/remote/codec.cpp @@ -1047,24 +1047,24 @@ bool AbstractCodec::directDeserialize(ByteBuffer *existingBuffer, char* deserial // // -BlockingSocketAbstractCodec::~BlockingSocketAbstractCodec() +BlockingTCPTransportCodec::~BlockingTCPTransportCodec() { assert(!_isOpen.get()); _sendThread.exitWait(); _readThread.exitWait(); } -void BlockingSocketAbstractCodec::readPollOne() { +void BlockingTCPTransportCodec::readPollOne() { throw std::logic_error("should not be called for blocking IO"); } -void BlockingSocketAbstractCodec::writePollOne() { +void BlockingTCPTransportCodec::writePollOne() { throw std::logic_error("should not be called for blocking IO"); } -void BlockingSocketAbstractCodec::close() { +void BlockingTCPTransportCodec::close() { if (_isOpen.getAndSet(false)) { @@ -1083,26 +1083,37 @@ void BlockingSocketAbstractCodec::close() { } } -void BlockingSocketAbstractCodec::internalClose(bool /*force*/) +void BlockingTCPTransportCodec::internalClose(bool /*force*/) { this->internalDestroy(); + + // TODO sync + if (_securitySession) + _securitySession->close(); + + if (IS_LOGGABLE(logLevelDebug)) + { + LOG(logLevelDebug, + "TCP socket to %s is to be closed.", + inetAddressToString(_socketAddress).c_str()); + } } -void BlockingSocketAbstractCodec::internalPostClose(bool /*force*/) { +void BlockingTCPTransportCodec::internalPostClose(bool /*force*/) { } -bool BlockingSocketAbstractCodec::terminated() { +bool BlockingTCPTransportCodec::terminated() { return !isOpen(); } -bool BlockingSocketAbstractCodec::isOpen() { +bool BlockingTCPTransportCodec::isOpen() { return _isOpen.get(); } // NOTE: must not be called from constructor (e.g. needs shared_from_this()) -void BlockingSocketAbstractCodec::start() { +void BlockingTCPTransportCodec::start() { _readThread.start(); @@ -1111,7 +1122,7 @@ void BlockingSocketAbstractCodec::start() { } -void BlockingSocketAbstractCodec::receiveThread() +void BlockingTCPTransportCodec::receiveThread() { Transport::shared_pointer ptr = this->shared_from_this(); @@ -1134,7 +1145,7 @@ void BlockingSocketAbstractCodec::receiveThread() } -void BlockingSocketAbstractCodec::sendThread() +void BlockingTCPTransportCodec::sendThread() { Transport::shared_pointer ptr = this->shared_from_this(); @@ -1160,7 +1171,7 @@ void BlockingSocketAbstractCodec::sendThread() } -void BlockingSocketAbstractCodec::sendBufferFull(int tries) { +void BlockingTCPTransportCodec::sendBufferFull(int tries) { // TODO constants epicsThreadSleep(std::max(tries * 0.1, 1)); } @@ -1168,17 +1179,16 @@ void BlockingSocketAbstractCodec::sendBufferFull(int tries) { // // -// BlockingSocketAbstractCodec +// BlockingTCPTransportCodec // // // -BlockingSocketAbstractCodec::BlockingSocketAbstractCodec( - bool serverFlag, - SOCKET channel, +BlockingTCPTransportCodec::BlockingTCPTransportCodec(bool serverFlag, const Context::shared_pointer &context, + SOCKET channel, const ResponseHandler::shared_pointer &responseHandler, int32_t sendBufferSize, - int32_t receiveBufferSize) + int32_t receiveBufferSize, int16 priority) :AbstractCodec( serverFlag, std::tr1::shared_ptr(new ByteBuffer((std::max((std::size_t)( @@ -1188,15 +1198,19 @@ BlockingSocketAbstractCodec::BlockingSocketAbstractCodec( MAX_ENSURE_DATA_BUFFER_SIZE), receiveBufferSize) + (PVA_ALIGNMENT - 1)) & (~(PVA_ALIGNMENT - 1)))), sendBufferSize, true) - ,_readThread(epics::pvData::Thread::Config(this, &BlockingSocketAbstractCodec::receiveThread) + ,_readThread(epics::pvData::Thread::Config(this, &BlockingTCPTransportCodec::receiveThread) .prio(epicsThreadPriorityCAServerLow) .name("TCP-rx") .autostart(false)) - ,_sendThread(epics::pvData::Thread::Config(this, &BlockingSocketAbstractCodec::sendThread) + ,_sendThread(epics::pvData::Thread::Config(this, &BlockingTCPTransportCodec::sendThread) .prio(epicsThreadPriorityCAServerLow) .name("TCP-tx") .autostart(false)) ,_channel(channel) + ,_context(context), _responseHandler(responseHandler) + ,_remoteTransportReceiveBufferSize(MAX_TCP_RECV) + ,_remoteTransportRevision(0), _priority(priority) + ,_verified(false) { _isOpen.getAndSet(true); @@ -1219,7 +1233,7 @@ BlockingSocketAbstractCodec::BlockingSocketAbstractCodec( } // must be called only once, when there will be no operation on socket (e.g. just before tx/rx thread exists) -void BlockingSocketAbstractCodec::internalDestroy() { +void BlockingTCPTransportCodec::internalDestroy() { if(_channel != INVALID_SOCKET) { @@ -1255,15 +1269,17 @@ void BlockingSocketAbstractCodec::internalDestroy() { _channel = INVALID_SOCKET; //TODO: mutex to guard _channel } + Transport::shared_pointer thisSharedPtr = this->shared_from_this(); + _context->getTransportRegistry()->remove(thisSharedPtr); } -void BlockingSocketAbstractCodec::invalidDataStreamHandler() { +void BlockingTCPTransportCodec::invalidDataStreamHandler() { close(); } -int BlockingSocketAbstractCodec::write( +int BlockingTCPTransportCodec::write( epics::pvData::ByteBuffer *src) { std::size_t remaining; @@ -1300,7 +1316,7 @@ int BlockingSocketAbstractCodec::write( } -std::size_t BlockingSocketAbstractCodec::getSocketReceiveBufferSize() +std::size_t BlockingTCPTransportCodec::getSocketReceiveBufferSize() const { osiSocklen_t intLen = sizeof(int); @@ -1321,7 +1337,7 @@ const { } -int BlockingSocketAbstractCodec::read(epics::pvData::ByteBuffer* dst) { +int BlockingTCPTransportCodec::read(epics::pvData::ByteBuffer* dst) { std::size_t remaining; while((remaining=dst->getRemaining()) > 0) { @@ -1366,22 +1382,6 @@ int BlockingSocketAbstractCodec::read(epics::pvData::ByteBuffer* dst) { } -void BlockingTCPTransportCodec::internalClose(bool force) { - BlockingSocketAbstractCodec::internalClose(force); - - // TODO sync - if (_securitySession) - _securitySession->close(); - - if (IS_LOGGABLE(logLevelDebug)) - { - LOG(logLevelDebug, - "TCP socket to %s is to be closed.", - inetAddressToString(_socketAddress).c_str()); - } -} - - bool BlockingTCPTransportCodec::verify(epics::pvData::int32 timeoutMs) { return _verifiedEvent.wait(timeoutMs/1000.0) && _verified; } diff --git a/src/remote/pv/codec.h b/src/remote/pv/codec.h index 6c69b63..94c113a 100644 --- a/src/remote/pv/codec.h +++ b/src/remote/pv/codec.h @@ -293,23 +293,25 @@ private: }; -/////////////////////////////////////////////////////////////////////////////////////////////////////////// - -class epicsShareClass BlockingSocketAbstractCodec: +class epicsShareClass BlockingTCPTransportCodec: public AbstractCodec, - public std::tr1::enable_shared_from_this + public SecurityPluginControl, + public std::tr1::enable_shared_from_this { public: - POINTER_DEFINITIONS(BlockingSocketAbstractCodec); + POINTER_DEFINITIONS(BlockingTCPTransportCodec); - BlockingSocketAbstractCodec( + BlockingTCPTransportCodec( bool serverFlag, + Context::shared_pointer const & context, SOCKET channel, + ResponseHandler::shared_pointer const & responseHandler, int32_t sendBufferSize, - int32_t receiveBufferSize); - virtual ~BlockingSocketAbstractCodec(); + int32_t receiveBufferSize, + epics::pvData::int16 priority); + virtual ~BlockingTCPTransportCodec(); virtual void readPollOne() OVERRIDE FINAL; virtual void writePollOne() OVERRIDE FINAL; @@ -328,56 +330,12 @@ public: virtual void invalidDataStreamHandler() OVERRIDE FINAL; virtual std::size_t getSocketReceiveBufferSize() const OVERRIDE FINAL; -private: - void receiveThread(); - void sendThread(); - -protected: - virtual void sendBufferFull(int tries) OVERRIDE FINAL; - virtual void internalDestroy(); - - /** - * Called to any resources just before closing transport - * @param[in] force flag indicating if forced (e.g. forced - * disconnect) is required - */ - virtual void internalClose(bool force); - - /** - * Called to any resources just after closing transport and without any locks held on transport - * @param[in] force flag indicating if forced (e.g. forced - * disconnect) is required - */ - virtual void internalPostClose(bool force); - -private: - AtomicValue _isOpen; - epics::pvData::Thread _readThread, _sendThread; - epics::pvData::Event _shutdownEvent; -protected: - SOCKET _channel; - osiSockAddr _socketAddress; - std::string _socketName; -}; - -class BlockingTCPTransportCodec : - public BlockingSocketAbstractCodec, - public SecurityPluginControl - -{ - -public: - virtual std::string getType() const OVERRIDE FINAL { return std::string("tcp"); } - virtual void internalDestroy() OVERRIDE FINAL { - BlockingSocketAbstractCodec::internalDestroy(); - Transport::shared_pointer thisSharedPtr = this->shared_from_this(); - _context->getTransportRegistry()->remove(thisSharedPtr); - } + void internalDestroy(); virtual void changedTransport() OVERRIDE {} @@ -453,7 +411,7 @@ public: } - virtual void flushSendQueue() OVERRIDE FINAL { }; + virtual void flushSendQueue() OVERRIDE FINAL { } virtual bool isClosed() OVERRIDE FINAL { @@ -485,27 +443,36 @@ public: virtual void sendSecurityPluginMessage(epics::pvData::PVField::shared_pointer const & data) OVERRIDE FINAL; +private: + void receiveThread(); + void sendThread(); + protected: + virtual void sendBufferFull(int tries) OVERRIDE FINAL; - BlockingTCPTransportCodec( - bool serverFlag, - Context::shared_pointer const & context, - SOCKET channel, - ResponseHandler::shared_pointer const & responseHandler, - int32_t sendBufferSize, - int32_t receiveBufferSize, - epics::pvData::int16 priority - ): - BlockingSocketAbstractCodec(serverFlag, channel, sendBufferSize, receiveBufferSize), - _context(context), _responseHandler(responseHandler), - _remoteTransportReceiveBufferSize(MAX_TCP_RECV), - _remoteTransportRevision(0), _priority(priority), - _verified(false) - { - } + /** + * Called to any resources just before closing transport + * @param[in] force flag indicating if forced (e.g. forced + * disconnect) is required + */ + virtual void internalClose(bool force); - virtual void internalClose(bool force) OVERRIDE; + /** + * Called to any resources just after closing transport and without any locks held on transport + * @param[in] force flag indicating if forced (e.g. forced + * disconnect) is required + */ + virtual void internalPostClose(bool force); +private: + AtomicValue _isOpen; + epics::pvData::Thread _readThread, _sendThread; + epics::pvData::Event _shutdownEvent; +protected: + SOCKET _channel; + osiSockAddr _socketAddress; + std::string _socketName; +protected: Context::shared_pointer _context; IntrospectionRegistry _incomingIR; @@ -523,11 +490,8 @@ private: bool _verified; epics::pvData::Mutex _verifiedMutex; epics::pvData::Event _verifiedEvent; - }; -/////////////////////////////////////////////////////////////////////////////////////////////////////////// - class epicsShareClass BlockingServerTCPTransportCodec : public BlockingTCPTransportCodec, public ChannelHostingTransport, From 2cc1be2deead851c6dd483a07d2c0014d1543757 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 15 May 2017 16:58:06 -0400 Subject: [PATCH 006/189] codec.h: minor --- src/remote/codec.cpp | 3 --- src/remote/pv/codec.h | 8 +++----- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/remote/codec.cpp b/src/remote/codec.cpp index fd70ed8..ce7d59d 100644 --- a/src/remote/codec.cpp +++ b/src/remote/codec.cpp @@ -1099,9 +1099,6 @@ void BlockingTCPTransportCodec::internalClose(bool /*force*/) } } -void BlockingTCPTransportCodec::internalPostClose(bool /*force*/) { -} - bool BlockingTCPTransportCodec::terminated() { return !isOpen(); } diff --git a/src/remote/pv/codec.h b/src/remote/pv/codec.h index 94c113a..f0c0641 100644 --- a/src/remote/pv/codec.h +++ b/src/remote/pv/codec.h @@ -337,10 +337,6 @@ public: void internalDestroy(); - - virtual void changedTransport() OVERRIDE {} - - virtual void processControlMessage() OVERRIDE FINAL { if (_command == 2) { @@ -462,7 +458,7 @@ protected: * @param[in] force flag indicating if forced (e.g. forced * disconnect) is required */ - virtual void internalPostClose(bool force); + virtual void internalPostClose(bool force) {} private: AtomicValue _isOpen; @@ -534,6 +530,8 @@ public: virtual void release(pvAccessID /*clientId*/) OVERRIDE FINAL {} + virtual void changedTransport() OVERRIDE {} + virtual pvAccessID preallocateChannelSID() OVERRIDE FINAL; virtual void depreallocateChannelSID(pvAccessID /*sid*/) OVERRIDE FINAL { From bbe6cb25533ad3854e7bf0e05fcd867d391e19d6 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 15 May 2017 17:22:10 -0400 Subject: [PATCH 007/189] Lock provide default no-op implementation for lock/unlock --- src/client/pv/pvAccess.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/client/pv/pvAccess.h b/src/client/pv/pvAccess.h index 79ac738..1c071e9 100644 --- a/src/client/pv/pvAccess.h +++ b/src/client/pv/pvAccess.h @@ -71,10 +71,10 @@ class epicsShareClass Lockable public: POINTER_DEFINITIONS(Lockable); - virtual ~Lockable() {}; + virtual ~Lockable() {} - virtual void lock() = 0; - virtual void unlock() = 0; + virtual void lock() {} + virtual void unlock() {} }; /** From b05e7699b51a02e895fc90802daf1e41b535515b Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 15 May 2017 17:24:16 -0400 Subject: [PATCH 008/189] remove no-op lock/unlock from Lock sub-classes --- src/ca/caChannel.cpp | 33 -------- src/ca/pv/caChannel.h | 10 --- src/pipelineService/pipelineServer.cpp | 10 --- src/remote/codec.cpp | 5 -- src/remote/pv/codec.h | 16 ---- src/remoteClient/clientContextImpl.cpp | 45 ----------- src/rpcService/rpcServer.cpp | 10 --- src/server/baseChannelRequester.cpp | 20 ----- src/server/beaconEmitter.cpp | 10 --- src/server/pv/baseChannelRequester.h | 4 - src/server/pv/beaconEmitter.h | 3 - src/server/pv/responseHandlers.h | 42 ----------- src/server/responseHandlers.cpp | 100 ------------------------- testApp/remote/testCodec.cpp | 76 ------------------- 14 files changed, 384 deletions(-) diff --git a/src/ca/caChannel.cpp b/src/ca/caChannel.cpp index 233d646..f6c7c06 100644 --- a/src/ca/caChannel.cpp +++ b/src/ca/caChannel.cpp @@ -1062,23 +1062,6 @@ void CAChannelGet::destroy() } -/* --------------- epics::pvData::Lockable --------------- */ - - -void CAChannelGet::lock() -{ - // TODO -} - - -void CAChannelGet::unlock() -{ - // TODO -} - - - - @@ -1408,22 +1391,6 @@ void CAChannelPut::destroy() } -/* --------------- epics::pvData::Lockable --------------- */ - - -void CAChannelPut::lock() -{ - // TODO -} - - -void CAChannelPut::unlock() -{ - // TODO -} - - - diff --git a/src/ca/pv/caChannel.h b/src/ca/pv/caChannel.h index f2ef22b..7700fb9 100644 --- a/src/ca/pv/caChannel.h +++ b/src/ca/pv/caChannel.h @@ -152,11 +152,6 @@ public: virtual void destroy(); - /* --------------- epics::pvData::Lockable --------------- */ - - virtual void lock(); - virtual void unlock(); - private: CAChannelGet(CAChannel::shared_pointer const & _channel, @@ -212,11 +207,6 @@ public: virtual void destroy(); - /* --------------- epics::pvData::Lockable --------------- */ - - virtual void lock(); - virtual void unlock(); - private: CAChannelPut(CAChannel::shared_pointer const & _channel, diff --git a/src/pipelineService/pipelineServer.cpp b/src/pipelineService/pipelineServer.cpp index b85c457..7c770c9 100644 --- a/src/pipelineService/pipelineServer.cpp +++ b/src/pipelineService/pipelineServer.cpp @@ -229,16 +229,6 @@ public: m_pipelineSession->cancel(); } - virtual void lock() - { - // noop - } - - virtual void unlock() - { - // noop - } - virtual size_t getFreeElementCount() { Lock guard(m_freeQueueLock); return m_freeQueue.size(); diff --git a/src/remote/codec.cpp b/src/remote/codec.cpp index ce7d59d..5d69b56 100644 --- a/src/remote/codec.cpp +++ b/src/remote/codec.cpp @@ -51,8 +51,6 @@ struct BreakTransport : TransportSender { throw epics::pvAccess::detail::connection_closed_exception("Break"); } - virtual void lock() {} - virtual void unlock() {} }; } // namespace @@ -1427,9 +1425,6 @@ public: control->flush(true); } - void lock() {} - void unlock() {} - private: PVField::shared_pointer _data; }; diff --git a/src/remote/pv/codec.h b/src/remote/pv/codec.h index f0c0641..bf9fa94 100644 --- a/src/remote/pv/codec.h +++ b/src/remote/pv/codec.h @@ -548,14 +548,6 @@ public: virtual int getChannelCount() OVERRIDE FINAL; - virtual void lock() OVERRIDE FINAL { - // noop - } - - virtual void unlock() OVERRIDE FINAL { - // noop - } - virtual bool verify(epics::pvData::int32 timeoutMs) OVERRIDE FINAL { TransportSender::shared_pointer transportSender = @@ -680,14 +672,6 @@ public: virtual void changedTransport() OVERRIDE FINAL; - virtual void lock() OVERRIDE FINAL { - // noop - } - - virtual void unlock() OVERRIDE FINAL { - // noop - } - virtual void aliveNotification() OVERRIDE FINAL; virtual void send(epics::pvData::ByteBuffer* buffer, diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 7d16d58..98087a0 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -539,14 +539,6 @@ public: { BaseRequestImpl::lastRequest(); } - - virtual void lock() { - // noop - } - - virtual void unlock() { - // noop - } }; @@ -1986,10 +1978,6 @@ public: return m_ioid; } - virtual void lock() { - // noop - } - virtual void send(ByteBuffer* buffer, TransportSendControl* control) { control->startMessage((int8)17, 8); buffer->putInt(m_channel->getServerChannelID()); @@ -2019,10 +2007,6 @@ public: // TODO notify? } - virtual void unlock() { - // noop - } - virtual void destroy() { { @@ -2339,16 +2323,6 @@ public: control->flush(true); } - virtual void lock() - { - // noop - } - - virtual void unlock() - { - // noop - } - Status start() { Lock guard(m_mutex); while (!m_monitorQueue.empty()) @@ -2703,16 +2677,6 @@ public: m_monitorStrategy->release(monitorElement); } - virtual void lock() - { - // noop - } - - virtual void unlock() - { - // noop - } - }; @@ -4100,11 +4064,6 @@ private: } - virtual void lock() { - // noop - } - - virtual void send(ByteBuffer* buffer, TransportSendControl* control) { m_channelMutex.lock(); bool issueCreateMessage = m_issueCreateMessage; @@ -4139,10 +4098,6 @@ private: } } - virtual void unlock() { - // noop - } - /** * Disconnects (destroys) all channels pending IO. diff --git a/src/rpcService/rpcServer.cpp b/src/rpcService/rpcServer.cpp index 0c9a9d9..f2e7f3c 100644 --- a/src/rpcService/rpcServer.cpp +++ b/src/rpcService/rpcServer.cpp @@ -168,16 +168,6 @@ public: { // noop } - - virtual void lock() - { - // noop - } - - virtual void unlock() - { - // noop - } }; diff --git a/src/server/baseChannelRequester.cpp b/src/server/baseChannelRequester.cpp index a77945c..672c283 100644 --- a/src/server/baseChannelRequester.cpp +++ b/src/server/baseChannelRequester.cpp @@ -100,16 +100,6 @@ void BaseChannelRequesterMessageTransportSender::send(ByteBuffer* buffer, Transp epics::pvData::SerializeHelper::serializeString(_message, buffer, control); } -void BaseChannelRequesterMessageTransportSender::lock() -{ - // noop -} - -void BaseChannelRequesterMessageTransportSender::unlock() -{ - // noop -} - BaseChannelRequesterFailureMessageTransportSender::BaseChannelRequesterFailureMessageTransportSender(const int8 command, Transport::shared_pointer const & transport, const pvAccessID ioid, const int8 qos, const Status& status) : _command(command), @@ -128,16 +118,6 @@ void BaseChannelRequesterFailureMessageTransportSender::send(ByteBuffer* buffer, _status.serialize(buffer, control); } -void BaseChannelRequesterFailureMessageTransportSender::lock() -{ - // noop -} - -void BaseChannelRequesterFailureMessageTransportSender::unlock() -{ - // noop -} - } } diff --git a/src/server/beaconEmitter.cpp b/src/server/beaconEmitter.cpp index bdce554..dcc79a8 100644 --- a/src/server/beaconEmitter.cpp +++ b/src/server/beaconEmitter.cpp @@ -49,16 +49,6 @@ BeaconEmitter::~BeaconEmitter() // destroy(); } -void BeaconEmitter::lock() -{ - //noop -} - -void BeaconEmitter::unlock() -{ - //noop -} - void BeaconEmitter::send(ByteBuffer* buffer, TransportSendControl* control) { // get server status diff --git a/src/server/pv/baseChannelRequester.h b/src/server/pv/baseChannelRequester.h index 7d9fa39..e38e1f4 100644 --- a/src/server/pv/baseChannelRequester.h +++ b/src/server/pv/baseChannelRequester.h @@ -65,8 +65,6 @@ class BaseChannelRequesterMessageTransportSender : public TransportSender public: BaseChannelRequesterMessageTransportSender(const pvAccessID _ioid, const std::string message,const epics::pvData::MessageType messageType); void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); - void lock(); - void unlock(); private: const pvAccessID _ioid; const std::string _message; @@ -78,8 +76,6 @@ class BaseChannelRequesterFailureMessageTransportSender : public TransportSender public: BaseChannelRequesterFailureMessageTransportSender(const epics::pvData::int8 command, Transport::shared_pointer const & transport, const pvAccessID ioid, const epics::pvData::int8 qos, const epics::pvData::Status& status); void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); - void lock(); - void unlock(); private: const epics::pvData::int8 _command; diff --git a/src/server/pv/beaconEmitter.h b/src/server/pv/beaconEmitter.h index 1c61214..07a2cfd 100644 --- a/src/server/pv/beaconEmitter.h +++ b/src/server/pv/beaconEmitter.h @@ -59,9 +59,6 @@ public: virtual ~BeaconEmitter(); - void lock(); - void unlock(); - void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); void timerStopped(); diff --git a/src/server/pv/responseHandlers.h b/src/server/pv/responseHandlers.h index 8fedbad..8c2b3d1 100644 --- a/src/server/pv/responseHandlers.h +++ b/src/server/pv/responseHandlers.h @@ -125,12 +125,6 @@ public: // TODO content } - virtual void lock() { - } - - virtual void unlock() { - } - private: osiSockAddr _echoFrom; }; @@ -174,8 +168,6 @@ public: epics::pvData::int32 cid, osiSockAddr const & sendTo, bool responseRequired, bool serverSearch); void channelFindResult(const epics::pvData::Status& status, ChannelFind::shared_pointer const & channelFind, bool wasFound); - void lock(); - void unlock(); void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); void callback(); @@ -242,8 +234,6 @@ public: void channelStateChange(Channel::shared_pointer const & c, const Channel::ConnectionState isConnected); std::string getRequesterName(); void message(std::string const & message, epics::pvData::MessageType messageType); - void lock(); - void unlock(); void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); private: ServerChannel::weak_pointer _serverChannel; @@ -286,14 +276,6 @@ public: buffer->putInt(_cid); } - void lock() { - // noop - } - - void unlock() { - // noop - } - private: pvAccessID _cid; pvAccessID _sid; @@ -345,8 +327,6 @@ public: ChannelGet::shared_pointer getChannelGet(); - void lock(); - void unlock(); void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); private: ChannelGet::shared_pointer _channelGet; @@ -396,8 +376,6 @@ public: void channelPutConnect(const epics::pvData::Status& status, ChannelPut::shared_pointer const & channelPut, epics::pvData::Structure::const_shared_pointer const & structure); void putDone(const epics::pvData::Status& status, ChannelPut::shared_pointer const & channelPut); void getDone(const epics::pvData::Status& status, ChannelPut::shared_pointer const & channelPut, epics::pvData::PVStructure::shared_pointer const & pvStructure, epics::pvData::BitSet::shared_pointer const & bitSet); - void lock(); - void unlock(); void destroy(); ChannelPut::shared_pointer getChannelPut(); @@ -460,8 +438,6 @@ public: void putGetDone(const epics::pvData::Status& status, ChannelPutGet::shared_pointer const & channelPutGet, epics::pvData::PVStructure::shared_pointer const & pvStructure, epics::pvData::BitSet::shared_pointer const & bitSet); - void lock(); - void unlock(); void destroy(); ChannelPutGet::shared_pointer getChannelPutGet(); @@ -521,8 +497,6 @@ public: void monitorConnect(const epics::pvData::Status& status, Monitor::shared_pointer const & monitor, epics::pvData::StructureConstPtr const & structure); void unlisten(Monitor::shared_pointer const & monitor); void monitorEvent(Monitor::shared_pointer const & monitor); - void lock(); - void unlock(); void destroy(); Monitor::shared_pointer getChannelMonitor(); @@ -579,8 +553,6 @@ public: void setLengthDone(const epics::pvData::Status& status, ChannelArray::shared_pointer const & channelArray); void getLengthDone(const epics::pvData::Status& status, ChannelArray::shared_pointer const & channelArray, std::size_t length); - void lock(); - void unlock(); void destroy(); ChannelArray::shared_pointer getChannelArray(); @@ -677,8 +649,6 @@ public: void channelProcessConnect(const epics::pvData::Status& status, ChannelProcess::shared_pointer const & channelProcess); void processDone(const epics::pvData::Status& status, ChannelProcess::shared_pointer const & channelProcess); - void lock(); - void unlock(); void destroy(); ChannelProcess::shared_pointer getChannelProcess(); @@ -724,8 +694,6 @@ public: virtual ~ServerGetFieldRequesterImpl() {} void getDone(const epics::pvData::Status& status, epics::pvData::FieldConstPtr const & field); - void lock(); - void unlock(); void destroy(); void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); private: @@ -748,14 +716,6 @@ public: _status.serialize(buffer, control); } - void lock() { - // noop - } - - void unlock() { - // noop - } - private: const pvAccessID _ioid; const epics::pvData::Status _status; @@ -802,8 +762,6 @@ public: void channelRPCConnect(const epics::pvData::Status& status, ChannelRPC::shared_pointer const & channelRPC); void requestDone(const epics::pvData::Status& status, ChannelRPC::shared_pointer const & channelRPC, epics::pvData::PVStructure::shared_pointer const & pvResponse); - void lock(); - void unlock(); void destroy(); /** * @return the channelRPC diff --git a/src/server/responseHandlers.cpp b/src/server/responseHandlers.cpp index 88c955c..41cee50 100644 --- a/src/server/responseHandlers.cpp +++ b/src/server/responseHandlers.cpp @@ -426,16 +426,6 @@ void ServerChannelFindRequesterImpl::channelFindResult(const Status& /*status*/, } } -void ServerChannelFindRequesterImpl::lock() -{ - // noop -} - -void ServerChannelFindRequesterImpl::unlock() -{ - // noop -} - void ServerChannelFindRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* control) { control->startMessage((int8)4, 12+4+16+2); @@ -906,16 +896,6 @@ void ServerChannelRequesterImpl::message(std::string const & message, MessageTyp LOG(logLevelDebug, "[%s] %s", getMessageTypeName(messageType).c_str(), message.c_str()); } -void ServerChannelRequesterImpl::lock() -{ - //noop -} - -void ServerChannelRequesterImpl::unlock() -{ - //noop -} - void ServerChannelRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* control) { ServerChannel::shared_pointer serverChannel; @@ -1201,16 +1181,6 @@ ChannelGet::shared_pointer ServerChannelGetRequesterImpl::getChannelGet() return _channelGet; } -void ServerChannelGetRequesterImpl::lock() -{ - // noop -} - -void ServerChannelGetRequesterImpl::unlock() -{ - // noop -} - // TODO get rid of all these mutex-es void ServerChannelGetRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* control) { @@ -1452,16 +1422,6 @@ void ServerChannelPutRequesterImpl::getDone(const Status& status, ChannelPut::sh _transport->enqueueSendRequest(thisSender); } -void ServerChannelPutRequesterImpl::lock() -{ - //noop -} - -void ServerChannelPutRequesterImpl::unlock() -{ - //noop -} - void ServerChannelPutRequesterImpl::destroy() { // keep a reference to ourselves as the owner @@ -1772,16 +1732,6 @@ void ServerChannelPutGetRequesterImpl::putGetDone(const Status& status, ChannelP _transport->enqueueSendRequest(thisSender); } -void ServerChannelPutGetRequesterImpl::lock() -{ - // noop -} - -void ServerChannelPutGetRequesterImpl::unlock() -{ - // noop -} - void ServerChannelPutGetRequesterImpl::destroy() { // keep a reference to ourselves as the owner @@ -2075,16 +2025,6 @@ void ServerMonitorRequesterImpl::monitorEvent(Monitor::shared_pointer const & /* _transport->enqueueSendRequest(thisSender); } -void ServerMonitorRequesterImpl::lock() -{ - //noop -} - -void ServerMonitorRequesterImpl::unlock() -{ - //noop -} - void ServerMonitorRequesterImpl::destroy() { // keep a reference to ourselves as the owner @@ -2440,16 +2380,6 @@ void ServerChannelArrayRequesterImpl::getLengthDone(const Status& status, Channe _transport->enqueueSendRequest(thisSender); } -void ServerChannelArrayRequesterImpl::lock() -{ - // noop -} - -void ServerChannelArrayRequesterImpl::unlock() -{ - // noop -} - void ServerChannelArrayRequesterImpl::destroy() { // keep a reference to ourselves as the owner @@ -2749,16 +2679,6 @@ void ServerChannelProcessRequesterImpl::processDone(const Status& status, Channe _transport->enqueueSendRequest(thisSender); } -void ServerChannelProcessRequesterImpl::lock() -{ - // noop -} - -void ServerChannelProcessRequesterImpl::unlock() -{ - // noop -} - void ServerChannelProcessRequesterImpl::destroy() { // keep a reference to ourselves as the owner @@ -2874,16 +2794,6 @@ void ServerGetFieldRequesterImpl::getDone(const Status& status, FieldConstPtr co _transport->enqueueSendRequest(thisSender); } -void ServerGetFieldRequesterImpl::lock() -{ - //noop -} - -void ServerGetFieldRequesterImpl::unlock() -{ - //noop -} - void ServerGetFieldRequesterImpl::destroy() { } @@ -3041,16 +2951,6 @@ void ServerChannelRPCRequesterImpl::requestDone(const Status& status, ChannelRPC _transport->enqueueSendRequest(thisSender); } -void ServerChannelRPCRequesterImpl::lock() -{ - // noop -} - -void ServerChannelRPCRequesterImpl::unlock() -{ - // noop -} - void ServerChannelRPCRequesterImpl::destroy() { // keep a reference to ourselves as the owner diff --git a/testApp/remote/testCodec.cpp b/testApp/remote/testCodec.cpp index 73fbabb..c504741 100644 --- a/testApp/remote/testCodec.cpp +++ b/testApp/remote/testCodec.cpp @@ -28,8 +28,6 @@ struct sender_break : public connection_closed_exception }; struct TransportSenderDisconnect: public TransportSender { - void unlock() {} - void lock() {} void send(ByteBuffer *buffer, TransportSendControl *control) { control->flush(true); @@ -40,8 +38,6 @@ struct TransportSenderDisconnect: public TransportSender { struct TransportSenderSignal: public TransportSender { Event *evt; TransportSenderSignal(Event& evt) :evt(&evt) {} - void unlock() {} - void lock() {} void send(ByteBuffer *buffer, TransportSendControl *control) { evt->signal(); @@ -2289,12 +2285,6 @@ private: TransportSenderForTestEnqueueSendRequest( TestCodec & codec): _codec(codec) {} - void unlock() { - } - - void lock() { - } - void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) { @@ -2314,12 +2304,6 @@ private: TransportSender2ForTestEnqueueSendRequest( TestCodec & codec): _codec(codec) {} - void unlock() { - } - - void lock() { - } - void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) { @@ -2403,12 +2387,6 @@ private: TransportSenderForTestEnqueueSendDirectRequest( TestCodec & codec): _codec(codec) {} - void unlock() { - } - - void lock() { - } - void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) { @@ -2428,12 +2406,6 @@ private: TransportSender2ForTestEnqueueSendDirectRequest( TestCodec & codec): _codec(codec) {} - void unlock() { - } - - void lock() { - } - void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) { @@ -2612,12 +2584,6 @@ private: TestCodec & codec, std::size_t bytesToSend): _codec(codec), _bytesToSent(bytesToSend) {} - void unlock() { - } - - void lock() { - } - void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) { @@ -2714,12 +2680,6 @@ private: TransportSenderForTestSendException( TestCodec & codec): _codec(codec) {} - void unlock() { - } - - void lock() { - } - void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) { @@ -2777,12 +2737,6 @@ private: TestCodec & codec, std::size_t bytesToSend): _codec(codec), _bytesToSent(bytesToSend) {} - void unlock() { - } - - void lock() { - } - void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) { @@ -2929,12 +2883,6 @@ private: TransportSenderForTestClearSendQueue( TestCodec & codec): _codec(codec) {} - void unlock() { - } - - void lock() { - } - void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) { @@ -2954,12 +2902,6 @@ private: TransportSender2ForTestClearSendQueue( TestCodec & codec): _codec(codec) {} - void unlock() { - } - - void lock() { - } - void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) { @@ -3065,12 +3007,6 @@ private: TransportSenderForTestEnqueueSendRequestExceptionThrown( TestCodec & /*codec*/) { /*: _codec(codec)*/ } - void unlock() { - } - - void lock() { - } - void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) { @@ -3095,12 +3031,6 @@ private: TransportSender2ForTestEnqueueSendRequestExceptionThrown( TestCodec & codec): _codec(codec) {} - void unlock() { - } - - void lock() { - } - void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) { @@ -3171,12 +3101,6 @@ private: TransportSenderForTestBlockingProcessQueueTest( TestCodec & codec): _codec(codec) {} - void unlock() { - } - - void lock() { - } - void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) { From 0c1f410e6349eb65b35636b7743a56022a42326d Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 15 May 2017 18:32:17 -0400 Subject: [PATCH 009/189] avoid unnecessary auto_ptr/new --- src/remote/blockingUDPTransport.cpp | 40 ++++++++++++++--------------- src/remote/pv/blockingUDP.h | 16 ++++++------ 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/remote/blockingUDPTransport.cpp b/src/remote/blockingUDPTransport.cpp index 8ad6db4..50b8a41 100644 --- a/src/remote/blockingUDPTransport.cpp +++ b/src/remote/blockingUDPTransport.cpp @@ -58,8 +58,8 @@ BlockingUDPTransport::BlockingUDPTransport(bool serverFlag, _tappedNIF(0), _sendToEnabled(false), _localMulticastAddressEnabled(false), - _receiveBuffer(new ByteBuffer(MAX_UDP_RECV+RECEIVE_BUFFER_PRE_RESERVE)), - _sendBuffer(new ByteBuffer(MAX_UDP_RECV)), + _receiveBuffer(MAX_UDP_RECV+RECEIVE_BUFFER_PRE_RESERVE), + _sendBuffer(MAX_UDP_RECV), _lastMessageStartPosition(0), _clientServerWithEndianFlag( (serverFlag ? 0x40 : 0x00) | ((EPICS_BYTE_ORDER == EPICS_ENDIAN_BIG) ? 0x80 : 0x00)) @@ -176,16 +176,16 @@ void BlockingUDPTransport::enqueueSendRequest(TransportSender::shared_pointer co Lock lock(_sendMutex); _sendToEnabled = false; - _sendBuffer->clear(); + _sendBuffer.clear(); sender->lock(); try { - sender->send(_sendBuffer.get(), this); + sender->send(&_sendBuffer, this); sender->unlock(); endMessage(); if(!_sendToEnabled) - send(_sendBuffer.get()); + send(&_sendBuffer); else - send(_sendBuffer.get(), _sendTo); + send(&_sendBuffer, _sendTo); } catch(...) { sender->unlock(); } @@ -198,20 +198,20 @@ void BlockingUDPTransport::flushSendQueue() } void BlockingUDPTransport::startMessage(int8 command, size_t /*ensureCapacity*/, int32 payloadSize) { - _lastMessageStartPosition = _sendBuffer->getPosition(); - _sendBuffer->putByte(PVA_MAGIC); - _sendBuffer->putByte(PVA_VERSION); - _sendBuffer->putByte(_clientServerWithEndianFlag); - _sendBuffer->putByte(command); // command - _sendBuffer->putInt(payloadSize); + _lastMessageStartPosition = _sendBuffer.getPosition(); + _sendBuffer.putByte(PVA_MAGIC); + _sendBuffer.putByte(PVA_VERSION); + _sendBuffer.putByte(_clientServerWithEndianFlag); + _sendBuffer.putByte(command); // command + _sendBuffer.putInt(payloadSize); } void BlockingUDPTransport::endMessage() { //we always (for now) send by packet, so no need for this here... //alignBuffer(PVA_ALIGNMENT); - _sendBuffer->putInt( + _sendBuffer.putInt( _lastMessageStartPosition+(sizeof(int16)+2), - _sendBuffer->getPosition()-_lastMessageStartPosition-PVA_MESSAGE_HEADER_SIZE); + _sendBuffer.getPosition()-_lastMessageStartPosition-PVA_MESSAGE_HEADER_SIZE); } void BlockingUDPTransport::run() { @@ -224,8 +224,8 @@ void BlockingUDPTransport::run() { try { - char* recvfrom_buffer_start = (char*)(_receiveBuffer->getArray()+RECEIVE_BUFFER_PRE_RESERVE); - size_t recvfrom_buffer_len =_receiveBuffer->getSize()-RECEIVE_BUFFER_PRE_RESERVE; + char* recvfrom_buffer_start = (char*)(_receiveBuffer.getArray()+RECEIVE_BUFFER_PRE_RESERVE); + size_t recvfrom_buffer_len =_receiveBuffer.getSize()-RECEIVE_BUFFER_PRE_RESERVE; while(!_closed.get()) { int bytesRead = recvfrom(_channel, @@ -249,11 +249,11 @@ void BlockingUDPTransport::run() { } if(likely(!ignore)) { - _receiveBuffer->setPosition(RECEIVE_BUFFER_PRE_RESERVE); - _receiveBuffer->setLimit(RECEIVE_BUFFER_PRE_RESERVE+bytesRead); + _receiveBuffer.setPosition(RECEIVE_BUFFER_PRE_RESERVE); + _receiveBuffer.setLimit(RECEIVE_BUFFER_PRE_RESERVE+bytesRead); try { - processBuffer(thisTransport, fromAddress, _receiveBuffer.get()); + processBuffer(thisTransport, fromAddress, &_receiveBuffer); } catch(std::exception& e) { LOG(logLevelError, "an exception caught while in UDP receiveThread at %s:%d: %s", @@ -396,7 +396,7 @@ bool BlockingUDPTransport::processBuffer(Transport::shared_pointer const & trans // handle _responseHandler->handleResponse(&fromAddress, transport, version, command, payloadSize, - _receiveBuffer.get()); + &_receiveBuffer); } // set position (e.g. in case handler did not read all) diff --git a/src/remote/pv/blockingUDP.h b/src/remote/pv/blockingUDP.h index 606f092..7e57250 100644 --- a/src/remote/pv/blockingUDP.h +++ b/src/remote/pv/blockingUDP.h @@ -90,7 +90,7 @@ public: } virtual std::size_t getReceiveBufferSize() const { - return _receiveBuffer->getSize(); + return _receiveBuffer.getSize(); } virtual std::size_t getSocketReceiveBufferSize() const; @@ -149,10 +149,10 @@ public: // NOTE: this is not yet used for UDP virtual void setByteOrder(int byteOrder) { // called from receive thread... or before processing - _receiveBuffer->setEndianess(byteOrder); + _receiveBuffer.setEndianess(byteOrder); // sync?! - _sendBuffer->setEndianess(byteOrder); + _sendBuffer.setEndianess(byteOrder); } virtual void enqueueSendRequest(TransportSender::shared_pointer const & sender); @@ -164,12 +164,12 @@ public: virtual void close(); virtual void ensureData(std::size_t size) { - if (_receiveBuffer->getRemaining() < size) + if (_receiveBuffer.getRemaining() < size) throw std::underflow_error("no more data in UDP packet"); } virtual void alignData(std::size_t alignment) { - _receiveBuffer->align(alignment); + _receiveBuffer.align(alignment); } virtual bool directSerialize(epics::pvData::ByteBuffer* /*existingBuffer*/, const char* /*toSerialize*/, @@ -218,7 +218,7 @@ public: } virtual void alignBuffer(std::size_t alignment) { - _sendBuffer->align(alignment); + _sendBuffer.align(alignment); } virtual void cachedSerialize( @@ -431,12 +431,12 @@ private: /** * Receive buffer. */ - std::auto_ptr _receiveBuffer; + epics::pvData::ByteBuffer _receiveBuffer; /** * Send buffer. */ - std::auto_ptr _sendBuffer; + epics::pvData::ByteBuffer _sendBuffer; /** * Last message start position. From 87dca19708b8ce3bd4fc5b3bab2288da83901d1d Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 18 May 2017 15:59:01 -0400 Subject: [PATCH 010/189] codec: avoid indirection when accessing buffers avoid some indirection to make this code easier to follow. move buffer lower limit to base class. --- src/remote/codec.cpp | 223 +++++++++++++++++------------------ src/remote/pv/codec.h | 20 ++-- testApp/remote/testCodec.cpp | 59 +++------ 3 files changed, 139 insertions(+), 163 deletions(-) diff --git a/src/remote/codec.cpp b/src/remote/codec.cpp index 5d69b56..b3cc0c4 100644 --- a/src/remote/codec.cpp +++ b/src/remote/codec.cpp @@ -65,10 +65,16 @@ const std::size_t AbstractCodec::MAX_ENSURE_DATA_SIZE = MAX_ENSURE_SIZE/2; const std::size_t AbstractCodec::MAX_ENSURE_BUFFER_SIZE = MAX_ENSURE_SIZE; const std::size_t AbstractCodec::MAX_ENSURE_DATA_BUFFER_SIZE = 1024; +static +size_t bufSizeSelect(size_t request) +{ + return std::max(request, MAX_TCP_RECV + AbstractCodec::MAX_ENSURE_DATA_BUFFER_SIZE); +} + AbstractCodec::AbstractCodec( bool serverFlag, - std::tr1::shared_ptr const & receiveBuffer, - std::tr1::shared_ptr const & sendBuffer, + size_t sendBufferSize, + size_t receiveBufferSize, int32_t socketSendBufferSize, bool blockingProcessQueue): //PROTECTED @@ -77,48 +83,43 @@ AbstractCodec::AbstractCodec( _senderThread(0), _writeMode(PROCESS_SEND_QUEUE), _writeOpReady(false),_lowLatency(false), - _socketBuffer(receiveBuffer), - _sendBuffer(sendBuffer), + _socketBuffer(bufSizeSelect(receiveBufferSize)), + _sendBuffer(bufSizeSelect(sendBufferSize)), //PRIVATE _storedPayloadSize(0), _storedPosition(0), _startPosition(0), - _maxSendPayloadSize(0), + _maxSendPayloadSize(_sendBuffer.getSize() - 2*PVA_MESSAGE_HEADER_SIZE), // start msg + control _lastMessageStartPosition(std::numeric_limits::max()),_lastSegmentedMessageType(0), _lastSegmentedMessageCommand(0), _nextMessagePayloadOffset(0), _byteOrderFlag(EPICS_BYTE_ORDER == EPICS_ENDIAN_BIG ? 0x80 : 0x00), _clientServerFlag(serverFlag ? 0x40 : 0x00), - _socketSendBufferSize(0) + _socketSendBufferSize(socketSendBufferSize) { - if (receiveBuffer->getSize() < 2*MAX_ENSURE_SIZE) + if (_socketBuffer.getSize() < 2*MAX_ENSURE_SIZE) throw std::invalid_argument( "receiveBuffer.capacity() < 2*MAX_ENSURE_SIZE"); // require aligned buffer size //(not condition, but simplifies alignment code) - if (receiveBuffer->getSize() % PVA_ALIGNMENT != 0) + if (_socketBuffer.getSize() % PVA_ALIGNMENT != 0) throw std::invalid_argument( "receiveBuffer.capacity() % PVAConstants.PVA_ALIGNMENT != 0"); - if (sendBuffer->getSize() < 2*MAX_ENSURE_SIZE) + if (_sendBuffer.getSize() < 2*MAX_ENSURE_SIZE) throw std::invalid_argument("sendBuffer() < 2*MAX_ENSURE_SIZE"); // require aligned buffer size //(not condition, but simplifies alignment code) - if (sendBuffer->getSize() % PVA_ALIGNMENT != 0) + if (_sendBuffer.getSize() % PVA_ALIGNMENT != 0) throw std::invalid_argument( "sendBuffer() % PVAConstants.PVA_ALIGNMENT != 0"); // initialize to be empty - _socketBuffer->setPosition(_socketBuffer->getLimit()); - _startPosition = _socketBuffer->getPosition(); + _socketBuffer.setPosition(_socketBuffer.getLimit()); + _startPosition = _socketBuffer.getPosition(); // clear send - _sendBuffer->clear(); - - // start msg + control - _maxSendPayloadSize = - _sendBuffer->getSize() - 2*PVA_MESSAGE_HEADER_SIZE; - _socketSendBufferSize = socketSendBufferSize; + _sendBuffer.clear(); } @@ -142,19 +143,19 @@ void AbstractCodec::processRead() { void AbstractCodec::processHeader() { // magic code - int8_t magicCode = _socketBuffer->getByte(); + int8_t magicCode = _socketBuffer.getByte(); // version - _version = _socketBuffer->getByte(); + _version = _socketBuffer.getByte(); // flags - _flags = _socketBuffer->getByte(); + _flags = _socketBuffer.getByte(); // command - _command = _socketBuffer->getByte(); + _command = _socketBuffer.getByte(); // read payload size - _payloadSize = _socketBuffer->getInt(); + _payloadSize = _socketBuffer.getInt(); // check magic code if (magicCode != PVA_MAGIC) @@ -184,8 +185,8 @@ void AbstractCodec::processReadNormal() { } /* - hexDump("Header", (const int8*)_socketBuffer->getArray(), - _socketBuffer->getPosition(), PVA_MESSAGE_HEADER_SIZE); + hexDump("Header", (const int8*)_socketBuffer.getArray(), + _socketBuffer.getPosition(), PVA_MESSAGE_HEADER_SIZE); */ @@ -216,9 +217,9 @@ void AbstractCodec::processReadNormal() { } _storedPayloadSize = _payloadSize; - _storedPosition = _socketBuffer->getPosition(); - _storedLimit = _socketBuffer->getLimit(); - _socketBuffer->setLimit(std::min + _storedPosition = _socketBuffer.getPosition(); + _storedLimit = _socketBuffer.getLimit(); + _socketBuffer.setLimit(std::min (_storedPosition + _storedPayloadSize, _storedLimit)); bool postProcess = true; try @@ -283,7 +284,7 @@ void AbstractCodec::postProcessApplicationMessage() // we only handle unused alignment bytes int bytesNotRead = - newPosition - _socketBuffer->getPosition(); + newPosition - _socketBuffer.getPosition(); if (bytesNotRead < PVA_ALIGNMENT) { @@ -292,7 +293,7 @@ void AbstractCodec::postProcessApplicationMessage() // due to aligned buffer size _storedPayloadSize += bytesNotRead; // reveal currently existing padding - _socketBuffer->setLimit(_storedLimit); + _socketBuffer.setLimit(_storedLimit); ensureData(bytesNotRead); _storedPayloadSize -= bytesNotRead; continue; @@ -307,8 +308,8 @@ void AbstractCodec::postProcessApplicationMessage() throw invalid_data_stream_exception( "unprocessed read buffer"); } - _socketBuffer->setLimit(_storedLimit); - _socketBuffer->setPosition(newPosition); + _socketBuffer.setLimit(_storedLimit); + _socketBuffer.setPosition(newPosition); break; } } @@ -361,7 +362,7 @@ bool AbstractCodec::readToBuffer( bool persistent) { // do we already have requiredBytes available? - std::size_t remainingBytes = _socketBuffer->getRemaining(); + std::size_t remainingBytes = _socketBuffer.getRemaining(); if (remainingBytes >= requiredBytes) { return true; } @@ -377,22 +378,22 @@ bool AbstractCodec::readToBuffer( // a new start position, we are careful to preserve alignment _startPosition = - MAX_ENSURE_SIZE + _socketBuffer->getPosition() % PVA_ALIGNMENT; + MAX_ENSURE_SIZE + _socketBuffer.getPosition() % PVA_ALIGNMENT; std::size_t endPosition = _startPosition + remainingBytes; for (std::size_t i = _startPosition; i < endPosition; i++) - _socketBuffer->putByte(i, _socketBuffer->getByte()); + _socketBuffer.putByte(i, _socketBuffer.getByte()); // update buffer to the new position - _socketBuffer->setLimit(_socketBuffer->getSize()); - _socketBuffer->setPosition(endPosition); + _socketBuffer.setLimit(_socketBuffer.getSize()); + _socketBuffer.setPosition(endPosition); // read at least requiredBytes bytes std::size_t requiredPosition = _startPosition + requiredBytes; - while (_socketBuffer->getPosition() < requiredPosition) + while (_socketBuffer.getPosition() < requiredPosition) { - int bytesRead = read(_socketBuffer.get()); + int bytesRead = read(&_socketBuffer); if (bytesRead < 0) { @@ -407,8 +408,8 @@ bool AbstractCodec::readToBuffer( else { // set pointers (aka flip) - _socketBuffer->setLimit(_socketBuffer->getPosition()); - _socketBuffer->setPosition(_startPosition); + _socketBuffer.setLimit(_socketBuffer.getPosition()); + _socketBuffer.setPosition(_startPosition); return false; } @@ -416,8 +417,8 @@ bool AbstractCodec::readToBuffer( } // set pointers (aka flip) - _socketBuffer->setLimit(_socketBuffer->getPosition()); - _socketBuffer->setPosition(_startPosition); + _socketBuffer.setLimit(_socketBuffer.getPosition()); + _socketBuffer.setPosition(_startPosition); return true; } @@ -426,7 +427,7 @@ bool AbstractCodec::readToBuffer( void AbstractCodec::ensureData(std::size_t size) { // enough of data? - if (_socketBuffer->getRemaining() >= size) + if (_socketBuffer.getRemaining() >= size) return; // to large for buffer... @@ -436,15 +437,14 @@ void AbstractCodec::ensureData(std::size_t size) { << ", but maximum " << MAX_ENSURE_DATA_SIZE << " is allowed."; LOG(logLevelWarn, "%s at %s:%d.,", msg.str().c_str(), __FILE__, __LINE__); - std::string s = msg.str(); - throw std::invalid_argument(s); + throw std::invalid_argument(msg.str()); } try { // subtract what was already processed - std::size_t pos = _socketBuffer->getPosition(); + std::size_t pos = _socketBuffer.getPosition(); _storedPayloadSize -= pos - _storedPosition; // SPLIT message case @@ -460,9 +460,9 @@ void AbstractCodec::ensureData(std::size_t size) { _readMode = SPLIT; readToBuffer(size, true); _readMode = storedMode; - _storedPosition = _socketBuffer->getPosition(); - _storedLimit = _socketBuffer->getLimit(); - _socketBuffer->setLimit( + _storedPosition = _socketBuffer.getPosition(); + _storedLimit = _socketBuffer.getLimit(); + _socketBuffer.setLimit( std::min( _storedPosition + _storedPayloadSize, _storedLimit)); @@ -483,25 +483,25 @@ void AbstractCodec::ensureData(std::size_t size) { //[0 to MAX_ENSURE_DATA_BUFFER_SIZE/2), if any // remaining is relative to payload since buffer is //bounded from outside - std::size_t remainingBytes = _socketBuffer->getRemaining(); + std::size_t remainingBytes = _socketBuffer.getRemaining(); for (std::size_t i = 0; i < remainingBytes; i++) - _socketBuffer->putByte(i, _socketBuffer->getByte()); + _socketBuffer.putByte(i, _socketBuffer.getByte()); // restore limit (there might be some data already present //and readToBuffer needs to know real limit) - _socketBuffer->setLimit(_storedLimit); + _socketBuffer.setLimit(_storedLimit); // remember alignment offset of end of the message (to be restored) std::size_t storedAlignmentOffset = - _socketBuffer->getPosition() % PVA_ALIGNMENT; + _socketBuffer.getPosition() % PVA_ALIGNMENT; // skip post-message alignment bytes if (storedAlignmentOffset > 0) { std::size_t toSkip = PVA_ALIGNMENT - storedAlignmentOffset; readToBuffer(toSkip, true); - std::size_t currentPos = _socketBuffer->getPosition(); - _socketBuffer->setPosition(currentPos + toSkip); + std::size_t currentPos = _socketBuffer.getPosition(); + _socketBuffer.setPosition(currentPos + toSkip); } // we expect segmented message, we expect header @@ -519,21 +519,21 @@ void AbstractCodec::ensureData(std::size_t size) { //segmented message) // SPLIT cannot mess with this, since start of the message, //i.e. current position, is always aligned - _socketBuffer->setPosition( - _socketBuffer->getPosition() + storedAlignmentOffset); + _socketBuffer.setPosition( + _socketBuffer.getPosition() + storedAlignmentOffset); // copy before position (i.e. start of the payload) for (int32_t i = remainingBytes - 1, - j = _socketBuffer->getPosition() - 1; i >= 0; i--, j--) - _socketBuffer->putByte(j, _socketBuffer->getByte(i)); + j = _socketBuffer.getPosition() - 1; i >= 0; i--, j--) + _socketBuffer.putByte(j, _socketBuffer.getByte(i)); - _startPosition = _socketBuffer->getPosition() - remainingBytes; - _socketBuffer->setPosition(_startPosition); + _startPosition = _socketBuffer.getPosition() - remainingBytes; + _socketBuffer.setPosition(_startPosition); _storedPayloadSize += remainingBytes - storedAlignmentOffset; _storedPosition = _startPosition; - _storedLimit = _socketBuffer->getLimit(); - _socketBuffer->setLimit( + _storedLimit = _socketBuffer.getLimit(); + _socketBuffer.setLimit( std::min( _storedPosition + _storedPayloadSize, _storedLimit)); @@ -565,23 +565,23 @@ std::size_t AbstractCodec::alignedValue( void AbstractCodec::alignData(std::size_t alignment) { std::size_t k = (alignment - 1); - std::size_t pos = _socketBuffer->getPosition(); + std::size_t pos = _socketBuffer.getPosition(); std::size_t newpos = (pos + k) & (~k); if (pos == newpos) return; - std::size_t diff = _socketBuffer->getLimit() - newpos; + std::size_t diff = _socketBuffer.getLimit() - newpos; if (diff > 0) { - _socketBuffer->setPosition(newpos); + _socketBuffer.setPosition(newpos); return; } ensureData(diff); // position has changed, recalculate - newpos = (_socketBuffer->getPosition() + k) & (~k); - _socketBuffer->setPosition(newpos); + newpos = (_socketBuffer.getPosition() + k) & (~k); + _socketBuffer.setPosition(newpos); } static const char PADDING_BYTES[] = @@ -599,7 +599,7 @@ static const char PADDING_BYTES[] = void AbstractCodec::alignBuffer(std::size_t alignment) { std::size_t k = (alignment - 1); - std::size_t pos = _sendBuffer->getPosition(); + std::size_t pos = _sendBuffer.getPosition(); std::size_t newpos = (pos + k) & (~k); if (pos == newpos) return; @@ -607,12 +607,12 @@ void AbstractCodec::alignBuffer(std::size_t alignment) { /* // there is always enough of space // since sendBuffer capacity % PVA_ALIGNMENT == 0 - _sendBuffer->setPosition(newpos); + _sendBuffer.setPosition(newpos); */ // for safety reasons we really pad (override previous message data) std::size_t padCount = newpos - pos; - _sendBuffer->put(PADDING_BYTES, 0, padCount); + _sendBuffer.put(PADDING_BYTES, 0, padCount); } @@ -624,18 +624,18 @@ void AbstractCodec::startMessage( std::numeric_limits::max(); // TODO revise this ensureBuffer( PVA_MESSAGE_HEADER_SIZE + ensureCapacity + _nextMessagePayloadOffset); - _lastMessageStartPosition = _sendBuffer->getPosition(); - _sendBuffer->putByte(PVA_MAGIC); - _sendBuffer->putByte(PVA_VERSION); - _sendBuffer->putByte( + _lastMessageStartPosition = _sendBuffer.getPosition(); + _sendBuffer.putByte(PVA_MAGIC); + _sendBuffer.putByte(PVA_VERSION); + _sendBuffer.putByte( (_lastSegmentedMessageType | _byteOrderFlag | _clientServerFlag)); // data message - _sendBuffer->putByte(command); // command - _sendBuffer->putInt(payloadSize); + _sendBuffer.putByte(command); // command + _sendBuffer.putInt(payloadSize); // apply offset if (_nextMessagePayloadOffset > 0) - _sendBuffer->setPosition( - _sendBuffer->getPosition() + _nextMessagePayloadOffset); + _sendBuffer.setPosition( + _sendBuffer.getPosition() + _nextMessagePayloadOffset); } @@ -646,11 +646,11 @@ void AbstractCodec::putControlMessage( _lastMessageStartPosition = std::numeric_limits::max(); // TODO revise this ensureBuffer(PVA_MESSAGE_HEADER_SIZE); - _sendBuffer->putByte(PVA_MAGIC); - _sendBuffer->putByte(PVA_VERSION); - _sendBuffer->putByte((0x01 | _byteOrderFlag | _clientServerFlag)); // control message - _sendBuffer->putByte(command); // command - _sendBuffer->putInt(data); // data + _sendBuffer.putByte(PVA_MAGIC); + _sendBuffer.putByte(PVA_VERSION); + _sendBuffer.putByte((0x01 | _byteOrderFlag | _clientServerFlag)); // control message + _sendBuffer.putByte(command); // command + _sendBuffer.putInt(data); // data } @@ -663,7 +663,7 @@ void AbstractCodec::endMessage(bool hasMoreSegments) { if (_lastMessageStartPosition != std::numeric_limits::max()) { - std::size_t lastPayloadBytePosition = _sendBuffer->getPosition(); + std::size_t lastPayloadBytePosition = _sendBuffer.getPosition(); // align alignBuffer(PVA_ALIGNMENT); @@ -673,7 +673,7 @@ void AbstractCodec::endMessage(bool hasMoreSegments) { lastPayloadBytePosition - _lastMessageStartPosition - PVA_MESSAGE_HEADER_SIZE; - _sendBuffer->putInt(_lastMessageStartPosition + 4, payloadSize); + _sendBuffer.putInt(_lastMessageStartPosition + 4, payloadSize); // set segmented bit if (hasMoreSegments) { @@ -681,13 +681,13 @@ void AbstractCodec::endMessage(bool hasMoreSegments) { if (_lastSegmentedMessageType == 0) { std::size_t flagsPosition = _lastMessageStartPosition + 2; - epics::pvData::int8 type = _sendBuffer->getByte(flagsPosition); + epics::pvData::int8 type = _sendBuffer.getByte(flagsPosition); // set first segment bit - _sendBuffer->putByte(flagsPosition, (type | 0x10)); + _sendBuffer.putByte(flagsPosition, (type | 0x10)); // first + last segment bit == in-between segment _lastSegmentedMessageType = type | 0x30; _lastSegmentedMessageCommand = - _sendBuffer->getByte(flagsPosition + 1); + _sendBuffer.getByte(flagsPosition + 1); } _nextMessagePayloadOffset = lastPayloadBytePosition % PVA_ALIGNMENT; } @@ -698,7 +698,7 @@ void AbstractCodec::endMessage(bool hasMoreSegments) { { std::size_t flagsPosition = _lastMessageStartPosition + 2; // set last segment bit (by clearing first segment bit) - _sendBuffer->putByte(flagsPosition, + _sendBuffer.putByte(flagsPosition, (_lastSegmentedMessageType & 0xEF)); _lastSegmentedMessageType = 0; } @@ -728,7 +728,7 @@ void AbstractCodec::endMessage(bool hasMoreSegments) { void AbstractCodec::ensureBuffer(std::size_t size) { - if (_sendBuffer->getRemaining() >= size) + if (_sendBuffer.getRemaining() >= size) return; // too large for buffer... @@ -742,7 +742,7 @@ void AbstractCodec::ensureBuffer(std::size_t size) { throw std::invalid_argument(s); } - while (_sendBuffer->getRemaining() < size) + while (_sendBuffer.getRemaining() < size) flush(false); } @@ -753,10 +753,10 @@ void AbstractCodec::flushSerializeBuffer() { void AbstractCodec::flushSendBuffer() { - _sendBuffer->flip(); + _sendBuffer.flip(); try { - send(_sendBuffer.get()); + send(&_sendBuffer); } catch (io_exception &) { try { if (isOpen()) @@ -767,7 +767,7 @@ void AbstractCodec::flushSendBuffer() { throw connection_closed_exception("Failed to send buffer."); } - _sendBuffer->clear(); + _sendBuffer.clear(); _lastMessageStartPosition = std::numeric_limits::max(); } @@ -878,7 +878,7 @@ void AbstractCodec::processSendQueue() if (sender.get() == 0) { // flush - if (_sendBuffer->getPosition() > 0) + if (_sendBuffer.getPosition() > 0) flush(true); sendCompleted(); // do not schedule sending @@ -892,7 +892,7 @@ void AbstractCodec::processSendQueue() try { processSender(sender); } catch(...) { - if (_sendBuffer->getPosition() > 0) + if (_sendBuffer.getPosition() > 0) flush(true); sendCompleted(); throw; @@ -901,7 +901,7 @@ void AbstractCodec::processSendQueue() } // flush - if (_sendBuffer->getPosition() > 0) + if (_sendBuffer.getPosition() > 0) flush(true); } @@ -926,9 +926,9 @@ void AbstractCodec::processSender( ScopedLock lock(sender); try { - _lastMessageStartPosition = _sendBuffer->getPosition(); + _lastMessageStartPosition = _sendBuffer.getPosition(); - sender->send(_sendBuffer.get(), this); + sender->send(&_sendBuffer, this); // automatic end (to set payload size) endMessage(false); @@ -961,10 +961,10 @@ void AbstractCodec::enqueueSendRequest( if (_senderThread == epicsThreadGetIdSelf() && _sendQueue.empty() && - _sendBuffer->getRemaining() >= requiredBufferSize) + _sendBuffer.getRemaining() >= requiredBufferSize) { processSender(sender); - if (_sendBuffer->getPosition() > 0) + if (_sendBuffer.getPosition() > 0) { if (_lowLatency) flush(true); @@ -984,9 +984,9 @@ void AbstractCodec::setRecipient(osiSockAddr const & sendTo) { void AbstractCodec::setByteOrder(int byteOrder) { - _socketBuffer->setEndianess(byteOrder); + _socketBuffer.setEndianess(byteOrder); // TODO sync - _sendBuffer->setEndianess(byteOrder); + _sendBuffer.setEndianess(byteOrder); _byteOrderFlag = EPICS_ENDIAN_BIG == byteOrder ? 0x80 : 0x00; } @@ -1182,16 +1182,13 @@ void BlockingTCPTransportCodec::sendBufferFull(int tries) { BlockingTCPTransportCodec::BlockingTCPTransportCodec(bool serverFlag, const Context::shared_pointer &context, SOCKET channel, const ResponseHandler::shared_pointer &responseHandler, - int32_t sendBufferSize, - int32_t receiveBufferSize, int16 priority) + size_t sendBufferSize, + size_t receiveBufferSize, int16 priority) :AbstractCodec( serverFlag, - std::tr1::shared_ptr(new ByteBuffer((std::max((std::size_t)( - MAX_TCP_RECV + MAX_ENSURE_DATA_BUFFER_SIZE), receiveBufferSize) + - (PVA_ALIGNMENT - 1)) & (~(PVA_ALIGNMENT - 1)))), - std::tr1::shared_ptr(new ByteBuffer((std::max((std::size_t)( MAX_TCP_RECV + - MAX_ENSURE_DATA_BUFFER_SIZE), receiveBufferSize) + (PVA_ALIGNMENT - 1)) - & (~(PVA_ALIGNMENT - 1)))), sendBufferSize, + sendBufferSize, + receiveBufferSize, + sendBufferSize, true) ,_readThread(epics::pvData::Thread::Config(this, &BlockingTCPTransportCodec::receiveThread) .prio(epicsThreadPriorityCAServerLow) diff --git a/src/remote/pv/codec.h b/src/remote/pv/codec.h index bf9fa94..e1727af 100644 --- a/src/remote/pv/codec.h +++ b/src/remote/pv/codec.h @@ -175,8 +175,8 @@ public: AbstractCodec( bool serverFlag, - std::tr1::shared_ptr const & receiveBuffer, - std::tr1::shared_ptr const & sendBuffer, + size_t sendBufferSize, + size_t receiveBufferSize, int32_t socketSendBufferSize, bool blockingProcessQueue); @@ -260,8 +260,8 @@ protected: bool _writeOpReady; bool _lowLatency; - std::tr1::shared_ptr _socketBuffer; - std::tr1::shared_ptr _sendBuffer; + epics::pvData::ByteBuffer _socketBuffer; + epics::pvData::ByteBuffer _sendBuffer; fair_queue _sendQueue; @@ -281,7 +281,7 @@ private: std::size_t _storedLimit; std::size_t _startPosition; - std::size_t _maxSendPayloadSize; + const std::size_t _maxSendPayloadSize; std::size_t _lastMessageStartPosition; std::size_t _lastSegmentedMessageType; int8_t _lastSegmentedMessageCommand; @@ -289,7 +289,7 @@ private: epics::pvData::int8 _byteOrderFlag; epics::pvData::int8 _clientServerFlag; - int32_t _socketSendBufferSize; + const size_t _socketSendBufferSize; }; @@ -308,8 +308,8 @@ public: Context::shared_pointer const & context, SOCKET channel, ResponseHandler::shared_pointer const & responseHandler, - int32_t sendBufferSize, - int32_t receiveBufferSize, + size_t sendBufferSize, + size_t receiveBufferSize, epics::pvData::int16 priority); virtual ~BlockingTCPTransportCodec(); @@ -348,7 +348,7 @@ public: virtual void processApplicationMessage() OVERRIDE FINAL { _responseHandler->handleResponse(&_socketAddress, shared_from_this(), - _version, _command, _payloadSize, _socketBuffer.get()); + _version, _command, _payloadSize, &_socketBuffer); } @@ -366,7 +366,7 @@ public: virtual std::size_t getReceiveBufferSize() const OVERRIDE FINAL { - return _socketBuffer->getSize(); + return _socketBuffer.getSize(); } diff --git a/testApp/remote/testCodec.cpp b/testApp/remote/testCodec.cpp index c504741..058494c 100644 --- a/testApp/remote/testCodec.cpp +++ b/testApp/remote/testCodec.cpp @@ -94,8 +94,8 @@ public: bool blocking = false): AbstractCodec( false, - std::tr1::shared_ptr(new ByteBuffer(receiveBufferSize)), - std::tr1::shared_ptr(new ByteBuffer(sendBufferSize)), + sendBufferSize, + receiveBufferSize, sendBufferSize/10, blocking), _closedCount(0), @@ -171,18 +171,11 @@ public: if (_throwExceptionOnSend) throw io_exception("text IO exception"); - // we could write remaining int8_ts, but for - //test this is enought - if (buffer->getRemaining() > _writeBuffer.getRemaining()) - return 0; + size_t nmove = std::min(buffer->getRemaining(), _writeBuffer.getRemaining()); - std::size_t startPos = buffer->getPosition(); - - while(buffer->getRemaining() > 0) { + for(size_t n=0; ngetByte()); - } - - return buffer->getPosition() - startPos; + return nmove; } @@ -220,7 +213,7 @@ public: void processControlMessage() { // alignment check - if (_socketBuffer->getPosition() % PVA_ALIGNMENT != 0) + if (_socketBuffer.getPosition() % PVA_ALIGNMENT != 0) throw std::logic_error("message not aligned"); _receivedControlMessages.push_back( @@ -230,7 +223,7 @@ public: void processApplicationMessage() { // alignment check - if (_socketBuffer->getPosition() % PVA_ALIGNMENT != 0) + if (_socketBuffer.getPosition() % PVA_ALIGNMENT != 0) throw std::logic_error("message not aligned"); PVAMessage caMessage(_version, _flags, @@ -252,8 +245,8 @@ public: std::size_t pos = caMessage._payload->getPosition(); - while(_socketBuffer->getRemaining() > 0) { - caMessage._payload->putByte(_socketBuffer->getByte()); + while(_socketBuffer.getRemaining() > 0) { + caMessage._payload->putByte(_socketBuffer.getByte()); } std::size_t read = @@ -296,9 +289,9 @@ public: return _writeMode; } - std::tr1::shared_ptr getSendBuffer() + ByteBuffer* getSendBuffer() { - return _sendBuffer; + return &_sendBuffer; } const osiSockAddr* getLastReadBufferSocketAddress() @@ -454,6 +447,9 @@ public: protected: void sendBufferFull(int tries) { + testDiag("sendBufferFull tries=%d", tries); + if(tries>10) // arbitrary limit + testAbort("Stuck"); _sendBufferFullCount++; _writeOpReady = false; _writeMode = WAIT_FOR_READY_SIGNAL; @@ -2770,6 +2766,7 @@ private: TestCodec &codec): _codec(codec) {} void writePollOne() { + testDiag("In %s", CURRENT_FUNCTION); _codec.processWrite(); // this should return immediately // now we fake reading @@ -2819,7 +2816,9 @@ private: codec.breakSender(); try { codec.processSendQueue(); - } catch(sender_break&) {} + } catch(sender_break&) { + testDiag("sender_break"); + } codec.addToReadBuffer(); @@ -2916,26 +2915,6 @@ private: { testDiag("BEGIN TEST %s:", CURRENT_FUNCTION); - try - { - // too small - TestCodec codec(1,DEFAULT_BUFFER_SIZE); - testFail("%s: too small buffer accepted", - CURRENT_FUNCTION); - } catch (std::exception &) { - // OK - } - - try - { - // too small - TestCodec codec(DEFAULT_BUFFER_SIZE,1); - testFail("%s: too small buffer accepted", - CURRENT_FUNCTION); - } catch (std::exception &) { - // OK - } - if (PVA_ALIGNMENT > 1) { try @@ -2970,7 +2949,7 @@ private: try { - codec.ensureBuffer(DEFAULT_BUFFER_SIZE+1); + codec.ensureBuffer(MAX_TCP_RECV + AbstractCodec::MAX_ENSURE_DATA_BUFFER_SIZE+1); testFail("%s: too big size accepted", CURRENT_FUNCTION); } catch (std::exception &) { From 3283bed413cb8a4011ccd56d6e48372f15954daa Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 18 May 2017 19:41:54 -0400 Subject: [PATCH 011/189] drop PVA_ALIGNMENT constant This will forevermore be 1, so no reason to incur complexity of testing this. size % PVA_ALIGNMENT -> 0 alignBuffer(PVA_ALIGNMENT) -> no-op alignedValue(val, PVA_ALIGNMENT) -> val --- src/pva/pv/pvaConstants.h | 7 - src/remote/blockingUDPTransport.cpp | 2 - src/remote/codec.cpp | 66 +----- testApp/remote/testCodec.cpp | 314 +++++----------------------- 4 files changed, 68 insertions(+), 321 deletions(-) diff --git a/src/pva/pv/pvaConstants.h b/src/pva/pv/pvaConstants.h index fb2077b..14f2868 100644 --- a/src/pva/pv/pvaConstants.h +++ b/src/pva/pv/pvaConstants.h @@ -40,13 +40,6 @@ const epics::pvData::int32 PVA_BROADCAST_PORT = 5076; /** PVA protocol message header size. */ const epics::pvData::int16 PVA_MESSAGE_HEADER_SIZE = 8; -/** - * All messages must be aligned to 8-bytes (64-bit). - * MUST be 1. Code does not handle well alignment in some situations (e.g. direct deserialize). - * Alignment is not worth additional code complexity. - */ -const epics::pvData::int32 PVA_ALIGNMENT = 1; - /** * UDP maximum send message size. * MAX_UDP: 1500 (max of ethernet and 802.{2,3} MTU) - 20/40(IPv4/IPv6) diff --git a/src/remote/blockingUDPTransport.cpp b/src/remote/blockingUDPTransport.cpp index 50b8a41..80f42f7 100644 --- a/src/remote/blockingUDPTransport.cpp +++ b/src/remote/blockingUDPTransport.cpp @@ -207,8 +207,6 @@ void BlockingUDPTransport::startMessage(int8 command, size_t /*ensureCapacity*/, } void BlockingUDPTransport::endMessage() { - //we always (for now) send by packet, so no need for this here... - //alignBuffer(PVA_ALIGNMENT); _sendBuffer.putInt( _lastMessageStartPosition+(sizeof(int16)+2), _sendBuffer.getPosition()-_lastMessageStartPosition-PVA_MESSAGE_HEADER_SIZE); diff --git a/src/remote/codec.cpp b/src/remote/codec.cpp index b3cc0c4..0b586c5 100644 --- a/src/remote/codec.cpp +++ b/src/remote/codec.cpp @@ -98,22 +98,9 @@ AbstractCodec::AbstractCodec( throw std::invalid_argument( "receiveBuffer.capacity() < 2*MAX_ENSURE_SIZE"); - // require aligned buffer size - //(not condition, but simplifies alignment code) - - if (_socketBuffer.getSize() % PVA_ALIGNMENT != 0) - throw std::invalid_argument( - "receiveBuffer.capacity() % PVAConstants.PVA_ALIGNMENT != 0"); - if (_sendBuffer.getSize() < 2*MAX_ENSURE_SIZE) throw std::invalid_argument("sendBuffer() < 2*MAX_ENSURE_SIZE"); - // require aligned buffer size - //(not condition, but simplifies alignment code) - if (_sendBuffer.getSize() % PVA_ALIGNMENT != 0) - throw std::invalid_argument( - "sendBuffer() % PVAConstants.PVA_ALIGNMENT != 0"); - // initialize to be empty _socketBuffer.setPosition(_socketBuffer.getLimit()); _startPosition = _socketBuffer.getPosition(); @@ -219,8 +206,7 @@ void AbstractCodec::processReadNormal() { _storedPayloadSize = _payloadSize; _storedPosition = _socketBuffer.getPosition(); _storedLimit = _socketBuffer.getLimit(); - _socketBuffer.setLimit(std::min - (_storedPosition + _storedPayloadSize, _storedLimit)); + _socketBuffer.setLimit(std::min(_storedPosition + _storedPayloadSize, _storedLimit)); bool postProcess = true; try { @@ -268,9 +254,7 @@ void AbstractCodec::postProcessApplicationMessage() { // set position as whole message was read //(in case code haven't done so) - std::size_t newPosition = - alignedValue( - _storedPosition + _storedPayloadSize, PVA_ALIGNMENT); + std::size_t newPosition = _storedPosition + _storedPayloadSize; // aligned buffer size ensures that there is enough space //in buffer, @@ -285,17 +269,12 @@ void AbstractCodec::postProcessApplicationMessage() // we only handle unused alignment bytes int bytesNotRead = newPosition - _socketBuffer.getPosition(); + assert(bytesNotRead>=0); - if (bytesNotRead < PVA_ALIGNMENT) + if (bytesNotRead==0) { - // make alignment bytes as real payload to enable SPLIT - // no end-of-socket or segmented scenario can happen - // due to aligned buffer size - _storedPayloadSize += bytesNotRead; // reveal currently existing padding _socketBuffer.setLimit(_storedLimit); - ensureData(bytesNotRead); - _storedPayloadSize -= bytesNotRead; continue; } @@ -368,7 +347,7 @@ bool AbstractCodec::readToBuffer( } // assumption: remainingBytes < MAX_ENSURE_DATA_BUFFER_SIZE && - // requiredBytes < (socketBuffer.capacity() - PVA_ALIGNMENT) + // requiredBytes < (socketBuffer.capacity() - 1) // // copy unread part to the beginning of the buffer @@ -377,8 +356,7 @@ bool AbstractCodec::readToBuffer( // // a new start position, we are careful to preserve alignment - _startPosition = - MAX_ENSURE_SIZE + _socketBuffer.getPosition() % PVA_ALIGNMENT; + _startPosition = MAX_ENSURE_SIZE; std::size_t endPosition = _startPosition + remainingBytes; @@ -491,19 +469,6 @@ void AbstractCodec::ensureData(std::size_t size) { //and readToBuffer needs to know real limit) _socketBuffer.setLimit(_storedLimit); - // remember alignment offset of end of the message (to be restored) - std::size_t storedAlignmentOffset = - _socketBuffer.getPosition() % PVA_ALIGNMENT; - - // skip post-message alignment bytes - if (storedAlignmentOffset > 0) - { - std::size_t toSkip = PVA_ALIGNMENT - storedAlignmentOffset; - readToBuffer(toSkip, true); - std::size_t currentPos = _socketBuffer.getPosition(); - _socketBuffer.setPosition(currentPos + toSkip); - } - // we expect segmented message, we expect header // that (and maybe some control packets) needs to be "removed" // so that we get combined payload @@ -513,14 +478,12 @@ void AbstractCodec::ensureData(std::size_t size) { _readMode = storedMode; // make sure we have all the data (maybe we run into SPLIT) - readToBuffer(size - remainingBytes + storedAlignmentOffset, true); + readToBuffer(size - remainingBytes, true); - // skip storedAlignmentOffset bytes (sender should padded start of - //segmented message) // SPLIT cannot mess with this, since start of the message, //i.e. current position, is always aligned _socketBuffer.setPosition( - _socketBuffer.getPosition() + storedAlignmentOffset); + _socketBuffer.getPosition()); // copy before position (i.e. start of the payload) for (int32_t i = remainingBytes - 1, @@ -530,7 +493,7 @@ void AbstractCodec::ensureData(std::size_t size) { _startPosition = _socketBuffer.getPosition() - remainingBytes; _socketBuffer.setPosition(_startPosition); - _storedPayloadSize += remainingBytes - storedAlignmentOffset; + _storedPayloadSize += remainingBytes; _storedPosition = _startPosition; _storedLimit = _socketBuffer.getLimit(); _socketBuffer.setLimit( @@ -604,12 +567,6 @@ void AbstractCodec::alignBuffer(std::size_t alignment) { if (pos == newpos) return; - /* - // there is always enough of space - // since sendBuffer capacity % PVA_ALIGNMENT == 0 - _sendBuffer.setPosition(newpos); - */ - // for safety reasons we really pad (override previous message data) std::size_t padCount = newpos - pos; _sendBuffer.put(PADDING_BYTES, 0, padCount); @@ -665,9 +622,6 @@ void AbstractCodec::endMessage(bool hasMoreSegments) { { std::size_t lastPayloadBytePosition = _sendBuffer.getPosition(); - // align - alignBuffer(PVA_ALIGNMENT); - // set paylaod size (non-aligned) std::size_t payloadSize = lastPayloadBytePosition - @@ -689,7 +643,7 @@ void AbstractCodec::endMessage(bool hasMoreSegments) { _lastSegmentedMessageCommand = _sendBuffer.getByte(flagsPosition + 1); } - _nextMessagePayloadOffset = lastPayloadBytePosition % PVA_ALIGNMENT; + _nextMessagePayloadOffset = 0; } else { diff --git a/testApp/remote/testCodec.cpp b/testApp/remote/testCodec.cpp index 058494c..67baa74 100644 --- a/testApp/remote/testCodec.cpp +++ b/testApp/remote/testCodec.cpp @@ -212,20 +212,12 @@ public: void processControlMessage() { - // alignment check - if (_socketBuffer.getPosition() % PVA_ALIGNMENT != 0) - throw std::logic_error("message not aligned"); - _receivedControlMessages.push_back( PVAMessage(_version, _flags, _command, _payloadSize)); } void processApplicationMessage() { - // alignment check - if (_socketBuffer.getPosition() % PVA_ALIGNMENT != 0) - throw std::logic_error("message not aligned"); - PVAMessage caMessage(_version, _flags, _command, _payloadSize); @@ -472,7 +464,6 @@ public: testHeaderSplitRead(); testNonEmptyPayload(); testNormalAlignment(); - testSplitAlignment(); testSegmentedMessage(); //testSegmentedInvalidInBetweenFlagsMessage(); testSegmentedMessageAlignment(); @@ -776,9 +767,8 @@ private: codec._readBuffer->put(PVA_VERSION); codec._readBuffer->put((int8_t)0x80); codec._readBuffer->put((int8_t)0x23); - codec._readBuffer->putInt(PVA_ALIGNMENT); - for (int i = 0; i < PVA_ALIGNMENT; i++) - codec._readBuffer->put((int8_t)i); + codec._readBuffer->putInt(1); // size + codec._readBuffer->put((int8_t)0); codec._readBuffer->flip(); codec.processRead(); @@ -804,8 +794,8 @@ private: header._payload->flip(); testOk( - (std::size_t)PVA_ALIGNMENT == header._payload->getLimit(), - "%s: PVA_ALIGNMENT == header._payload->getLimit()", + 1 == header._payload->getLimit(), + "%s: 1 == header._payload->getLimit()", CURRENT_FUNCTION); } @@ -823,14 +813,13 @@ private: codec._readBuffer->put(PVA_VERSION); codec._readBuffer->put((int8_t)0x80); codec._readBuffer->put((int8_t)0x23); - int32_t payloadSize1 = PVA_ALIGNMENT+1; + const int32_t payloadSize1 = 2; codec._readBuffer->putInt(payloadSize1); for (int32_t i = 0; i < payloadSize1; i++) codec._readBuffer->put((int8_t)i); // align - std::size_t aligned = - AbstractCodec::alignedValue(payloadSize1, PVA_ALIGNMENT); + std::size_t aligned = payloadSize1; for (std::size_t i = payloadSize1; i < aligned; i++) codec._readBuffer->put((int8_t)0xFF); @@ -841,15 +830,14 @@ private: codec._readBuffer->put((int8_t)0x80); codec._readBuffer->put((int8_t)0x45); - int32_t payloadSize2 = 2*PVA_ALIGNMENT-1; + const int32_t payloadSize2 = 1; codec._readBuffer->putInt(payloadSize2); for (int32_t i = 0; i < payloadSize2; i++) { codec._readBuffer->put((int8_t)i); } - aligned = - AbstractCodec::alignedValue(payloadSize2, PVA_ALIGNMENT); + aligned = payloadSize2; for (std::size_t i = payloadSize2; i < aligned; i++) { codec._readBuffer->put((int8_t)0xFF); @@ -937,9 +925,7 @@ private: } // align - std::size_t aligned = - AbstractCodec::alignedValue( - _payloadSize1, PVA_ALIGNMENT); + std::size_t aligned = _payloadSize1; for (std::size_t i = _payloadSize1; i < aligned; i++) _codec._readBuffer->put((int8_t)0xFF); @@ -961,9 +947,7 @@ private: { _codec._readBuffer->clear(); - std::size_t aligned = - AbstractCodec::alignedValue( - _payloadSize2, PVA_ALIGNMENT); + std::size_t aligned = _payloadSize2; for (std::size_t i = _payloadSize2; i < aligned; i++) { _codec._readBuffer->put((int8_t)0xFF); @@ -983,97 +967,6 @@ private: }; - void testSplitAlignment() - { - - testDiag("BEGIN TEST %s:", CURRENT_FUNCTION); - TestCodec codec(DEFAULT_BUFFER_SIZE,DEFAULT_BUFFER_SIZE); - - // "<=" used instead of "==" to suppress compiler warning - if (PVA_ALIGNMENT <= 1) - return; - - codec._readPayload = true; - - codec._readBuffer->put(PVA_MAGIC); - codec._readBuffer->put(PVA_VERSION); - codec._readBuffer->put((int8_t)0x80); - codec._readBuffer->put((int8_t)0x23); - - int32_t payloadSize1 = PVA_ALIGNMENT+1; - codec._readBuffer->putInt(payloadSize1); - - for (int32_t i = 0; i < payloadSize1-2; i++) { - codec._readBuffer->put((int8_t)i); - } - - int32_t payloadSize2 = 2*PVA_ALIGNMENT-1; - - std::auto_ptr - readPollOneCallback( - new ReadPollOneCallbackForTestSplitAlignment - (codec, payloadSize1, payloadSize2)); - - codec._readPollOneCallback = readPollOneCallback; - - codec._readBuffer->flip(); - codec.processRead(); - - - testOk(codec._invalidDataStreamCount == 0, - "%s: codec._invalidDataStreamCount == 0", - CURRENT_FUNCTION); - testOk(codec._closedCount == 0, - "%s: codec._closedCount == 0", CURRENT_FUNCTION); - testOk(codec._receivedControlMessages.size() == 0, - "%s: codec._receivedControlMessages.size() == 0 ", - CURRENT_FUNCTION); - testOk(codec._receivedAppMessages.size() == 2, - "%s: codec._receivedAppMessages.size() == 2", - CURRENT_FUNCTION); - testOk(codec._readPollOneCount == 2, - "%s: codec._readPollOneCount == 2", CURRENT_FUNCTION); - - PVAMessage msg = codec._receivedAppMessages[0]; - - testOk(msg._payloadSize == payloadSize1, - "%s: msg._payloadSize == payloadSize1", CURRENT_FUNCTION); - testOk(msg._payload.get() != 0, - "%s: msg._payload.get() != 0", CURRENT_FUNCTION); - - msg._payload->flip(); - - testOk(payloadSize1 = msg._payload->getLimit(), - "%s: payloadSize1 = msg._payload->getLimit()", - CURRENT_FUNCTION); - - for (int32_t i = 0; i < msg._payloadSize; i++) { - testOk((int8_t)i == msg._payload->getByte(), - "%s: (int8_t)i == msg._payload->getByte()", - CURRENT_FUNCTION); - } - - msg = codec._receivedAppMessages[1]; - - testOk(msg._payloadSize == payloadSize2, - "%s: msg._payloadSize == payloadSize2", CURRENT_FUNCTION); - testOk(msg._payload.get() != 0, - "%s: msg._payload.get() != 0", CURRENT_FUNCTION); - - msg._payload->flip(); - - testOk((std::size_t)payloadSize2 == msg._payload->getLimit(), - "%s: payloadSize2 == msg._payload->getLimit()", - CURRENT_FUNCTION); - - for (int32_t i = 0; i < msg._payloadSize; i++) { - testOk((int8_t)i == msg._payload->getByte(), - "%s: (int8_t)i == msg._payload->getByte()", - CURRENT_FUNCTION); - } - } - - void testSegmentedMessage() { @@ -1089,7 +982,7 @@ private: codec._readBuffer->put((int8_t)0x90); codec._readBuffer->put((int8_t)0x01); - int32_t payloadSize1 = PVA_ALIGNMENT; + int32_t payloadSize1 = 1; codec._readBuffer->putInt(payloadSize1); int32_t c = 0; @@ -1102,7 +995,7 @@ private: codec._readBuffer->put((int8_t)0xB0); codec._readBuffer->put((int8_t)0x01); - int32_t payloadSize2 = 2*PVA_ALIGNMENT; + int32_t payloadSize2 = 2; codec._readBuffer->putInt(payloadSize2); for (int32_t i = 0; i < payloadSize2; i++) @@ -1121,7 +1014,7 @@ private: codec._readBuffer->put((int8_t)0xB0); codec._readBuffer->put((int8_t)0x01); - int32_t payloadSize3 = PVA_ALIGNMENT; + int32_t payloadSize3 = 1; codec._readBuffer->putInt(payloadSize3); for (int32_t i = 0; i < payloadSize3; i++) @@ -1133,7 +1026,7 @@ private: codec._readBuffer->put((int8_t)0xA0); codec._readBuffer->put((int8_t)0x01); - int32_t payloadSize4 = 2*PVA_ALIGNMENT; + int32_t payloadSize4 = 2; codec._readBuffer->putInt(payloadSize4); for (int32_t i = 0; i < payloadSize4; i++) @@ -1209,7 +1102,7 @@ private: codec._readBuffer->put((int8_t)0x90); codec._readBuffer->put((int8_t)0x01); - int32_t payloadSize1 = PVA_ALIGNMENT; + int32_t payloadSize1 = 1; codec._readBuffer->putInt(payloadSize1); int32_t c = 0; @@ -1223,7 +1116,7 @@ private: codec._readBuffer->put((int8_t)0x90); codec._readBuffer->put((int8_t)0x01); - int32_t payloadSize2 = 2*PVA_ALIGNMENT; + int32_t payloadSize2 = 2; codec._readBuffer->putInt(payloadSize2); for (int32_t i = 0; i < payloadSize2; i++) @@ -1242,7 +1135,7 @@ private: codec._readBuffer->put((int8_t)0xB0); codec._readBuffer->put((int8_t)0x01); - int32_t payloadSize3 = PVA_ALIGNMENT; + int32_t payloadSize3 = 1; codec._readBuffer->putInt(payloadSize3); for (int32_t i = 0; i < payloadSize3; i++) @@ -1254,7 +1147,7 @@ private: codec._readBuffer->put((int8_t)0xA0); codec._readBuffer->put((int8_t)0x01); - int32_t payloadSize4 = 2*PVA_ALIGNMENT; + int32_t payloadSize4 = 2; codec._readBuffer->putInt(payloadSize4); for (int32_t i = 0; i < payloadSize4; i++) @@ -1303,15 +1196,14 @@ private: codec._readBuffer->put((int8_t)0x90); codec._readBuffer->put((int8_t)0x01); - int32_t payloadSize1 = PVA_ALIGNMENT+1; + int32_t payloadSize1 = 1+1; codec._readBuffer->putInt(payloadSize1); int32_t c = 0; for (int32_t i = 0; i < payloadSize1; i++) codec._readBuffer->put((int8_t)(c++)); - std::size_t aligned = - AbstractCodec::alignedValue(payloadSize1, PVA_ALIGNMENT); + std::size_t aligned = payloadSize1; for (std::size_t i = payloadSize1; i < aligned; i++) codec._readBuffer->put((int8_t)0xFF); @@ -1322,22 +1214,15 @@ private: codec._readBuffer->put((int8_t)0xB0); codec._readBuffer->put((int8_t)0x01); - int32_t payloadSize2 = 2*PVA_ALIGNMENT-1; - int32_t payloadSize2Real = - payloadSize2 + payloadSize1 % PVA_ALIGNMENT; + int32_t payloadSize2 = 1; + int32_t payloadSize2Real = payloadSize2; codec._readBuffer->putInt(payloadSize2Real); - // pre-message padding - for (int32_t i = 0; i < payloadSize1 % PVA_ALIGNMENT; i++) - codec._readBuffer->put((int8_t)0xEE); - for (int32_t i = 0; i < payloadSize2; i++) codec._readBuffer->put((int8_t)(c++)); - aligned = - AbstractCodec::alignedValue( - payloadSize2Real, PVA_ALIGNMENT); + aligned = payloadSize2Real; for (std::size_t i = payloadSize2Real; i < aligned; i++) codec._readBuffer->put((int8_t)0xFF); @@ -1348,22 +1233,14 @@ private: codec._readBuffer->put((int8_t)0xB0); codec._readBuffer->put((int8_t)0x01); - int32_t payloadSize3 = PVA_ALIGNMENT+2; - int32_t payloadSize3Real = - payloadSize3 + payloadSize2Real % PVA_ALIGNMENT; + int32_t payloadSize3 = 3; + int32_t payloadSize3Real = payloadSize3; codec._readBuffer->putInt(payloadSize3Real); - // pre-message padding required - for (int32_t i = 0; - i < payloadSize2Real % PVA_ALIGNMENT; i++) - codec._readBuffer->put((int8_t)0xEE); - for (int32_t i = 0; i < payloadSize3; i++) codec._readBuffer->put((int8_t)(c++)); - aligned = - AbstractCodec::alignedValue( - payloadSize3Real, PVA_ALIGNMENT); + aligned = payloadSize3Real; for (std::size_t i = payloadSize3Real; i < aligned; i++) codec._readBuffer->put((int8_t)0xFF); @@ -1374,23 +1251,15 @@ private: codec._readBuffer->put((int8_t)0xA0); codec._readBuffer->put((int8_t)0x01); - int32_t payloadSize4 = 2*PVA_ALIGNMENT+3; - int32_t payloadSize4Real = - payloadSize4 + payloadSize3Real % PVA_ALIGNMENT; + int32_t payloadSize4 = 2+3; + int32_t payloadSize4Real = payloadSize4; codec._readBuffer->putInt(payloadSize4Real); - // pre-message padding required - for (int32_t i = 0; - i < payloadSize3Real % PVA_ALIGNMENT; i++) - codec._readBuffer->put((int8_t)0xEE); - for (int32_t i = 0; i < payloadSize4; i++) codec._readBuffer->put((int8_t)(c++)); - aligned = - AbstractCodec::alignedValue( - payloadSize4Real, PVA_ALIGNMENT); + aligned = payloadSize4Real; for (std::size_t i = payloadSize4Real; i < aligned; i++) codec._readBuffer->put((int8_t)0xFF); @@ -1468,16 +1337,16 @@ private: testDiag("BEGIN TEST %s:", CURRENT_FUNCTION); for (int32_t firstMessagePayloadSize = 1; // cannot be zero - firstMessagePayloadSize <= 3*PVA_ALIGNMENT; + firstMessagePayloadSize <= 3; firstMessagePayloadSize++) { for (int32_t secondMessagePayloadSize = 0; - secondMessagePayloadSize <= 2*PVA_ALIGNMENT; + secondMessagePayloadSize <= 2; secondMessagePayloadSize++) { // cannot be zero for (int32_t thirdMessagePayloadSize = 1; - thirdMessagePayloadSize <= 2*PVA_ALIGNMENT; + thirdMessagePayloadSize <= 2; thirdMessagePayloadSize++) { std::size_t splitAt = 1; @@ -1501,9 +1370,7 @@ private: for (int32_t i = 0; i < payloadSize1; i++) codec._readBuffer->put((int8_t)(c++)); - std::size_t aligned = - AbstractCodec::alignedValue( - payloadSize1, PVA_ALIGNMENT); + std::size_t aligned = payloadSize1; for (std::size_t i = payloadSize1; i < aligned; i++) codec._readBuffer->put((int8_t)0xFF); @@ -1515,22 +1382,14 @@ private: codec._readBuffer->put((int8_t)0x01); int32_t payloadSize2 = secondMessagePayloadSize; - int payloadSize2Real = - payloadSize2 + payloadSize1 % PVA_ALIGNMENT; + int payloadSize2Real = payloadSize2; codec._readBuffer->putInt(payloadSize2Real); - // pre-message padding - for (int32_t i = 0; - i < payloadSize1 % PVA_ALIGNMENT; i++) - codec._readBuffer->put((int8_t)0xEE); - for (int32_t i = 0; i < payloadSize2; i++) codec._readBuffer->put((int8_t)(c++)); - aligned = - AbstractCodec::alignedValue( - payloadSize2Real, PVA_ALIGNMENT); + aligned = payloadSize2Real; for (std::size_t i = payloadSize2Real; i < aligned; i++) @@ -1543,22 +1402,14 @@ private: codec._readBuffer->put((int8_t)0x01); int32_t payloadSize3 = thirdMessagePayloadSize; - int32_t payloadSize3Real = - payloadSize3 + payloadSize2Real % PVA_ALIGNMENT; + int32_t payloadSize3Real = payloadSize3; codec._readBuffer->putInt(payloadSize3Real); - // pre-message padding required - for (int32_t i = 0; - i < payloadSize2Real % PVA_ALIGNMENT; i++) - codec._readBuffer->put((int8_t)0xEE); - for (int32_t i = 0; i < payloadSize3; i++) codec._readBuffer->put((int8_t)(c++)); - aligned = - AbstractCodec::alignedValue( - payloadSize3Real, PVA_ALIGNMENT); + aligned = payloadSize3Real; for (std::size_t i = payloadSize3Real; i < aligned; i++) @@ -1742,9 +1593,8 @@ private: codec._readPayload = true; codec.startMessage((int8_t)0x23, 0); - codec.ensureBuffer((std::size_t)PVA_ALIGNMENT); - for (int32_t i = 0; i < PVA_ALIGNMENT; i++) - codec.getSendBuffer()->put((int8_t)i); + codec.ensureBuffer(1); + codec.getSendBuffer()->put((int8_t)0); codec.endMessage(); @@ -1772,8 +1622,7 @@ private: header._payload->flip(); - testOk((std::size_t)PVA_ALIGNMENT == - header._payload->getLimit(), + testOk(1u == header._payload->getLimit(), "%s: PVA_ALIGNMENT == header._payload->getLimit()", CURRENT_FUNCTION); } @@ -1787,7 +1636,7 @@ private: codec._readPayload = true; codec.startMessage((int8_t)0x23, 0); - int32_t payloadSize1 = PVA_ALIGNMENT+1; + int32_t payloadSize1 = 1+1; codec.ensureBuffer(payloadSize1); for (int32_t i = 0; i < payloadSize1; i++) @@ -1796,7 +1645,7 @@ private: codec.endMessage(); codec.startMessage((int8_t)0x45, 0); - int32_t payloadSize2 = 2*PVA_ALIGNMENT-1; + int32_t payloadSize2 = 1; codec.ensureBuffer(payloadSize2); for (int32_t i = 0; i < payloadSize2; i++) @@ -1872,25 +1721,25 @@ private: int32_t c = 0; - int32_t payloadSize1 = PVA_ALIGNMENT; + int32_t payloadSize1 = 1; for (int32_t i = 0; i < payloadSize1; i++) codec.getSendBuffer()->put((int8_t)(c++)); codec.flush(false); - int32_t payloadSize2 = 2*PVA_ALIGNMENT; + int32_t payloadSize2 = 2; for (int32_t i = 0; i < payloadSize2; i++) codec.getSendBuffer()->put((int8_t)(c++)); codec.flush(false); - int32_t payloadSize3 = PVA_ALIGNMENT; + int32_t payloadSize3 = 1; for (int32_t i = 0; i < payloadSize3; i++) codec.getSendBuffer()->put((int8_t)(c++)); codec.flush(false); - int32_t payloadSize4 = 2*PVA_ALIGNMENT; + int32_t payloadSize4 = 2; for (int32_t i = 0; i < payloadSize4; i++) codec.getSendBuffer()->put((int8_t)(c++)); @@ -1943,21 +1792,21 @@ private: testDiag("BEGIN TEST %s:", CURRENT_FUNCTION); for (int32_t firstMessagePayloadSize = 1; // cannot be zero - firstMessagePayloadSize <= 3*PVA_ALIGNMENT; + firstMessagePayloadSize <= 3; firstMessagePayloadSize++) { for (int32_t secondMessagePayloadSize = 0; - secondMessagePayloadSize <= 2*PVA_ALIGNMENT; + secondMessagePayloadSize <= 2; secondMessagePayloadSize++) { // cannot be zero for (int32_t thirdMessagePayloadSize = 1; - thirdMessagePayloadSize <= 2*PVA_ALIGNMENT; + thirdMessagePayloadSize <= 2; thirdMessagePayloadSize++) { // cannot be zero for (int32_t fourthMessagePayloadSize = 1; - fourthMessagePayloadSize <= 2*PVA_ALIGNMENT; + fourthMessagePayloadSize <= 2; fourthMessagePayloadSize++) { TestCodec codec(DEFAULT_BUFFER_SIZE, @@ -2105,16 +1954,16 @@ private: for (int32_t firstMessagePayloadSize = 1; // cannot be zero - firstMessagePayloadSize <= 3*PVA_ALIGNMENT; + firstMessagePayloadSize <= 3; firstMessagePayloadSize++) { for (int32_t secondMessagePayloadSize = 0; - secondMessagePayloadSize <= 2*PVA_ALIGNMENT; + secondMessagePayloadSize <= 2; secondMessagePayloadSize++) { // cannot be zero for (int32_t thirdMessagePayloadSize = 1; - thirdMessagePayloadSize <= 2*PVA_ALIGNMENT; + thirdMessagePayloadSize <= 2; thirdMessagePayloadSize++) { std::size_t splitAt = 1; @@ -2139,9 +1988,7 @@ private: for (int32_t i = 0; i < payloadSize1; i++) codec._readBuffer->put((int8_t)(c++)); - std::size_t aligned = - AbstractCodec::alignedValue( - payloadSize1, PVA_ALIGNMENT); + std::size_t aligned = payloadSize1; for (std::size_t i = payloadSize1; i < aligned; i++) codec._readBuffer->put((int8_t)0xFF); @@ -2153,22 +2000,14 @@ private: codec._readBuffer->put((int8_t)0x01); int32_t payloadSize2 = secondMessagePayloadSize; - int32_t payloadSize2Real = - payloadSize2 + payloadSize1 % PVA_ALIGNMENT; + int32_t payloadSize2Real = payloadSize2; codec._readBuffer->putInt(payloadSize2Real); - // pre-message padding - for (int32_t i = 0; - i < payloadSize1 % PVA_ALIGNMENT; i++) - codec._readBuffer->put((int8_t)0xEE); - for (int32_t i = 0; i < payloadSize2; i++) codec._readBuffer->put((int8_t)(c++)); - aligned = - AbstractCodec::alignedValue( - payloadSize2Real, PVA_ALIGNMENT); + aligned = payloadSize2Real; for (std::size_t i = payloadSize2Real; i < aligned; i++) @@ -2181,22 +2020,14 @@ private: codec._readBuffer->put((int8_t)0x01); int32_t payloadSize3 = thirdMessagePayloadSize; - int32_t payloadSize3Real = - payloadSize3 + payloadSize2Real % PVA_ALIGNMENT; + int32_t payloadSize3Real = payloadSize3; codec._readBuffer->putInt(payloadSize3Real); - // pre-message padding required - for (int32_t i = 0; - i < payloadSize2Real % PVA_ALIGNMENT; i++) - codec._readBuffer->put((int8_t)0xEE); - for (int32_t i = 0; i < payloadSize3; i++) codec._readBuffer->put((int8_t)(c++)); - aligned = - AbstractCodec::alignedValue( - payloadSize3Real, PVA_ALIGNMENT); + aligned = payloadSize3Real; for (std::size_t i = payloadSize3Real; i < aligned; i++) @@ -2915,35 +2746,6 @@ private: { testDiag("BEGIN TEST %s:", CURRENT_FUNCTION); - if (PVA_ALIGNMENT > 1) - { - try - { - // non aligned - TestCodec codec(2*AbstractCodec::MAX_ENSURE_SIZE+1, - DEFAULT_BUFFER_SIZE); - - testFail("%s: non-aligned buffer size accepted", - CURRENT_FUNCTION); - - } catch (std::exception &) { - // OK - } - - try - { - // non aligned - TestCodec codec(DEFAULT_BUFFER_SIZE, - 2*AbstractCodec::MAX_ENSURE_SIZE+1); - - testFail("%s: non-aligned buffer size accepted", - CURRENT_FUNCTION); - - } catch (std::exception &) { - // OK - } - } - TestCodec codec(DEFAULT_BUFFER_SIZE, DEFAULT_BUFFER_SIZE); From 24c9b31cf6ab79c779a04427af6227753dbdcda7 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 23 May 2017 17:13:39 -0400 Subject: [PATCH 012/189] update pvAccess.h doc comments describe how things should be! --- src/client/pv/pvAccess.h | 340 ++++++++++++++++++--------- src/factory/ChannelAccessFactory.cpp | 6 +- 2 files changed, 232 insertions(+), 114 deletions(-) diff --git a/src/client/pv/pvAccess.h b/src/client/pv/pvAccess.h index 1c071e9..088ebc6 100644 --- a/src/client/pv/pvAccess.h +++ b/src/client/pv/pvAccess.h @@ -593,7 +593,7 @@ public: /** - * Requester for channelGet. + * Handle for an RPC operation */ class epicsShareClass ChannelRPC : public ChannelRequest { public: @@ -604,7 +604,16 @@ public: /** * Issue an RPC request to the channel. - * Completion status is reported by calling ChannelRPCRequester.requestDone() callback. + * + * Completion status is reported by calling ChannelRPCRequester::requestDone() callback, + * which may be called from this method. + * + * @pre The underlying Channel must be connected, and this ChannelRPC valid. + * Otherwise the ChannelRPCRequester::requestDone() is called with an error. + * + * @post After calling request(), the requestDone() callback will be called at some later time. + * May call ChannelRPC::cancel() to request to abort() this operation. + * * @param pvArgument The argument structure for an RPC request. */ virtual void request(epics::pvData::PVStructure::shared_pointer const & pvArgument) = 0; @@ -612,7 +621,9 @@ public: /** - * Requester for channelGet. + * Notifications associated with Channel::createChannelRPC() + * + * No locks may be held while calling these methods. */ class epicsShareClass ChannelRPCRequester : virtual public Requester { public: @@ -622,29 +633,37 @@ public: virtual ~ChannelRPCRequester() {} /** - * The client and server have both completed the createChannelGet request. - * @param status Completion status. - * @param channelRPC The channelRPC interface or null if the request failed. + * RPC creation request satisfied. + * + * Must check status.isOk(). + * + * On Success, a non-NULL 'operation' is provided. + * This is the same pointer which was, or will be, returned from Channel::createChannelRPC(). + * + * It is allowed to call ChannelRPC::request() from within this method. */ virtual void channelRPCConnect( const epics::pvData::Status& status, - ChannelRPC::shared_pointer const & channelRPC) = 0; + ChannelRPC::shared_pointer const & operation) = 0; /** - * The request is done. This is always called with no locks held. - * @param status Completion status. - * @param channelRPC The channelRPC interface. - * @param pvResponse The response data for the RPC request or null if the request failed. + * RPC request (execution) completed. + * + * Must check status.isOk(). + * + * On Success, a non-NULL 'pvResponse' is provided. + * + * It is allowed to call ChannelRPC::request() from within this method. */ virtual void requestDone( const epics::pvData::Status& status, - ChannelRPC::shared_pointer const & channelRPC, + ChannelRPC::shared_pointer const & operation, epics::pvData::PVStructure::shared_pointer const & pvResponse) = 0; }; /** - * Requester for a getStructure request. + * Completion notification for Channel::getField() */ class epicsShareClass GetFieldRequester : virtual public Requester { public: @@ -653,7 +672,10 @@ public: virtual ~GetFieldRequester() {} /** - * The client and server have both completed the getStructure request. + * Check status.isOk() to determine success. + * On success the 'field' will be non-NULL. + * On failure 'field' will be NULL. + * * @param status Completion status. * @param field The Structure for the request. */ @@ -667,8 +689,15 @@ public: class ChannelRequester; /** - * Interface for accessing a channel. - * A channel is created via a call to ChannelAccess.createChannel(std::string channelName). + * The interface through which Operations (get, put, monitor, ...) are initiated. + * + * Handle for a Channel returned by ChannelProvider::createChannel() + * + * At any given moment a Channel may be CONNECTED or DISCONNECTED. (NEVER_CONNECTED and DESTORYED are special cases of DISCONNECTED) + * + * A Channel is required to honor calls to Channel::create*() methods while in the disconnected state. + * + * A Channel is required to maintain a strong reference (shared_ptr<>) to the ChannelProvider through which it was created. */ class epicsShareClass Channel : public Requester, @@ -693,8 +722,8 @@ public: static const char* ConnectionStateNames[]; /** - * Get the the channel provider of this channel. - * @return The channel provider. + * The ChannelProvider from which this Channel was requested. + * May never be NULL. */ virtual std::tr1::shared_ptr getProvider() = 0; @@ -703,137 +732,188 @@ public: * For example: * - client side channel would return server's address, e.g. "/192.168.1.101:5064" * - server side channel would return underlying bus address, e.g. "#C0 S1". - * @return the channel's address. + * + * The value returned here will changed depending on the connection status. + * A disconnected channel should return an empty() string. **/ virtual std::string getRemoteAddress() = 0; /** - * Returns the connection state of this channel. - * @return the ConnectionState value. + * Poll the connection state in more detail **/ virtual ConnectionState getConnectionState() = 0; /** - * Get the channel name. - * @return The name. + * The name passed to ChannelProvider::createChannel() */ virtual std::string getChannelName() = 0; /** - * Get the channel Requester. - * @return The Requester. + * The ChannelRequester passed to ChannelProvider::createChannel() */ -// virtual ChannelRequester::shared_pointer getChannelRequester() = 0; virtual std::tr1::shared_ptr getChannelRequester() = 0; /** - * Is the channel connected? - * @return (false,true) means (not, is) connected. + * Poll connection state */ virtual bool isConnected() { return getConnectionState()==CONNECTED; } /** - * Get a Field which describes the subField. - * GetFieldRequester.getDone is called after both client and server have processed the getField request. - * This is for clients that want to introspect a PVRecord via channel access. + * Initiate a request to retrieve a description of the structure of this Channel. + * + * While the type described by calls to getField() should match what is provided for all operations except RPC. + * + * GetFieldRequester::getDone() will be called before getField() returns, or at some time afterwards. + * * @param Requester The Requester. - * @param subField The name of the subField. - * If this is null or an empty std::string the returned Field is for the entire record. + * @param subField Empty string, or the field name of a sub-structure. */ virtual void getField(GetFieldRequester::shared_pointer const & requester,std::string const & subField) = 0; /** - * Get the access rights for a field of a PVStructure created via a call to createPVStructure. - * MATEJ Channel access can store this info via auxInfo. + * Not useful... + * * @param pvField The field for which access rights is desired. * @return The access rights. */ virtual AccessRights getAccessRights(epics::pvData::PVField::shared_pointer const & pvField) = 0; /** - * Create a ChannelProcess. - * ChannelProcessRequester.channelProcessReady is called after both client and server are ready for - * the client to make a process request. - * @param channelProcessRequester The interface for notifying when this request is complete - * and when channel completes processing. - * @param pvRequest Additional options (e.g. triggering). - * @return ChannelProcess instance. + * Initiate a request for a Process action. + * + * ChannelProcessRequester::channelProcessConnect() may be called before createChannelProcess() returns, or at some time afterwards. + * + * Failure is indicated by a call to channelProcessConnect with !Error::isOk() + * + * @pre The Channel need not be CONNECTED + * + * @post The returned ChannelProcess will hold a strong reference to the provided ChannelProcessRequester. + * + * @post Returned shared_ptr will have unique()==true. + * + * @return A non-NULL ChannelProcess unless channelProcessConnect() called with an Error */ virtual ChannelProcess::shared_pointer createChannelProcess( - ChannelProcessRequester::shared_pointer const & channelProcessRequester, + ChannelProcessRequester::shared_pointer const & requester, epics::pvData::PVStructure::shared_pointer const & pvRequest); /** - * Create a ChannelGet. - * ChannelGetRequester.channelGetReady is called after both client and server are ready for - * the client to make a get request. - * @param channelGetRequester The interface for notifying when this request is complete - * and when a channel get completes. - * @param pvRequest A structure describing the desired set of fields from the remote PVRecord. - * This has the same form as a pvRequest to PVCopyFactory.create. - * @return ChannelGet instance. + * Initiate a request for a Get action. + * + * ChannelGetRequester::channelGetConnect() may be called before createChannelGet() returns, or at some time afterwards. + * + * Failure is indicated by a call to channelProcessConnect with !Error::isOk() + * + * @pre The Channel need not be CONNECTED + * + * @post The returned ChannelGet will hold a strong reference to the provided ChannelGetRequester. + * + * @post Returned shared_ptr will have unique()==true. + * + * @return A non-NULL ChannelGet unless channelGetConnect() called with an Error */ virtual ChannelGet::shared_pointer createChannelGet( - ChannelGetRequester::shared_pointer const & channelGetRequester, + ChannelGetRequester::shared_pointer const & requester, epics::pvData::PVStructure::shared_pointer const & pvRequest); /** - * Create a ChannelPut. - * ChannelPutRequester.channelPutReady is called after both client and server are ready for - * the client to make a put request. - * @param channelPutRequester The interface for notifying when this request is complete - * and when a channel get completes. - * @param pvRequest A structure describing the desired set of fields from the remote PVRecord. - * This has the same form as a pvRequest to PVCopyFactory.create. - * @return ChannelPut instance. + * Initiate a request for a Put action. + * + * ChannelPutRequester::channelPutConnect() may be called before createChannelPut() returns, or at some time afterwards. + * + * Failure is indicated by a call to channelProcessConnect with !Error::isOk() + * + * @pre The Channel need not be CONNECTED + * + * @post The returned ChannelPut will hold a strong reference to the provided ChannelPutRequester. + * + * @post Returned shared_ptr will have unique()==true. + * + * @return A non-NULL ChannelPut unless channelPutConnect() called with an Error */ virtual ChannelPut::shared_pointer createChannelPut( - ChannelPutRequester::shared_pointer const & channelPutRequester, + ChannelPutRequester::shared_pointer const & requester, epics::pvData::PVStructure::shared_pointer const & pvRequest); /** - * Create a ChannelPutGet. - * ChannelPutGetRequester.channelPutGetReady is called after both client and server are ready for - * the client to make a putGet request. - * @param channelPutGetRequester The interface for notifying when this request is complete - * and when a channel get completes. - * @param pvRequest A structure describing the desired set of fields from the remote PVRecord. - * This has the same form as a pvRequest to PVCopyFactory.create. - * @return ChannelPutGet instance. + * Initiate a request for a PutGet action. + * + * ChannelPutGetRequester::channelPutGetConnect() may be called before createChannelPutGet() returns, or at some time afterwards. + * + * Failure is indicated by a call to channelProcessConnect with !Error::isOk() + * + * @pre The Channel need not be CONNECTED + * + * @post The returned ChannelPutGet will hold a strong reference to the provided ChannelPutGetRequester. + * + * @post Returned shared_ptr will have unique()==true. + * + * @return A non-NULL ChannelPutGet unless channelPutGetConnect() called with an Error */ virtual ChannelPutGet::shared_pointer createChannelPutGet( - ChannelPutGetRequester::shared_pointer const & channelPutGetRequester, + ChannelPutGetRequester::shared_pointer const & requester, epics::pvData::PVStructure::shared_pointer const & pvRequest); /** - * Create a ChannelRPC (Remote Procedure Call). - * @param channelRPCRequester The Requester. - * @param pvRequest Request options. - * @return ChannelRPC instance. + * Initiate a request for a RPC action. + * + * ChannelRPCRequester::channelRPCConnect() may be called before createChannelRPC() returns, or at some time afterwards. + * + * Failure is indicated by a call to channelProcessConnect with !Error::isOk() + * + * @pre The Channel need not be CONNECTED + * + * @post The returned ChannelRPC will hold a strong reference to the provided ChannelRPCRequester. + * + * @post Returned shared_ptr will have unique()==true. + * + * @return A non-NULL ChannelRPC unless channelRPCConnect() called with an Error */ virtual ChannelRPC::shared_pointer createChannelRPC( - ChannelRPCRequester::shared_pointer const & channelRPCRequester, + ChannelRPCRequester::shared_pointer const & requester, epics::pvData::PVStructure::shared_pointer const & pvRequest); /** - * Create a Monitor. - * @param monitorRequester The Requester. - * @param pvRequest A structure describing the desired set of fields from the remote PVRecord. - * This has the same form as a pvRequest to PVCopyFactory.create. - * @return Monitor instance. + * Initiate a request for a Monitor action. + * + * MonitorRequester::channelMonitorConnect() may be called before createMonitor() returns, or at some time afterwards. + * + * Failure is indicated by a call to monitorConnect with !Error::isOk() + * + * @pre The Channel need not be CONNECTED + * + * @post The returned Monitor will hold a strong reference to the provided MonitorRequester. + * + * @post Returned shared_ptr will have unique()==true. + * + * @return A non-NULL Monitor unless monitorConnect() called with an Error */ virtual Monitor::shared_pointer createMonitor( - MonitorRequester::shared_pointer const & monitorRequester, + MonitorRequester::shared_pointer const & requester, epics::pvData::PVStructure::shared_pointer const & pvRequest); /** + * Initiate a request for a Array (get) action. + * + * ChannelArrayRequester::channelArrayConnect() may be called before createChannelArray() returns, or at some time afterwards. + * + * Failure is indicated by a call to channelArrayConnect with !Error::isOk() + * + * @pre The Channel need not be CONNECTED + * + * @post The returned ChannelArray will hold a strong reference to the provided MonitorRequester. + * + * @post Returned shared_ptr will have unique()==true. + * + * @return A non-NULL ChannelArray unless channelArrayConnect() called with an Error + * * Create a ChannelArray. * @param channelArrayRequester The ChannelArrayRequester * @param pvRequest Additional options (e.g. triggering). * @return ChannelArray instance. */ virtual ChannelArray::shared_pointer createChannelArray( - ChannelArrayRequester::shared_pointer const & channelArrayRequester, + ChannelArrayRequester::shared_pointer const & requester, epics::pvData::PVStructure::shared_pointer const & pvRequest); /** @@ -850,7 +930,9 @@ public: /** - * Listener for connect state changes. + * Event notifications associated with Channel life-cycle. + * + * See ChannelProvider::createChannel() */ class epicsShareClass ChannelRequester : public virtual Requester { public: @@ -860,14 +942,33 @@ public: virtual ~ChannelRequester() {} /** - * A channel has been created. This may be called multiple times if there are multiple providers. + * The request made with ChannelProvider::createChannel() is satisfied. + * + * Will be called at most once for each call to createChannel(). + * + * The Channel passed here must be the same as was returned by createChannel(), if it has returned. + * Note that this method may be called before createChanel() returns. + * + * Status::isOk() indicates that the Channel is valid. + * Calls to Channel methods can be made from this method, and later until Channel::destroy() is called. + * + * !Status::isOk() indicates that the Channel is not available. + * No calls to the Channel are permitted. + * channelStateChange() will never be called. + * + * Caller must hold no locks. + * * @param status Completion status. * @param channel The channel. */ virtual void channelCreated(const epics::pvData::Status& status, Channel::shared_pointer const & channel) = 0; /** - * A channel connection state change has occurred. + * Called occasionally after channelCreated() with Status::isOk() to give notification of + * connection state changes. + * + * Caller must hold no locks. + * * @param c The channel. * @param connectionState The new connection state. */ @@ -882,8 +983,9 @@ enum FlushStrategy { }; /** - * Interface implemented by code that can provide access to the record - * to which a channel connects. + * An instance of a Client or Server. + * + * Uniquely configurable (via ChannelProviderFactory::newInstance(Configuration*) */ class epicsShareClass ChannelProvider : public epics::pvData::Destroyable, private epics::pvData::NoDefaultMethods { public: @@ -911,45 +1013,61 @@ public: virtual std::string getProviderName() = 0; /** - * Find a channel. - * @param channelName The channel name. - * @param channelFindRequester The Requester. - * @return An interface for the find. + * Test to see if this provider has the named channel. + * + * May call ChannelFindRequester::channelFindResult() before returning, or at some time later. + * If an exception is thrown, then channelFindResult() will never be called. + * + * @param name The channel name. + * @param requester The Requester. + * @return An unique()==true handle for the pending response. May only return NULL if channelFindResult() called with an Error */ - virtual ChannelFind::shared_pointer channelFind(std::string const & channelName, - ChannelFindRequester::shared_pointer const & channelFindRequester) = 0; + virtual ChannelFind::shared_pointer channelFind(std::string const & name, + ChannelFindRequester::shared_pointer const & requester) = 0; /** - * Find channels. - * @param channelFindRequester The Requester. - * @return An interface for the find. + * Request a list of all valid channel names for this provider. + * + * May call ChannelListRequester::channelListResult() before returning, or at some time later. + * If an exception is thrown, then channelListResult() will never be called. + * + * @param requester The Requester. + * @return An unique()==true handle for the pending response. May only return NULL if channelFindResult() called with an Error */ - virtual ChannelFind::shared_pointer channelList(ChannelListRequester::shared_pointer const & channelListRequester) = 0; + virtual ChannelFind::shared_pointer channelList(ChannelListRequester::shared_pointer const & requester) = 0; /** - * Create a channel. - * @param channelName The name of the channel. - * @param channelRequester The Requester. - * @param priority channel priority, must be PRIORITY_MIN <= priority <= PRIORITY_MAX. - * @return Channel instance. If channel does not exist null is returned and channelRequester notified. + * See longer form */ - virtual Channel::shared_pointer createChannel(std::string const & channelName,ChannelRequester::shared_pointer const & channelRequester, + virtual Channel::shared_pointer createChannel(std::string const & name,ChannelRequester::shared_pointer const & requester, short priority = PRIORITY_DEFAULT); /** - * Create a channel. - * @param channelName The name of the channel. - * @param channelRequester The Requester. + * Request a Channel. + * + * May call ChannelListRequester::channelCreated() before returning, or at some time later. + * If an exception is thrown, then channelCreated() will never be called. + * + * The returned Channel will hold a strong reference to the provided ChannelRequester + * + * Returned shared_ptr includes only external references. + * eg. the first call to createChannel() with a particular name, priority, and address + * must return a unique()==true pointer. + * Subsequent calls with the same triple must either return the same reference or + * another with unique()==true. + * + * @param name The name of the channel. + * @param requester The Requester. * @param priority channel priority, must be PRIORITY_MIN <= priority <= PRIORITY_MAX. - * @param address address (or list of addresses) where to look for a channel. Implementation independed std::string. - * @return Channel instance. If channel does not exist null is returned and channelRequester notified. + * @param address Implementation dependent condition. eg. A network address to bypass the search phase. Pass an empty() string for default behavour. + * @return A non-NULL Channel unless channelCreated() called with an Error */ - virtual Channel::shared_pointer createChannel(std::string const & channelName,ChannelRequester::shared_pointer const & channelRequester, + virtual Channel::shared_pointer createChannel(std::string const & name,ChannelRequester::shared_pointer const & requester, short priority, std::string const & address) = 0; virtual void configure(epics::pvData::PVStructure::shared_pointer /*configuration*/) EPICS_DEPRECATED {}; - virtual void flush() {}; - virtual void poll() {}; + virtual void flush() EPICS_DEPRECATED {}; + virtual void poll() EPICS_DEPRECATED {}; }; diff --git a/src/factory/ChannelAccessFactory.cpp b/src/factory/ChannelAccessFactory.cpp index f1700fb..150b5ea 100644 --- a/src/factory/ChannelAccessFactory.cpp +++ b/src/factory/ChannelAccessFactory.cpp @@ -116,11 +116,11 @@ epicsShareFunc void unregisterAllChannelProviderFactory() Channel::shared_pointer -ChannelProvider::createChannel(std::string const & channelName, - ChannelRequester::shared_pointer const & channelRequester, +ChannelProvider::createChannel(std::string const & name, + ChannelRequester::shared_pointer const & requester, short priority) { - return createChannel(channelName, channelRequester, priority, ""); + return createChannel(name, requester, priority, ""); } } From e80ab0464e7c8393d98e57972e2c6919640c24ef Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 24 May 2017 15:02:25 -0400 Subject: [PATCH 013/189] less hacky-ness in operation disconnect/destroy notification avoid pointer/reference comparison. --- src/remote/pv/remote.h | 2 +- src/remoteClient/clientContextImpl.cpp | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/remote/pv/remote.h b/src/remote/pv/remote.h index 8ea7b4d..94dd1fa 100644 --- a/src/remote/pv/remote.h +++ b/src/remote/pv/remote.h @@ -566,7 +566,7 @@ public: * Report status to clients (e.g. disconnected). * @param status to report. */ - virtual void reportStatus(epics::pvData::Status const & status) = 0; + virtual void reportStatus(Channel::ConnectionState status) = 0; /** * Get request requester. diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 98087a0..5e5661a 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -342,12 +342,11 @@ public: // TODO notify? } - void reportStatus(const Status& status) { + void reportStatus(Channel::ConnectionState status) { // destroy, since channel (parent) was destroyed - // NOTE: by-ref compare, not nice - if (&status == &ChannelImpl::channelDestroyed) + if (status == Channel::DESTROYED) destroy(); - else if (&status == &ChannelImpl::channelDisconnected) + else if (status == Channel::DISCONNECTED) { m_subscribed.clear(); stopRequest(); @@ -2000,9 +1999,9 @@ public: cancel(); } - void reportStatus(const Status& status) { + void reportStatus(Channel::ConnectionState status) { // destroy, since channel (parent) was destroyed - if (&status == &ChannelImpl::channelDestroyed) + if (status == Channel::DESTROYED) destroy(); // TODO notify? } @@ -4105,7 +4104,7 @@ private: */ void disconnectPendingIO(bool destroy) { - Status& status = destroy ? channelDestroyed : channelDisconnected; + Channel::ConnectionState state = destroy ? Channel::DESTROYED : Channel::DISCONNECTED; Lock guard(m_responseRequestsMutex); @@ -4125,7 +4124,7 @@ private: { if((ptr = rrs[i].lock())) { - EXCEPTION_GUARD(ptr->reportStatus(status)); + EXCEPTION_GUARD(ptr->reportStatus(state)); } } } From d7a7b819000cf059d9e514c2d6ac400014cb542c Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 24 May 2017 16:38:04 -0400 Subject: [PATCH 014/189] move monitor.h from pvDataCPP --- src/client/pv/monitor.h | 128 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/client/pv/monitor.h diff --git a/src/client/pv/monitor.h b/src/client/pv/monitor.h new file mode 100644 index 0000000..54ac1d1 --- /dev/null +++ b/src/client/pv/monitor.h @@ -0,0 +1,128 @@ +/* monitor.h */ +/* + * Copyright information and license terms for this software can be + * found in the file LICENSE that is included with the distribution + */ +/** + * @author mrk + */ +#ifndef MONITOR_H +#define MONITOR_H + +#include +#include +#include +#include +#include +#include + +#include + +namespace epics { namespace pvData { + +class MonitorElement; +typedef std::tr1::shared_ptr MonitorElementPtr; +typedef std::vector MonitorElementPtrArray; + +class Monitor; +typedef std::tr1::shared_ptr MonitorPtr; + + +/** + * @brief An element for a monitorQueue. + * + * Class instance representing monitor element. + * @author mrk + */ +class epicsShareClass MonitorElement { + public: + POINTER_DEFINITIONS(MonitorElement); + MonitorElement(){} + MonitorElement(PVStructurePtr const & pvStructurePtr) + : pvStructurePtr(pvStructurePtr), + changedBitSet(BitSet::create(static_cast(pvStructurePtr->getNumberFields()))), + overrunBitSet(BitSet::create(static_cast(pvStructurePtr->getNumberFields()))) + {} + PVStructurePtr pvStructurePtr; + BitSet::shared_pointer changedBitSet; + BitSet::shared_pointer overrunBitSet; +}; + +/** + * @brief Monitor changes to fields of a pvStructure. + * + * This is used by pvAccess to implement monitors. + * @author mrk + */ +class epicsShareClass Monitor : public Destroyable{ + public: + POINTER_DEFINITIONS(Monitor); + virtual ~Monitor(){} + /** + * Start monitoring. + * @return completion status. + */ + virtual Status start() = 0; + /** + * Stop Monitoring. + * @return completion status. + */ + virtual Status stop() = 0; + /** + * If monitor has occurred return data. + * @return monitorElement for modified data. + * Must call get to determine if data is available. + */ + virtual MonitorElementPtr poll() = 0; + /** + * Release a MonitorElement that was returned by poll. + * A poll() must be called after the release() to check the presence of any modified data. + * @param monitorElement + */ + virtual void release(MonitorElementPtr const & monitorElement) = 0; + + struct Stats { + size_t nfilled; //!< # of elements ready to be poll()d + size_t noutstanding; //!< # of elements poll()d but not released()d + size_t nempty; //!< # of elements available for new remote data + }; + + virtual void getStats(Stats& s) const { + s.nfilled = s.noutstanding = s.nempty = 0; + } +}; + + +/** + * @brief Callback implemented by monitor clients. + * + * Requester for ChannelMonitor. + * @author mrk + */ +class epicsShareClass MonitorRequester : public virtual Requester { + public: + POINTER_DEFINITIONS(MonitorRequester); + virtual ~MonitorRequester(){} + /** + * The client and server have both completed the createMonitor request. + * @param status Completion status. + * @param monitor The monitor + * @param structure The structure defining the data. + */ + virtual void monitorConnect(Status const & status, + MonitorPtr const & monitor, StructureConstPtr const & structure) = 0; + /** + * A monitor event has occurred. + * The requester must call Monitor.poll to get data. + * @param monitor The monitor. + */ + virtual void monitorEvent(MonitorPtr const & monitor) = 0; + /** + * The data source is no longer available. + * @param monitor The monitor. + */ + virtual void unlisten(MonitorPtr const & monitor) = 0; +}; + +}} +#endif /* MONITOR_H */ From 7c2a093338b5167b2d315f1ddf1715d631d0ce46 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 25 May 2017 18:01:41 -0400 Subject: [PATCH 015/189] add ChannelBaseRequester::channelDisconnect() per-operation notification of channel disconnect/destroy. --- src/client/Makefile | 1 + src/client/pv/monitor.h | 61 +++++++-------------- src/client/pv/pvAccess.h | 75 ++++++++++++++++++++------ src/client/pvAccess.cpp | 2 +- src/remote/pv/remote.h | 2 +- src/remoteClient/clientContextImpl.cpp | 32 ++++++++--- 6 files changed, 109 insertions(+), 64 deletions(-) diff --git a/src/client/Makefile b/src/client/Makefile index a89c26d..358aae1 100644 --- a/src/client/Makefile +++ b/src/client/Makefile @@ -2,6 +2,7 @@ SRC_DIRS += $(PVACCESS_SRC)/client +INC += pv/monitor.h INC += pv/pvAccess.h LIBSRCS += pvAccess.cpp diff --git a/src/client/pv/monitor.h b/src/client/pv/monitor.h index 54ac1d1..39b16dd 100644 --- a/src/client/pv/monitor.h +++ b/src/client/pv/monitor.h @@ -18,7 +18,7 @@ #include -namespace epics { namespace pvData { +namespace epics { namespace pvAccess { class MonitorElement; typedef std::tr1::shared_ptr MonitorElementPtr; @@ -38,14 +38,14 @@ class epicsShareClass MonitorElement { public: POINTER_DEFINITIONS(MonitorElement); MonitorElement(){} - MonitorElement(PVStructurePtr const & pvStructurePtr) + MonitorElement(epics::pvData::PVStructurePtr const & pvStructurePtr) : pvStructurePtr(pvStructurePtr), - changedBitSet(BitSet::create(static_cast(pvStructurePtr->getNumberFields()))), - overrunBitSet(BitSet::create(static_cast(pvStructurePtr->getNumberFields()))) + changedBitSet(epics::pvData::BitSet::create(static_cast(pvStructurePtr->getNumberFields()))), + overrunBitSet(epics::pvData::BitSet::create(static_cast(pvStructurePtr->getNumberFields()))) {} - PVStructurePtr pvStructurePtr; - BitSet::shared_pointer changedBitSet; - BitSet::shared_pointer overrunBitSet; + epics::pvData::PVStructurePtr pvStructurePtr; + epics::pvData::BitSet::shared_pointer changedBitSet; + epics::pvData::BitSet::shared_pointer overrunBitSet; }; /** @@ -54,7 +54,7 @@ class epicsShareClass MonitorElement { * This is used by pvAccess to implement monitors. * @author mrk */ -class epicsShareClass Monitor : public Destroyable{ +class epicsShareClass Monitor : public epics::pvData::Destroyable{ public: POINTER_DEFINITIONS(Monitor); virtual ~Monitor(){} @@ -62,12 +62,12 @@ class epicsShareClass Monitor : public Destroyable{ * Start monitoring. * @return completion status. */ - virtual Status start() = 0; + virtual epics::pvData::Status start() = 0; /** * Stop Monitoring. * @return completion status. */ - virtual Status stop() = 0; + virtual epics::pvData::Status stop() = 0; /** * If monitor has occurred return data. * @return monitorElement for modified data. @@ -93,36 +93,15 @@ class epicsShareClass Monitor : public Destroyable{ }; -/** - * @brief Callback implemented by monitor clients. - * - * Requester for ChannelMonitor. - * @author mrk - */ -class epicsShareClass MonitorRequester : public virtual Requester { - public: - POINTER_DEFINITIONS(MonitorRequester); - virtual ~MonitorRequester(){} - /** - * The client and server have both completed the createMonitor request. - * @param status Completion status. - * @param monitor The monitor - * @param structure The structure defining the data. - */ - virtual void monitorConnect(Status const & status, - MonitorPtr const & monitor, StructureConstPtr const & structure) = 0; - /** - * A monitor event has occurred. - * The requester must call Monitor.poll to get data. - * @param monitor The monitor. - */ - virtual void monitorEvent(MonitorPtr const & monitor) = 0; - /** - * The data source is no longer available. - * @param monitor The monitor. - */ - virtual void unlisten(MonitorPtr const & monitor) = 0; -}; - }} + +namespace epics { namespace pvData { + +using epics::pvAccess::MonitorElement; +using epics::pvAccess::MonitorElementPtr; +using epics::pvAccess::MonitorElementPtrArray; +using epics::pvAccess::Monitor; +using epics::pvAccess::MonitorPtr; +}} + #endif /* MONITOR_H */ diff --git a/src/client/pv/pvAccess.h b/src/client/pv/pvAccess.h index 088ebc6..e208845 100644 --- a/src/client/pv/pvAccess.h +++ b/src/client/pv/pvAccess.h @@ -39,12 +39,6 @@ using epics::pvData::RequesterPtr; using epics::pvData::MessageType; using epics::pvData::getMessageTypeName; -using epics::pvData::MonitorElement; -using epics::pvData::MonitorElementPtr; -using epics::pvData::MonitorElementPtrArray; -using epics::pvData::Monitor; -using epics::pvData::MonitorRequester; - // TODO add write-only? // change names enum AccessRights { @@ -116,7 +110,6 @@ private: bool locked; }; - class Channel; class ChannelProvider; class ChannelArrayRequester; @@ -127,8 +120,23 @@ class ChannelPutRequester; class ChannelPutGetRequester; class ChannelRPCRequester; +struct epicsShareClass ChannelBaseRequester : virtual public epics::pvData::Requester +{ + POINTER_DEFINITIONS(ChannelBaseRequester); + + virtual ~ChannelBaseRequester() {} + + /** Notification when underlying Channel becomes DISCONNECTED or DESTORYED + * + * (re)connection is notified through a sub-class *Connect() method. + * + * @param destroy true for final disconnect (shutdown). + */ + virtual void channelDisconnect(bool destroy) {} +}; + /** - * Base interface for all channel requests. + * Base interface for all channel requests (aka. Operations). */ class epicsShareClass ChannelRequest : public epics::pvData::Destroyable, public Lockable, private epics::pvData::NoDefaultMethods { public: @@ -159,6 +167,37 @@ public: virtual void lastRequest() = 0; }; +/** + * @brief Callback implemented by monitor clients. + * + * Requester for ChannelMonitor. + * @author mrk + */ +class epicsShareClass MonitorRequester : public ChannelBaseRequester { + public: + POINTER_DEFINITIONS(MonitorRequester); + virtual ~MonitorRequester(){} + /** + * The client and server have both completed the createMonitor request. + * @param status Completion status. + * @param monitor The monitor + * @param structure The structure defining the data. + */ + virtual void monitorConnect(epics::pvData::Status const & status, + MonitorPtr const & monitor, epics::pvData::StructureConstPtr const & structure) = 0; + /** + * A monitor event has occurred. + * The requester must call Monitor.poll to get data. + * @param monitor The monitor. + */ + virtual void monitorEvent(MonitorPtr const & monitor) = 0; + /** + * The data source is no longer available. + * @param monitor The monitor. + */ + virtual void unlisten(MonitorPtr const & monitor) = 0; +}; + /** * Request to put and get Array Data. * The data is either taken from or put in the PVArray returned by ChannelArrayRequester.channelArrayConnect. @@ -204,7 +243,7 @@ public: /** * The Requester for a ChannelArray. */ -class epicsShareClass ChannelArrayRequester : virtual public Requester { +class epicsShareClass ChannelArrayRequester : public ChannelBaseRequester { public: POINTER_DEFINITIONS(ChannelArrayRequester); typedef ChannelArray operation_type; @@ -338,7 +377,7 @@ public: /** * Requester for channelGet. */ -class epicsShareClass ChannelGetRequester : virtual public Requester { +class epicsShareClass ChannelGetRequester : public ChannelBaseRequester { public: POINTER_DEFINITIONS(ChannelGetRequester); typedef ChannelGet operation_type; @@ -392,7 +431,7 @@ public: /** * Requester for channelProcess. */ -class epicsShareClass ChannelProcessRequester : virtual public Requester { +class epicsShareClass ChannelProcessRequester : public ChannelBaseRequester { public: POINTER_DEFINITIONS(ChannelProcessRequester); typedef ChannelProcess operation_type; @@ -450,7 +489,7 @@ public: /** * Requester for ChannelPut. */ -class epicsShareClass ChannelPutRequester : virtual public Requester { +class epicsShareClass ChannelPutRequester : public ChannelBaseRequester { public: POINTER_DEFINITIONS(ChannelPutRequester); typedef ChannelPut operation_type; @@ -530,7 +569,7 @@ public: /** * Requester for ChannelPutGet. */ -class epicsShareClass ChannelPutGetRequester : virtual public Requester +class epicsShareClass ChannelPutGetRequester : public ChannelBaseRequester { public: POINTER_DEFINITIONS(ChannelPutGetRequester); @@ -625,7 +664,7 @@ public: * * No locks may be held while calling these methods. */ -class epicsShareClass ChannelRPCRequester : virtual public Requester { +class epicsShareClass ChannelRPCRequester : public ChannelBaseRequester { public: POINTER_DEFINITIONS(ChannelRPCRequester); typedef ChannelRPC operation_type; @@ -665,7 +704,7 @@ public: /** * Completion notification for Channel::getField() */ -class epicsShareClass GetFieldRequester : virtual public Requester { +class epicsShareClass GetFieldRequester : public ChannelBaseRequester { public: POINTER_DEFINITIONS(GetFieldRequester); @@ -1249,6 +1288,12 @@ public: } } +// compatibility +namespace epics { namespace pvData { +using epics::pvAccess::MonitorRequester; +}} + + #endif /* PVACCESS_H */ /** @page Overview Documentation diff --git a/src/client/pvAccess.cpp b/src/client/pvAccess.cpp index c932f9f..b51e839 100644 --- a/src/client/pvAccess.cpp +++ b/src/client/pvAccess.cpp @@ -81,7 +81,7 @@ ChannelRPC::shared_pointer Channel::createChannelRPC( } pvd::Monitor::shared_pointer Channel::createMonitor( - epics::pvData::MonitorRequester::shared_pointer const & requester, + epics::pvAccess::MonitorRequester::shared_pointer const & requester, epics::pvData::PVStructure::shared_pointer const & pvRequest) { pvd::Monitor::shared_pointer ret; diff --git a/src/remote/pv/remote.h b/src/remote/pv/remote.h index 94dd1fa..1b66f2b 100644 --- a/src/remote/pv/remote.h +++ b/src/remote/pv/remote.h @@ -572,7 +572,7 @@ public: * Get request requester. * @return request requester. */ - virtual std::tr1::shared_ptr getRequester() = 0; + virtual std::tr1::shared_ptr getRequester() = 0; }; /** diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 5e5661a..1542067 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -145,7 +145,7 @@ protected: ChannelImpl::shared_pointer m_channel; - Requester::shared_pointer m_requester; + ChannelBaseRequester::shared_pointer m_requester; /* negative... */ static const int NULL_REQUEST = -1; @@ -170,7 +170,7 @@ protected: virtual ~BaseRequestImpl() {}; - BaseRequestImpl(ChannelImpl::shared_pointer const & channel, Requester::shared_pointer const & requester) : + BaseRequestImpl(ChannelImpl::shared_pointer const & channel, ChannelBaseRequester::shared_pointer const & requester) : m_channel(channel), m_requester(requester), m_ioid(INVALID_IOID), @@ -213,7 +213,7 @@ protected: public: // used to send message to this request - Requester::shared_pointer getRequester() { + ChannelBaseRequester::shared_pointer getRequester() { return m_requester; } @@ -1969,7 +1969,7 @@ public: PVACCESS_REFCOUNT_MONITOR_DESTRUCT(channelGetField); } - Requester::shared_pointer getRequester() { + ChannelBaseRequester::shared_pointer getRequester() { return m_callback; } @@ -4043,10 +4043,11 @@ private: void reportChannelStateChange() { - Channel::shared_pointer thisPointer = shared_from_this(); + Channel::shared_pointer self(shared_from_this()); while (true) { + std::vector ops; ConnectionState connectionState; { Lock guard(m_channelMutex); @@ -4054,9 +4055,28 @@ private: break; connectionState = channelStateChangeQueue.front(); channelStateChangeQueue.pop(); + + if(connectionState==Channel::DISCONNECTED || connectionState==Channel::DESTROYED) { + Lock guard(m_responseRequestsMutex); + ops.reserve(m_responseRequests.size()); + for(IOIDResponseRequestMap::const_iterator it = m_responseRequests.begin(), + end = m_responseRequests.end(); + it!=end; ++it) + { + ops.push_back(it->second); + } + } } - EXCEPTION_GUARD(m_requester->channelStateChange(thisPointer, connectionState)); + EXCEPTION_GUARD(m_requester->channelStateChange(self, connectionState)); + + if(connectionState==Channel::DISCONNECTED || connectionState==Channel::DESTROYED) { + for(size_t i=0, N=ops.size(); igetRequester()->channelDisconnect(connectionState==Channel::DESTROYED);) + } + } } From 7c85e6073b01f3ea0a849f0f89c5fbbf6c4e63c1 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 30 May 2017 12:07:23 +0200 Subject: [PATCH 016/189] move ServerContextImpl into private header --- src/pipelineService/pv/pipelineServer.h | 2 +- src/rpcService/pv/rpcServer.h | 2 +- src/server/beaconEmitter.cpp | 2 +- src/server/pv/baseChannelRequester.h | 2 +- src/server/pv/serverContext.h | 347 ----------------------- src/server/pv/serverContextImpl.h | 358 ++++++++++++++++++++++++ testApp/Makefile | 2 + testApp/remote/testServer.cpp | 2 +- testApp/remote/testServerContext.cpp | 2 +- 9 files changed, 366 insertions(+), 353 deletions(-) create mode 100644 src/server/pv/serverContextImpl.h diff --git a/src/pipelineService/pv/pipelineServer.h b/src/pipelineService/pv/pipelineServer.h index 968e9f0..8b00033 100644 --- a/src/pipelineService/pv/pipelineServer.h +++ b/src/pipelineService/pv/pipelineServer.h @@ -21,7 +21,7 @@ #include #include -#include +#include #include diff --git a/src/rpcService/pv/rpcServer.h b/src/rpcService/pv/rpcServer.h index b6ead62..4182011 100644 --- a/src/rpcService/pv/rpcServer.h +++ b/src/rpcService/pv/rpcServer.h @@ -21,7 +21,7 @@ #include #include -#include +#include #include diff --git a/src/server/beaconEmitter.cpp b/src/server/beaconEmitter.cpp index dcc79a8..b1b0ea4 100644 --- a/src/server/beaconEmitter.cpp +++ b/src/server/beaconEmitter.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include using namespace std; using namespace epics::pvData; diff --git a/src/server/pv/baseChannelRequester.h b/src/server/pv/baseChannelRequester.h index e38e1f4..5a15d69 100644 --- a/src/server/pv/baseChannelRequester.h +++ b/src/server/pv/baseChannelRequester.h @@ -20,7 +20,7 @@ # undef baseChannelRequesterEpicsExportSharedSymbols #endif -#include +#include #include namespace epics { diff --git a/src/server/pv/serverContext.h b/src/server/pv/serverContext.h index fde37e1..66e23b6 100644 --- a/src/server/pv/serverContext.h +++ b/src/server/pv/serverContext.h @@ -106,353 +106,6 @@ public: }; - -class epicsShareClass ServerContextImpl : - public ServerContext, - public Context, - public std::tr1::enable_shared_from_this -{ -public: - typedef std::tr1::shared_ptr shared_pointer; - typedef std::tr1::shared_ptr const_shared_pointer; -private: - ServerContextImpl(); -public: - static shared_pointer create(); - static shared_pointer create(const Configuration::shared_pointer& conf); - - virtual ~ServerContextImpl(); - - //**************** derived from ServerContext ****************// - const GUID& getGUID(); - const Version& getVersion(); - void initialize(ChannelProviderRegistry::shared_pointer const & channelProviderRegistry); - void run(epics::pvData::int32 seconds); - void shutdown(); - void destroy(); - void printInfo(); - void printInfo(std::ostream& str); - void dispose(); - void setBeaconServerStatusProvider(BeaconServerStatusProvider::shared_pointer const & beaconServerStatusProvider); - //**************** derived from Context ****************// - epics::pvData::Timer::shared_pointer getTimer(); - Channel::shared_pointer getChannel(pvAccessID id); - Transport::shared_pointer getSearchTransport(); - Configuration::shared_pointer getConfiguration(); - TransportRegistry::shared_pointer getTransportRegistry(); - std::map >& getSecurityPlugins(); - - virtual void newServerDetected(); - - - epicsTimeStamp& getStartTime(); - - - /** - * Version. - */ - static const Version VERSION; - - - /** - * Server state enum. - */ - enum State { - /** - * State value of non-initialized context. - */ - NOT_INITIALIZED, - - /** - * State value of initialized context. - */ - INITIALIZED, - - /** - * State value of running context. - */ - RUNNING, - - /** - * State value of shutdown (once running) context. - */ - SHUTDOWN, - - /** - * State value of destroyed context. - */ - DESTROYED - }; - /** - * Names of the enum State - */ - static const char* StateNames[]; - - /** - * Get initialization status. - * @return initialization status. - */ - bool isInitialized(); - - /** - * Get destruction status. - * @return destruction status. - */ - bool isDestroyed(); - - /** - * Get beacon address list. - * @return beacon address list. - */ - std::string getBeaconAddressList(); - - /** - * Get beacon address list auto flag. - * @return beacon address list auto flag. - */ - bool isAutoBeaconAddressList(); - - /** - * Get beacon period (in seconds). - * @return beacon period (in seconds). - */ - float getBeaconPeriod(); - - /** - * Get receiver buffer (payload) size. - * @return max payload size. - */ - epics::pvData::int32 getReceiveBufferSize(); - - /** - * Get server port. - * @return server port. - */ - epics::pvData::int32 getServerPort(); - - /** - * Get broadcast port. - * @return broadcast port. - */ - epics::pvData::int32 getBroadcastPort(); - - /** - * Get ignore search address list. - * @return ignore search address list. - */ - std::string getIgnoreAddressList(); - - /** - * Get registered beacon server status provider. - * @return registered beacon server status provider. - */ - BeaconServerStatusProvider::shared_pointer getBeaconServerStatusProvider(); - - /** - * Get server newtwork (IP) address. - * @return server network (IP) address, NULL if not bounded. - */ - osiSockAddr* getServerInetAddress(); - - /** - * Broadcast (UDP send) transport. - * @return broadcast transport. - */ - BlockingUDPTransport::shared_pointer getBroadcastTransport(); - - /** - * Get channel provider registry implementation used by this instance. - * @return channel provider registry used by this instance. - */ - ChannelProviderRegistry::shared_pointer getChannelProviderRegistry(); - - /** - * Get channel provider name. - * @return channel provider name. - */ - std::string getChannelProviderName(); - - /** - * Set channel provider name. - * This method can only be called before initialize. - */ - void setChannelProviderName(std::string providerName); - - /** - * Get channel providers. - * @return channel providers. - */ - std::vector& getChannelProviders(); - - /** - * Return true if channel provider name is provided by configuration (e.g. system env. var.). - * @return true if channel provider name is provided by configuration (e.g. system env. var.) - */ - bool isChannelProviderNamePreconfigured(); - -private: - - /** - * Server GUID. - */ - GUID _guid; - - /** - * Initialization status. - */ - State _state; - - /** - * A space-separated list of broadcast address which to send beacons. - * Each address must be of the form: ip.number:port or host.name:port - */ - std::string _beaconAddressList; - - /** - * List of used NIF. - */ - IfaceNodeVector _ifaceList; - - osiSockAddr _ifaceAddr; - - /** - * A space-separated list of address from which to ignore name resolution requests. - * Each address must be of the form: ip.number:port or host.name:port - */ - std::string _ignoreAddressList; - - /** - * Define whether or not the network interfaces should be discovered at runtime. - */ - bool _autoBeaconAddressList; - - /** - * Period in second between two beacon signals. - */ - float _beaconPeriod; - - /** - * Broadcast port number to listen to. - */ - epics::pvData::int32 _broadcastPort; - - /** - * Port number for the server to listen to. - */ - epics::pvData::int32 _serverPort; - - /** - * Length in bytes of the maximum buffer (payload) size that may pass through PVA. - */ - epics::pvData::int32 _receiveBufferSize; - - /** - * Timer. - */ - epics::pvData::Timer::shared_pointer _timer; - - /** - * UDP transports needed to receive channel searches. - */ - BlockingUDPTransportVector _udpTransports; - - /** - * UDP socket used to sending. - */ - BlockingUDPTransport::shared_pointer _broadcastTransport; - - /** - * Beacon emitter. - */ - BeaconEmitter::shared_pointer _beaconEmitter; - - /** - * PVAS acceptor (accepts PVA virtual circuit). - */ - BlockingTCPAcceptor::shared_pointer _acceptor; - - /** - * PVA transport (virtual circuit) registry. - * This registry contains all active transports - connections to PVA servers. - */ - TransportRegistry::shared_pointer _transportRegistry; - - /** - * Response handler. - */ - ResponseHandler::shared_pointer _responseHandler; - - /** - * Channel access. - */ - ChannelProviderRegistry::shared_pointer _channelProviderRegistry; - - /** - * Channel provider name. - */ - std::string _channelProviderNames; - - /** - * Channel provider. - */ - std::vector _channelProviders; - - /** - * Run mutex. - */ - epics::pvData::Mutex _mutex; - - /** - * Run event. - */ - epics::pvData::Event _runEvent; - - /** - * Beacon server status provider interface (optional). - */ - BeaconServerStatusProvider::shared_pointer _beaconServerStatusProvider; - - /** - * Generate GUID. - */ - void generateGUID(); - - /** - * Initialize logger. - */ - void initializeLogger(); - - /** - * Load configuration. - */ - void loadConfiguration(); - - /** - * Internal initialization. - */ - void internalInitialize(); - - /** - * Initialize broadcast DP transport (broadcast socket and repeater connection). - */ - void initializeBroadcastTransport(); - - /** - * Internal destroy. - */ - void internalDestroy(); - - /** - * Destroy all transports. - */ - void destroyAllTransports(); - - Configuration::shared_pointer configuration; - - epicsTimeStamp _startTime; - -}; - epicsShareFunc ServerContext::shared_pointer startPVAServer( std::string const & providerNames = PVACCESS_ALL_PROVIDERS, int timeToRun = 0, diff --git a/src/server/pv/serverContextImpl.h b/src/server/pv/serverContextImpl.h new file mode 100644 index 0000000..17ad4d2 --- /dev/null +++ b/src/server/pv/serverContextImpl.h @@ -0,0 +1,358 @@ +#ifndef SERVERCONTEXTIMPL_H +#define SERVERCONTEXTIMPL_H + +#include "serverContext.h" + +namespace epics { +namespace pvAccess { + +class epicsShareClass ServerContextImpl : + public ServerContext, + public Context, + public std::tr1::enable_shared_from_this +{ +public: + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; +private: + ServerContextImpl(); +public: + static shared_pointer create(); + static shared_pointer create(const Configuration::shared_pointer& conf); + + virtual ~ServerContextImpl(); + + //**************** derived from ServerContext ****************// + const GUID& getGUID(); + const Version& getVersion(); + void initialize(ChannelProviderRegistry::shared_pointer const & channelProviderRegistry); + void run(epics::pvData::int32 seconds); + void shutdown(); + void destroy(); + void printInfo(); + void printInfo(std::ostream& str); + void dispose(); + void setBeaconServerStatusProvider(BeaconServerStatusProvider::shared_pointer const & beaconServerStatusProvider); + //**************** derived from Context ****************// + epics::pvData::Timer::shared_pointer getTimer(); + Channel::shared_pointer getChannel(pvAccessID id); + Transport::shared_pointer getSearchTransport(); + Configuration::shared_pointer getConfiguration(); + TransportRegistry::shared_pointer getTransportRegistry(); + std::map >& getSecurityPlugins(); + + virtual void newServerDetected(); + + + epicsTimeStamp& getStartTime(); + + + /** + * Version. + */ + static const Version VERSION; + + + /** + * Server state enum. + */ + enum State { + /** + * State value of non-initialized context. + */ + NOT_INITIALIZED, + + /** + * State value of initialized context. + */ + INITIALIZED, + + /** + * State value of running context. + */ + RUNNING, + + /** + * State value of shutdown (once running) context. + */ + SHUTDOWN, + + /** + * State value of destroyed context. + */ + DESTROYED + }; + /** + * Names of the enum State + */ + static const char* StateNames[]; + + /** + * Get initialization status. + * @return initialization status. + */ + bool isInitialized(); + + /** + * Get destruction status. + * @return destruction status. + */ + bool isDestroyed(); + + /** + * Get beacon address list. + * @return beacon address list. + */ + std::string getBeaconAddressList(); + + /** + * Get beacon address list auto flag. + * @return beacon address list auto flag. + */ + bool isAutoBeaconAddressList(); + + /** + * Get beacon period (in seconds). + * @return beacon period (in seconds). + */ + float getBeaconPeriod(); + + /** + * Get receiver buffer (payload) size. + * @return max payload size. + */ + epics::pvData::int32 getReceiveBufferSize(); + + /** + * Get server port. + * @return server port. + */ + epics::pvData::int32 getServerPort(); + + /** + * Get broadcast port. + * @return broadcast port. + */ + epics::pvData::int32 getBroadcastPort(); + + /** + * Get ignore search address list. + * @return ignore search address list. + */ + std::string getIgnoreAddressList(); + + /** + * Get registered beacon server status provider. + * @return registered beacon server status provider. + */ + BeaconServerStatusProvider::shared_pointer getBeaconServerStatusProvider(); + + /** + * Get server newtwork (IP) address. + * @return server network (IP) address, NULL if not bounded. + */ + osiSockAddr* getServerInetAddress(); + + /** + * Broadcast (UDP send) transport. + * @return broadcast transport. + */ + BlockingUDPTransport::shared_pointer getBroadcastTransport(); + + /** + * Get channel provider registry implementation used by this instance. + * @return channel provider registry used by this instance. + */ + ChannelProviderRegistry::shared_pointer getChannelProviderRegistry(); + + /** + * Get channel provider name. + * @return channel provider name. + */ + std::string getChannelProviderName(); + + /** + * Set channel provider name. + * This method can only be called before initialize. + */ + void setChannelProviderName(std::string providerName); + + /** + * Get channel providers. + * @return channel providers. + */ + std::vector& getChannelProviders(); + + /** + * Return true if channel provider name is provided by configuration (e.g. system env. var.). + * @return true if channel provider name is provided by configuration (e.g. system env. var.) + */ + bool isChannelProviderNamePreconfigured(); + +private: + + /** + * Server GUID. + */ + GUID _guid; + + /** + * Initialization status. + */ + State _state; + + /** + * A space-separated list of broadcast address which to send beacons. + * Each address must be of the form: ip.number:port or host.name:port + */ + std::string _beaconAddressList; + + /** + * List of used NIF. + */ + IfaceNodeVector _ifaceList; + + osiSockAddr _ifaceAddr; + + /** + * A space-separated list of address from which to ignore name resolution requests. + * Each address must be of the form: ip.number:port or host.name:port + */ + std::string _ignoreAddressList; + + /** + * Define whether or not the network interfaces should be discovered at runtime. + */ + bool _autoBeaconAddressList; + + /** + * Period in second between two beacon signals. + */ + float _beaconPeriod; + + /** + * Broadcast port number to listen to. + */ + epics::pvData::int32 _broadcastPort; + + /** + * Port number for the server to listen to. + */ + epics::pvData::int32 _serverPort; + + /** + * Length in bytes of the maximum buffer (payload) size that may pass through PVA. + */ + epics::pvData::int32 _receiveBufferSize; + + /** + * Timer. + */ + epics::pvData::Timer::shared_pointer _timer; + + /** + * UDP transports needed to receive channel searches. + */ + BlockingUDPTransportVector _udpTransports; + + /** + * UDP socket used to sending. + */ + BlockingUDPTransport::shared_pointer _broadcastTransport; + + /** + * Beacon emitter. + */ + BeaconEmitter::shared_pointer _beaconEmitter; + + /** + * PVAS acceptor (accepts PVA virtual circuit). + */ + BlockingTCPAcceptor::shared_pointer _acceptor; + + /** + * PVA transport (virtual circuit) registry. + * This registry contains all active transports - connections to PVA servers. + */ + TransportRegistry::shared_pointer _transportRegistry; + + /** + * Response handler. + */ + ResponseHandler::shared_pointer _responseHandler; + + /** + * Channel access. + */ + ChannelProviderRegistry::shared_pointer _channelProviderRegistry; + + /** + * Channel provider name. + */ + std::string _channelProviderNames; + + /** + * Channel provider. + */ + std::vector _channelProviders; + + /** + * Run mutex. + */ + epics::pvData::Mutex _mutex; + + /** + * Run event. + */ + epics::pvData::Event _runEvent; + + /** + * Beacon server status provider interface (optional). + */ + BeaconServerStatusProvider::shared_pointer _beaconServerStatusProvider; + + /** + * Generate GUID. + */ + void generateGUID(); + + /** + * Initialize logger. + */ + void initializeLogger(); + + /** + * Load configuration. + */ + void loadConfiguration(); + + /** + * Internal initialization. + */ + void internalInitialize(); + + /** + * Initialize broadcast DP transport (broadcast socket and repeater connection). + */ + void initializeBroadcastTransport(); + + /** + * Internal destroy. + */ + void internalDestroy(); + + /** + * Destroy all transports. + */ + void destroyAllTransports(); + + Configuration::shared_pointer configuration; + + epicsTimeStamp _startTime; + +}; + +} +} + +#endif // SERVERCONTEXTIMPL_H diff --git a/testApp/Makefile b/testApp/Makefile index 8b85465..9f9cd10 100644 --- a/testApp/Makefile +++ b/testApp/Makefile @@ -3,6 +3,8 @@ TOP = .. include $(TOP)/configure/CONFIG +USR_CPPFLAGS += -I$(TOP)/src/server/pv + PVACCESS_TEST = $(TOP)/testApp PROD_LIBS += pvAccess pvData $(MBLIB) Com diff --git a/testApp/remote/testServer.cpp b/testApp/remote/testServer.cpp index 7c7dce1..c191bda 100644 --- a/testApp/remote/testServer.cpp +++ b/testApp/remote/testServer.cpp @@ -9,7 +9,7 @@ // disable buggy boost enable_shared_from_this assert code #define BOOST_DISABLE_ASSERTS -#include +#include #include #include #include diff --git a/testApp/remote/testServerContext.cpp b/testApp/remote/testServerContext.cpp index 697dee3..24332ed 100644 --- a/testApp/remote/testServerContext.cpp +++ b/testApp/remote/testServerContext.cpp @@ -2,7 +2,7 @@ * testServerContext.cpp */ -#include +#include #include using namespace epics::pvAccess; From 277e5c33fbad540bd28e40d1ceda2c1a3677236a Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 30 May 2017 17:12:31 +0200 Subject: [PATCH 017/189] privatize some API details hide a number of APIs which should not be public APIs. --- pvtoolsSrc/Makefile | 2 ++ src/pva/Makefile | 1 + src/pva/pv/pvaDefs.h | 22 ++++++++++++ src/remote/Makefile | 8 ----- src/remote/pv/beaconHandler.h | 1 + src/remote/pv/channelSearchManager.h | 2 +- src/remote/pv/remote.h | 10 +----- src/remote/pv/security.h | 23 ++----------- src/remote/pv/securityImpl.h | 34 +++++++++++++++++++ .../pv/simpleChannelSearchManagerImpl.h | 1 + src/remote/security.cpp | 2 +- src/remoteClient/Makefile | 2 -- src/remoteClient/clientContextImpl.cpp | 2 +- src/rpcService/pv/rpcServer.h | 6 ++-- src/rpcService/rpcServer.cpp | 3 +- src/server/Makefile | 3 -- src/server/pv/serverContext.h | 8 ++--- src/server/pv/serverContextImpl.h | 4 +++ src/server/responseHandlers.cpp | 2 +- src/server/serverContext.cpp | 3 +- testApp/Makefile | 4 ++- 21 files changed, 86 insertions(+), 57 deletions(-) create mode 100644 src/pva/pv/pvaDefs.h create mode 100644 src/remote/pv/securityImpl.h diff --git a/pvtoolsSrc/Makefile b/pvtoolsSrc/Makefile index 90e9248..c841412 100644 --- a/pvtoolsSrc/Makefile +++ b/pvtoolsSrc/Makefile @@ -2,6 +2,8 @@ TOP=.. include $(TOP)/configure/CONFIG +USR_CPPFLAGS += -I$(TOP)/src/remote + PROD_HOST += pvget pvget_SRCS += pvget.cpp pvget_LIBS += pvAccess pvData $(MBLIB) ca Com diff --git a/src/pva/Makefile b/src/pva/Makefile index a1b75dc..1bf2665 100644 --- a/src/pva/Makefile +++ b/src/pva/Makefile @@ -3,6 +3,7 @@ SRC_DIRS += $(PVACCESS_SRC)/pva INC += pv/pvaConstants.h +INC += pv/pvaDefs.h INC += pv/pvaVersion.h INC += pv/pvaVersionNum.h INC += pv/clientFactory.h diff --git a/src/pva/pv/pvaDefs.h b/src/pva/pv/pvaDefs.h new file mode 100644 index 0000000..6497d47 --- /dev/null +++ b/src/pva/pv/pvaDefs.h @@ -0,0 +1,22 @@ +#ifndef PVADEFS_H +#define PVADEFS_H + +#include +#include +#include + +namespace epics { +namespace pvAccess { + +/** + * Globally unique ID. + */ +typedef struct { + char value[12]; +} GUID; + +typedef epicsInt32 pvAccessID; + +}} + +#endif // PVADEFS_H diff --git a/src/remote/Makefile b/src/remote/Makefile index 6b7a417..943cf9d 100644 --- a/src/remote/Makefile +++ b/src/remote/Makefile @@ -2,16 +2,8 @@ SRC_DIRS += $(PVACCESS_SRC)/remote -INC += pv/remote.h INC += pv/security.h -INC += pv/blockingUDP.h -INC += pv/beaconHandler.h -INC += pv/blockingTCP.h -INC += pv/channelSearchManager.h -INC += pv/simpleChannelSearchManagerImpl.h -INC += pv/transportRegistry.h INC += pv/serializationHelper.h -INC += pv/codec.h LIBSRCS += blockingUDPTransport.cpp LIBSRCS += blockingUDPConnector.cpp diff --git a/src/remote/pv/beaconHandler.h b/src/remote/pv/beaconHandler.h index e437e17..289bc6a 100644 --- a/src/remote/pv/beaconHandler.h +++ b/src/remote/pv/beaconHandler.h @@ -22,6 +22,7 @@ # undef beaconHandlerEpicsExportSharedSymbols #endif +#include #include #include diff --git a/src/remote/pv/channelSearchManager.h b/src/remote/pv/channelSearchManager.h index 18bb5de..40a0991 100644 --- a/src/remote/pv/channelSearchManager.h +++ b/src/remote/pv/channelSearchManager.h @@ -19,7 +19,7 @@ # undef channelSearchManagerEpicsExportSharedSymbols #endif -#include +#include namespace epics { namespace pvAccess { diff --git a/src/remote/pv/remote.h b/src/remote/pv/remote.h index 1b66f2b..1e5d2ed 100644 --- a/src/remote/pv/remote.h +++ b/src/remote/pv/remote.h @@ -33,6 +33,7 @@ #include #include #include +#include /// TODO only here because of the Lockable #include @@ -48,13 +49,6 @@ namespace pvAccess { class TransportRegistry; -/** - * Globally unique ID. - */ -typedef struct { - char value[12]; -} GUID; - enum QoS { /** * Default behavior. @@ -94,8 +88,6 @@ enum QoS { QOS_GET_PUT = 0x80 }; -typedef epics::pvData::int32 pvAccessID; - enum ApplicationCommands { CMD_BEACON = 0, CMD_CONNECTION_VALIDATION = 1, diff --git a/src/remote/pv/security.h b/src/remote/pv/security.h index 97aced7..75ccbb6 100644 --- a/src/remote/pv/security.h +++ b/src/remote/pv/security.h @@ -25,7 +25,8 @@ # undef securityEpicsExportSharedSymbols #endif -#include +#include +#include #include #include @@ -412,26 +413,6 @@ public: } }; -class AuthNZHandler : - public AbstractResponseHandler, - private epics::pvData::NoDefaultMethods -{ -public: - AuthNZHandler(Context* context) : - AbstractResponseHandler(context, "authNZ message") - { - } - - virtual ~AuthNZHandler() {} - - virtual void handleResponse(osiSockAddr* responseFrom, - Transport::shared_pointer const & transport, - epics::pvData::int8 version, - epics::pvData::int8 command, - size_t payloadSize, - epics::pvData::ByteBuffer* payloadBuffer); -}; - class epicsShareClass SecurityPluginRegistry : private epics::pvData::NoDefaultMethods { diff --git a/src/remote/pv/securityImpl.h b/src/remote/pv/securityImpl.h new file mode 100644 index 0000000..e90b3f4 --- /dev/null +++ b/src/remote/pv/securityImpl.h @@ -0,0 +1,34 @@ +#ifndef SECURITYIMPL_H +#define SECURITYIMPL_H + +#include + +#include "security.h" + +namespace epics { +namespace pvAccess { + + +class AuthNZHandler : + public AbstractResponseHandler, + private epics::pvData::NoDefaultMethods +{ +public: + AuthNZHandler(Context* context) : + AbstractResponseHandler(context, "authNZ message") + { + } + + virtual ~AuthNZHandler() {} + + virtual void handleResponse(osiSockAddr* responseFrom, + Transport::shared_pointer const & transport, + epics::pvData::int8 version, + epics::pvData::int8 command, + size_t payloadSize, + epics::pvData::ByteBuffer* payloadBuffer); +}; + +}} + +#endif // SECURITYIMPL_H diff --git a/src/remote/pv/simpleChannelSearchManagerImpl.h b/src/remote/pv/simpleChannelSearchManagerImpl.h index 0008dcc..09dd762 100644 --- a/src/remote/pv/simpleChannelSearchManagerImpl.h +++ b/src/remote/pv/simpleChannelSearchManagerImpl.h @@ -22,6 +22,7 @@ #endif #include +#include namespace epics { namespace pvAccess { diff --git a/src/remote/security.cpp b/src/remote/security.cpp index 92a680c..9c5f2c2 100644 --- a/src/remote/security.cpp +++ b/src/remote/security.cpp @@ -7,7 +7,7 @@ #include #define epicsExportSharedSymbols -#include +#include using namespace epics::pvData; using namespace epics::pvAccess; diff --git a/src/remoteClient/Makefile b/src/remoteClient/Makefile index 494f695..25ef118 100644 --- a/src/remoteClient/Makefile +++ b/src/remoteClient/Makefile @@ -2,6 +2,4 @@ SRC_DIRS += $(PVACCESS_SRC)/remoteClient -INC += pv/clientContextImpl.h - LIBSRCS += clientContextImpl.cpp diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 1542067..b5a2033 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include diff --git a/src/rpcService/pv/rpcServer.h b/src/rpcService/pv/rpcServer.h index 4182011..454bce0 100644 --- a/src/rpcService/pv/rpcServer.h +++ b/src/rpcService/pv/rpcServer.h @@ -21,19 +21,21 @@ #include #include -#include +#include #include namespace epics { namespace pvAccess { +class ServerContext; + class epicsShareClass RPCServer : public std::tr1::enable_shared_from_this { private: - ServerContextImpl::shared_pointer m_serverContext; + std::tr1::shared_ptr m_serverContext; ChannelProviderFactory::shared_pointer m_channelProviderFactory; ChannelProvider::shared_pointer m_channelProviderImpl; diff --git a/src/rpcService/rpcServer.cpp b/src/rpcService/rpcServer.cpp index f2e7f3c..e87ce35 100644 --- a/src/rpcService/rpcServer.cpp +++ b/src/rpcService/rpcServer.cpp @@ -10,6 +10,7 @@ #define epicsExportSharedSymbols #include +#include #include using namespace epics::pvData; @@ -525,7 +526,7 @@ RPCServer::RPCServer() m_channelProviderImpl = m_channelProviderFactory->sharedInstance(); m_serverContext = ServerContextImpl::create(); - m_serverContext->setChannelProviderName(m_channelProviderImpl->getProviderName()); + static_cast(m_serverContext.get())->setChannelProviderName(m_channelProviderImpl->getProviderName()); m_serverContext->initialize(getChannelProviderRegistry()); } diff --git a/src/server/Makefile b/src/server/Makefile index 3334bae..2e841be 100644 --- a/src/server/Makefile +++ b/src/server/Makefile @@ -3,10 +3,7 @@ SRC_DIRS += $(PVACCESS_SRC)/server INC += pv/serverContext.h -INC += pv/responseHandlers.h INC += pv/serverChannelImpl.h -INC += pv/baseChannelRequester.h -INC += pv/beaconEmitter.h INC += pv/beaconServerStatusProvider.h LIBSRCS += responseHandlers.cpp diff --git a/src/server/pv/serverContext.h b/src/server/pv/serverContext.h index 66e23b6..42147a9 100644 --- a/src/server/pv/serverContext.h +++ b/src/server/pv/serverContext.h @@ -7,15 +7,13 @@ #ifndef SERVERCONTEXT_H_ #define SERVERCONTEXT_H_ -#include +#include + +#include #include #include #include #include -#include -#include -#include -#include #include diff --git a/src/server/pv/serverContextImpl.h b/src/server/pv/serverContextImpl.h index 17ad4d2..a5df9ba 100644 --- a/src/server/pv/serverContextImpl.h +++ b/src/server/pv/serverContextImpl.h @@ -1,6 +1,10 @@ #ifndef SERVERCONTEXTIMPL_H #define SERVERCONTEXTIMPL_H +#include +#include +#include + #include "serverContext.h" namespace epics { diff --git a/src/server/responseHandlers.cpp b/src/server/responseHandlers.cpp index 41cee50..04369cf 100644 --- a/src/server/responseHandlers.cpp +++ b/src/server/responseHandlers.cpp @@ -39,7 +39,7 @@ #include #include #include -#include +#include using std::string; using std::ostringstream; diff --git a/src/server/serverContext.cpp b/src/server/serverContext.cpp index 21068d8..d66b1c5 100644 --- a/src/server/serverContext.cpp +++ b/src/server/serverContext.cpp @@ -653,7 +653,7 @@ ServerContext::shared_pointer startPVAServer(std::string const & providerNames, if (runInSeparateThread) { - // delete left to the thread + // delete left to the thread (which doesn't) auto_ptr param(new ThreadRunnerParam()); param->ctx = ctx; param->timeToRun = timeToRun; @@ -665,6 +665,7 @@ ServerContext::shared_pointer startPVAServer(std::string const & providerNames, threadRunner, param.get()); param.release(); + // leak... } else { diff --git a/testApp/Makefile b/testApp/Makefile index 9f9cd10..22139aa 100644 --- a/testApp/Makefile +++ b/testApp/Makefile @@ -3,7 +3,9 @@ TOP = .. include $(TOP)/configure/CONFIG -USR_CPPFLAGS += -I$(TOP)/src/server/pv +USR_CPPFLAGS += -I$(TOP)/src/server +USR_CPPFLAGS += -I$(TOP)/src/remote +USR_CPPFLAGS += -I$(TOP)/src/remoteClient PVACCESS_TEST = $(TOP)/testApp From dd78b467f8f6b57f71b0e75a2941047ad6d74f4e Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 30 May 2017 17:32:28 +0200 Subject: [PATCH 018/189] consolidate AtomicBoolean --- pvtoolsSrc/pvput.cpp | 33 +-------------------------------- src/pva/pv/pvaDefs.h | 23 +++++++++++++++++++++++ src/remote/pv/remote.h | 32 -------------------------------- 3 files changed, 24 insertions(+), 64 deletions(-) diff --git a/pvtoolsSrc/pvput.cpp b/pvtoolsSrc/pvput.cpp index 8608528..9eb9e89 100644 --- a/pvtoolsSrc/pvput.cpp +++ b/pvtoolsSrc/pvput.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -357,38 +358,6 @@ void printValue(std::string const & channelName, PVStructure::shared_pointer con std::cout << std::endl << *(pv.get()) << std::endl << std::endl; } -struct AtomicBoolean_null_deleter -{ - void operator()(void const *) const {} -}; - -// standard performance on set/clear, use of TR1::shared_ptr lock-free counter for get -// alternative is to use boost::atomic -class AtomicBoolean -{ -public: - AtomicBoolean() : counter(static_cast(0), AtomicBoolean_null_deleter()) {}; - - void set() { - mutex.lock(); - setp = counter; - mutex.unlock(); - } - void clear() { - mutex.lock(); - setp.reset(); - mutex.unlock(); - } - - bool get() const { - return counter.use_count() == 2; - } -private: - TR1::shared_ptr counter; - TR1::shared_ptr setp; - epics::pvData::Mutex mutex; -}; - class ChannelPutRequesterImpl : public ChannelPutRequester { private: diff --git a/src/pva/pv/pvaDefs.h b/src/pva/pv/pvaDefs.h index 6497d47..c88820e 100644 --- a/src/pva/pv/pvaDefs.h +++ b/src/pva/pv/pvaDefs.h @@ -17,6 +17,29 @@ typedef struct { typedef epicsInt32 pvAccessID; +class AtomicBoolean +{ +public: + AtomicBoolean() : val(false) {} + + void set() { + epicsGuard G(mutex); + val = true; + } + void clear() { + epicsGuard G(mutex); + val = false; + } + + bool get() const { + epicsGuard G(mutex); + return val; + } +private: + bool val; + mutable epicsMutex mutex; +}; + }} #endif // PVADEFS_H diff --git a/src/remote/pv/remote.h b/src/remote/pv/remote.h index 1e5d2ed..c0a35ee 100644 --- a/src/remote/pv/remote.h +++ b/src/remote/pv/remote.h @@ -609,38 +609,6 @@ public: }; -struct AtomicBoolean_null_deleter -{ - void operator()(void const *) const {} -}; - -// standard performance on set/clear, use of tr1::shared_ptr lock-free counter for get -// alternative is to use boost::atomic -class AtomicBoolean -{ -public: - AtomicBoolean() : counter(static_cast(0), AtomicBoolean_null_deleter()) {}; - - void set() { - mutex.lock(); - setp = counter; - mutex.unlock(); - } - void clear() { - mutex.lock(); - setp.reset(); - mutex.unlock(); - } - - bool get() const { - return counter.use_count() == 2; - } -private: - std::tr1::shared_ptr counter; - std::tr1::shared_ptr setp; - epics::pvData::Mutex mutex; -}; - } } From 0fbbcc2d9f46cf6ef0883f1c0a33a01296e88318 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 30 May 2017 17:33:04 +0200 Subject: [PATCH 019/189] remove deprecated Properties --- src/utils/configuration.cpp | 115 ---------------------------- src/utils/pv/configuration.h | 38 --------- testApp/utils/configurationTest.cpp | 33 +------- 3 files changed, 1 insertion(+), 185 deletions(-) diff --git a/src/utils/configuration.cpp b/src/utils/configuration.cpp index 08111b2..b0f75eb 100644 --- a/src/utils/configuration.cpp +++ b/src/utils/configuration.cpp @@ -26,121 +26,6 @@ namespace pvAccess { using namespace epics::pvData; using namespace std; -Properties::Properties() {} - -Properties::Properties(const string &fileName) : _fileName(fileName) {} - -const std::string &Properties::getProperty(const string &key) const -{ - _properties_t::const_iterator propertiesIterator = _properties.find(key); - if(propertiesIterator != _properties.end()) { - return propertiesIterator->second; - } else { - THROW_BASE_EXCEPTION(string("Property not found in the map: ") + key); - } -} - -const std::string &Properties::getProperty(const string &key, const string &defaultValue) const -{ - _properties_t::const_iterator propertiesIterator = _properties.find(key); - if(propertiesIterator != _properties.end()) { - return propertiesIterator->second; - } else { - return defaultValue; - } -} - -void Properties::load() -{ - load(_fileName); -} - -void Properties::load(const string &fileName) -{ - ifstream strm(fileName.c_str()); - load(strm); -} - -namespace { -string trim(const string& in) -{ - size_t A = in.find_first_not_of(" \t\r"), - B = in.find_last_not_of(" \t\r"); - if(A==B) - return string(); - else - return in.substr(A, B-A+1); -} -} - -void Properties::load(std::istream& strm) -{ - _properties_t newmap; - - std::string line; - unsigned lineno = 0; - while(getline(strm, line).good()) { - lineno++; - size_t idx = line.find_first_not_of(" \t\r"); - if(idx==line.npos || line[idx]=='#') - continue; - - idx = line.find_first_of('='); - if(idx==line.npos) { - ostringstream msg; - msg<<"Malformed line "<first << " = " << it->second << "\n"; - } -} - -void Properties::list() -{ - for (std::map::iterator propertiesIterator = _properties.begin() ; - propertiesIterator != _properties.end(); - propertiesIterator++ ) - { - cout << "Key:" << propertiesIterator->first << ",Value: " << propertiesIterator->second << endl; - } -} - bool Configuration::getPropertyAsBoolean(const std::string &name, const bool defaultValue) const { string value = getPropertyAsString(name, defaultValue ? "1" : "0"); diff --git a/src/utils/pv/configuration.h b/src/utils/pv/configuration.h index 5e0f77f..34cf8d3 100644 --- a/src/utils/pv/configuration.h +++ b/src/utils/pv/configuration.h @@ -36,44 +36,6 @@ union osiSockAddr; // defined in osiSock; namespace epics { namespace pvAccess { -class epicsShareClass Properties -{ -public: - Properties() EPICS_DEPRECATED; - Properties(const std::string &fileName) EPICS_DEPRECATED; - - inline void setProperty(const std::string &key,const std::string &value) - { - _properties[key] = value; - } - const std::string& getProperty(const std::string &key) const; - const std::string& getProperty(const std::string &key, const std::string &defaultValue) const; - inline bool hasProperty(const std::string &key) const - { - return _properties.find(key) != _properties.end(); - } - - void store() const; - void store(const std::string &fileName) const; - void store(std::ostream& strm) const; - void load(); - void load(const std::string &fileName); - void load(std::istream& strm); - void list(); - - inline size_t size() const { - return _properties.size(); - } -private: - typedef std::map _properties_t; - _properties_t _properties; - std::string _fileName; -public: - inline const _properties_t& map() const { - return _properties; - } -}; - class ConfigurationStack; /** diff --git a/testApp/utils/configurationTest.cpp b/testApp/utils/configurationTest.cpp index 1cee215..9f0bebc 100644 --- a/testApp/utils/configurationTest.cpp +++ b/testApp/utils/configurationTest.cpp @@ -54,36 +54,6 @@ void showEscaped(const char *msg, const std::string& s) testDiag("%s: '%s", msg, &chars[0]); } -static -void testProp() -{ - Properties plist; - - { - std::istringstream input(indata); - plist.load(input); - testOk1(!input.bad()); - testOk1(input.eof()); - } - - testOk1(plist.size()==3); - testOk1(plist.getProperty("hello")=="world"); - testOk1(plist.getProperty("this")=="is a test"); - testOk1(!plist.hasProperty("foobar")); - - { - std::ostringstream output; - plist.store(output); - std::string expect(expectdata), actual(output.str()); - - testOk1(!output.bad()); - testOk(expect.size()==actual.size(), "%u == %u", (unsigned)expect.size(), (unsigned)actual.size()); - testOk1(actual==expectdata); - showEscaped("actual", actual); - showEscaped("expect", expect); - } -} - static void showEnv(const char *name) { testDiag("%s = \"%s\"", name, getenv(name)); @@ -201,8 +171,7 @@ void testConfig() MAIN(configurationTest) { - testPlan(49); - testProp(); + testPlan(40); testBuilder(); testConfig(); return testDone(); From ce25f0b17540cab011deb4b300a24f5b9c5198c2 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 31 May 2017 11:40:51 +0200 Subject: [PATCH 020/189] ServerContext ref. loop breaking and threading Drop unnecessary "worker" thread which does no work. Ensure that returned shared_ptr is unique()==true. Add ServerContext::create() to start a new server with specific config and/or providers --- src/pipelineService/pipelineServer.cpp | 76 +---- src/pipelineService/pv/pipelineServer.h | 5 +- src/remote/pv/remote.h | 2 +- src/remoteClient/clientContextImpl.cpp | 10 +- src/rpcService/pv/rpcServer.h | 1 - src/rpcService/rpcServer.cpp | 50 +-- src/server/pv/serverContext.h | 66 ++-- src/server/pv/serverContextImpl.h | 115 +------ src/server/responseHandlers.cpp | 2 +- src/server/serverContext.cpp | 401 ++++++++---------------- testApp/remote/Makefile | 2 +- testApp/remote/channelAccessIFTest.cpp | 6 +- testApp/remote/rpcServiceExample.cpp | 2 +- testApp/remote/syncTestRequesters.h | 193 ++++-------- testApp/remote/testServer.cpp | 74 +---- testApp/remote/testServerContext.cpp | 29 +- 16 files changed, 299 insertions(+), 735 deletions(-) diff --git a/src/pipelineService/pipelineServer.cpp b/src/pipelineService/pipelineServer.cpp index 7c770c9..501fa5a 100644 --- a/src/pipelineService/pipelineServer.cpp +++ b/src/pipelineService/pipelineServer.cpp @@ -691,52 +691,11 @@ string PipelineChannelProvider::PROVIDER_NAME("PipelineService"); Status PipelineChannelProvider::noSuchChannelStatus(Status::STATUSTYPE_ERROR, "no such channel"); - -class PipelineChannelProviderFactory : public ChannelProviderFactory -{ -public: - POINTER_DEFINITIONS(PipelineChannelProviderFactory); - - PipelineChannelProviderFactory() : - m_channelProviderImpl(new PipelineChannelProvider()) - { - } - - virtual std::string getFactoryName() - { - return PipelineChannelProvider::PROVIDER_NAME; - } - - virtual ChannelProvider::shared_pointer sharedInstance() - { - return m_channelProviderImpl; - } - - virtual ChannelProvider::shared_pointer newInstance() - { - // TODO use std::make_shared - std::tr1::shared_ptr tp(new PipelineChannelProvider()); - ChannelProvider::shared_pointer channelProvider = tp; - return channelProvider; - } - -private: - PipelineChannelProvider::shared_pointer m_channelProviderImpl; -}; - - PipelineServer::PipelineServer() { - // TODO factory is never deregistered, multiple PipelineServer instances create multiple factories, etc. - m_channelProviderFactory.reset(new PipelineChannelProviderFactory()); - registerChannelProviderFactory(m_channelProviderFactory); - - m_channelProviderImpl = m_channelProviderFactory->sharedInstance(); - - m_serverContext = ServerContextImpl::create(); - m_serverContext->setChannelProviderName(m_channelProviderImpl->getProviderName()); - - m_serverContext->initialize(getChannelProviderRegistry()); + ChannelProvider::shared_pointer prov(new PipelineChannelProvider); + m_serverContext = ServerContext::create(ServerContext::Config() + .provider(m_channelProviderImpl)); } PipelineServer::~PipelineServer() @@ -756,40 +715,17 @@ void PipelineServer::run(int seconds) m_serverContext->run(seconds); } -struct ThreadRunnerParam { - PipelineServer::shared_pointer server; - int timeToRun; -}; - -static void threadRunner(void* usr) -{ - ThreadRunnerParam* pusr = static_cast(usr); - ThreadRunnerParam param = *pusr; - delete pusr; - - param.server->run(param.timeToRun); -} - /// Method requires usage of std::tr1::shared_ptr. This instance must be /// owned by a shared_ptr instance. void PipelineServer::runInNewThread(int seconds) { - std::auto_ptr param(new ThreadRunnerParam()); - param->server = shared_from_this(); - param->timeToRun = seconds; - - epicsThreadCreate("PipelineServer thread", - epicsThreadPriorityMedium, - epicsThreadGetStackSize(epicsThreadStackSmall), - threadRunner, param.get()); - - // let the thread delete 'param' - param.release(); + if(seconds!=0) + std::cerr<<"PipelineServer::runInNewThread() only suppose seconds=0\n"; } void PipelineServer::destroy() { - m_serverContext->destroy(); + m_serverContext->shutdown(); } void PipelineServer::registerService(std::string const & serviceName, PipelineService::shared_pointer const & service) diff --git a/src/pipelineService/pv/pipelineServer.h b/src/pipelineService/pv/pipelineServer.h index 8b00033..0198b30 100644 --- a/src/pipelineService/pv/pipelineServer.h +++ b/src/pipelineService/pv/pipelineServer.h @@ -21,7 +21,7 @@ #include #include -#include +#include #include @@ -33,8 +33,7 @@ class epicsShareClass PipelineServer : { private: - ServerContextImpl::shared_pointer m_serverContext; - ChannelProviderFactory::shared_pointer m_channelProviderFactory; + ServerContext::shared_pointer m_serverContext; ChannelProvider::shared_pointer m_channelProviderImpl; // TODO no thread poll implementation diff --git a/src/remote/pv/remote.h b/src/remote/pv/remote.h index c0a35ee..ce4d2b5 100644 --- a/src/remote/pv/remote.h +++ b/src/remote/pv/remote.h @@ -328,7 +328,7 @@ public: - virtual Configuration::shared_pointer getConfiguration() = 0; + virtual Configuration::const_shared_pointer getConfiguration() = 0; /** * Get map of available security plug-ins. diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index b5a2033..0104ee0 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -3744,9 +3744,9 @@ private: resubscribeSubscriptions(); setConnectionState(CONNECTED); } - catch (...) { + catch (std::exception& e) { + LOG(logLevelError, "connectionCompleted() %d '%s' unhandled exception: %s\n", sid, m_name.c_str(), e.what()); // noop - // TODO at least log something?? } // NOTE: always call cancel @@ -4300,7 +4300,7 @@ public: loadConfiguration(); } - virtual Configuration::shared_pointer getConfiguration() { + virtual Configuration::const_shared_pointer getConfiguration() { return m_configuration; } @@ -4746,8 +4746,8 @@ private: pvAccessID cid = generateCID(); return InternalChannelImpl::create(shared_from_this(), cid, name, requester, priority, addresses); } - catch(...) { - // TODO + catch(std::exception& e) { + LOG(logLevelError, "createChannelInternal() exception: %s\n", e.what()); return ChannelImpl::shared_pointer(); } // TODO namedLocker.releaseSynchronizationObject(name); diff --git a/src/rpcService/pv/rpcServer.h b/src/rpcService/pv/rpcServer.h index 454bce0..f552d1c 100644 --- a/src/rpcService/pv/rpcServer.h +++ b/src/rpcService/pv/rpcServer.h @@ -36,7 +36,6 @@ class epicsShareClass RPCServer : private: std::tr1::shared_ptr m_serverContext; - ChannelProviderFactory::shared_pointer m_channelProviderFactory; ChannelProvider::shared_pointer m_channelProviderImpl; // TODO no thread poll implementation diff --git a/src/rpcService/rpcServer.cpp b/src/rpcService/rpcServer.cpp index e87ce35..9df2d5d 100644 --- a/src/rpcService/rpcServer.cpp +++ b/src/rpcService/rpcServer.cpp @@ -483,52 +483,12 @@ string RPCChannelProvider::PROVIDER_NAME("rpcService"); Status RPCChannelProvider::noSuchChannelStatus(Status::STATUSTYPE_ERROR, "no such channel"); - -class RPCChannelProviderFactory : public ChannelProviderFactory -{ -public: - POINTER_DEFINITIONS(RPCChannelProviderFactory); - - RPCChannelProviderFactory() : - m_channelProviderImpl(new RPCChannelProvider()) - { - } - - virtual std::string getFactoryName() - { - return RPCChannelProvider::PROVIDER_NAME; - } - - virtual ChannelProvider::shared_pointer sharedInstance() - { - return m_channelProviderImpl; - } - - virtual ChannelProvider::shared_pointer newInstance() - { - // TODO use std::make_shared - std::tr1::shared_ptr tp(new RPCChannelProvider()); - ChannelProvider::shared_pointer channelProvider = tp; - return channelProvider; - } - -private: - RPCChannelProvider::shared_pointer m_channelProviderImpl; -}; - - RPCServer::RPCServer() + :m_channelProviderImpl(new RPCChannelProvider) { - // TODO factory is never deregistered, multiple RPCServer instances create multiple factories, etc. - m_channelProviderFactory.reset(new RPCChannelProviderFactory()); - registerChannelProviderFactory(m_channelProviderFactory); - - m_channelProviderImpl = m_channelProviderFactory->sharedInstance(); - - m_serverContext = ServerContextImpl::create(); - static_cast(m_serverContext.get())->setChannelProviderName(m_channelProviderImpl->getProviderName()); - - m_serverContext->initialize(getChannelProviderRegistry()); + ChannelProvider::shared_pointer prov(new RPCChannelProvider); + m_serverContext = ServerContext::create(ServerContext::Config() + .provider(m_channelProviderImpl)); } RPCServer::~RPCServer() @@ -581,7 +541,7 @@ void RPCServer::runInNewThread(int seconds) void RPCServer::destroy() { - m_serverContext->destroy(); + m_serverContext->shutdown(); } void RPCServer::registerService(std::string const & serviceName, RPCService::shared_pointer const & service) diff --git a/src/server/pv/serverContext.h b/src/server/pv/serverContext.h index 42147a9..d30be56 100644 --- a/src/server/pv/serverContext.h +++ b/src/server/pv/serverContext.h @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -26,8 +27,7 @@ namespace pvAccess { class epicsShareClass ServerContext { public: - typedef std::tr1::shared_ptr shared_pointer; - typedef std::tr1::shared_ptr const_shared_pointer; + POINTER_DEFINITIONS(ServerContext); /** * Destructor @@ -46,37 +46,22 @@ public: */ virtual const Version& getVersion() = 0; - /** - * Set ChannelProviderRegistry implementation and initialize server. - * @param channelProviderRegistry channel providers registry to be used. - */ - virtual void initialize(ChannelProviderRegistry::shared_pointer const & channelProviderRegistry) = 0; - /** * Run server (process events). * @param seconds time in seconds the server will process events (method will block), if 0 * the method would block until destroy() is called. * @throws BaseException if server is already destroyed. */ - virtual void run(epics::pvData::int32 seconds) = 0; + virtual void run(epics::pvData::uint32 seconds) = 0; - /** - * Shutdown (stop executing run() method) of this context. - * After shutdown Context cannot be rerun again, destroy() has to be called to clear all used resources. - * @throws BaseException if the context has been destroyed. - */ virtual void shutdown() = 0; - /** - * Clear all resources attached to this context. - * @throws BaseException if the context has been destroyed. - */ - virtual void destroy() = 0; + void destroy() EPICS_DEPRECATED { this->shutdown(); } /** * Prints detailed information about the context to the standard output stream. */ - virtual void printInfo() = 0; + void printInfo(); /** * Prints detailed information about the context to the specified output stream. @@ -84,14 +69,22 @@ public: */ virtual void printInfo(std::ostream& str) = 0; - /** - * Dispose (destroy) server context. - * This calls destroy() and silently handles all exceptions. - */ - virtual void dispose() = 0; + void dispose(); virtual epicsTimeStamp& getStartTime() = 0; + /** + * Get server port. + * @return server port. + */ + virtual epics::pvData::int32 getServerPort() = 0; + + /** + * Get broadcast port. + * @return broadcast port. + */ + virtual epics::pvData::int32 getBroadcastPort() = 0; + // ************************************************************************** // // **************************** [ Plugins ] ********************************* // // ************************************************************************** // @@ -102,6 +95,29 @@ public: */ virtual void setBeaconServerStatusProvider(BeaconServerStatusProvider::shared_pointer const & beaconServerStatusProvider) = 0; + class Config { + friend class ServerContext; + Configuration::const_shared_pointer _conf; + std::vector _providers; + public: + Config() {} + Config& config(const Configuration::const_shared_pointer& c) { _conf = c; return *this; } + Config& providers(const std::vector& p) { _providers = p; return *this; } + Config& provider(const ChannelProvider::shared_pointer& p) { _providers.push_back(p); return *this; } + }; + + /** Start a new PVA server + * + * By default the server will select ChannelProviders using the + * EPICS_PVA_PROVIDER_NAMES or EPICS_PVAS_PROVIDER_NAMES Configuration key. + * + * If a list of provided is given with Config::providers() then this + * overrides any Configuration. + * + * If a specific Configuration is given with Config::config() then + * this overrides the default Configuration. + */ + static ServerContext::shared_pointer create(const Config& conf = Config()); }; epicsShareFunc ServerContext::shared_pointer startPVAServer( diff --git a/src/server/pv/serverContextImpl.h b/src/server/pv/serverContextImpl.h index a5df9ba..b6fef86 100644 --- a/src/server/pv/serverContextImpl.h +++ b/src/server/pv/serverContextImpl.h @@ -1,6 +1,7 @@ #ifndef SERVERCONTEXTIMPL_H #define SERVERCONTEXTIMPL_H +#include #include #include #include @@ -15,33 +16,27 @@ class epicsShareClass ServerContextImpl : public Context, public std::tr1::enable_shared_from_this { + friend class ServerContext; public: typedef std::tr1::shared_ptr shared_pointer; typedef std::tr1::shared_ptr const_shared_pointer; -private: - ServerContextImpl(); -public: - static shared_pointer create(); - static shared_pointer create(const Configuration::shared_pointer& conf); + ServerContextImpl(); virtual ~ServerContextImpl(); //**************** derived from ServerContext ****************// const GUID& getGUID(); const Version& getVersion(); - void initialize(ChannelProviderRegistry::shared_pointer const & channelProviderRegistry); - void run(epics::pvData::int32 seconds); + void initialize(); + void run(epics::pvData::uint32 seconds); void shutdown(); - void destroy(); - void printInfo(); void printInfo(std::ostream& str); - void dispose(); void setBeaconServerStatusProvider(BeaconServerStatusProvider::shared_pointer const & beaconServerStatusProvider); //**************** derived from Context ****************// epics::pvData::Timer::shared_pointer getTimer(); Channel::shared_pointer getChannel(pvAccessID id); Transport::shared_pointer getSearchTransport(); - Configuration::shared_pointer getConfiguration(); + Configuration::const_shared_pointer getConfiguration(); TransportRegistry::shared_pointer getTransportRegistry(); std::map >& getSecurityPlugins(); @@ -56,53 +51,6 @@ public: */ static const Version VERSION; - - /** - * Server state enum. - */ - enum State { - /** - * State value of non-initialized context. - */ - NOT_INITIALIZED, - - /** - * State value of initialized context. - */ - INITIALIZED, - - /** - * State value of running context. - */ - RUNNING, - - /** - * State value of shutdown (once running) context. - */ - SHUTDOWN, - - /** - * State value of destroyed context. - */ - DESTROYED - }; - /** - * Names of the enum State - */ - static const char* StateNames[]; - - /** - * Get initialization status. - * @return initialization status. - */ - bool isInitialized(); - - /** - * Get destruction status. - * @return destruction status. - */ - bool isDestroyed(); - /** * Get beacon address list. * @return beacon address list. @@ -163,24 +111,6 @@ public: */ BlockingUDPTransport::shared_pointer getBroadcastTransport(); - /** - * Get channel provider registry implementation used by this instance. - * @return channel provider registry used by this instance. - */ - ChannelProviderRegistry::shared_pointer getChannelProviderRegistry(); - - /** - * Get channel provider name. - * @return channel provider name. - */ - std::string getChannelProviderName(); - - /** - * Set channel provider name. - * This method can only be called before initialize. - */ - void setChannelProviderName(std::string providerName); - /** * Get channel providers. * @return channel providers. @@ -200,11 +130,6 @@ private: */ GUID _guid; - /** - * Initialization status. - */ - State _state; - /** * A space-separated list of broadcast address which to send beacons. * Each address must be of the form: ip.number:port or host.name:port @@ -285,16 +210,6 @@ private: */ ResponseHandler::shared_pointer _responseHandler; - /** - * Channel access. - */ - ChannelProviderRegistry::shared_pointer _channelProviderRegistry; - - /** - * Channel provider name. - */ - std::string _channelProviderNames; - /** * Channel provider. */ @@ -330,30 +245,14 @@ private: */ void loadConfiguration(); - /** - * Internal initialization. - */ - void internalInitialize(); - - /** - * Initialize broadcast DP transport (broadcast socket and repeater connection). - */ - void initializeBroadcastTransport(); - - /** - * Internal destroy. - */ - void internalDestroy(); - /** * Destroy all transports. */ void destroyAllTransports(); - Configuration::shared_pointer configuration; + Configuration::const_shared_pointer configuration; epicsTimeStamp _startTime; - }; } diff --git a/src/server/responseHandlers.cpp b/src/server/responseHandlers.cpp index 04369cf..18b8d49 100644 --- a/src/server/responseHandlers.cpp +++ b/src/server/responseHandlers.cpp @@ -823,7 +823,7 @@ void ServerChannelRequesterImpl::channelCreated(const Status& status, Channel::s } catch (std::exception& e) { - LOG(logLevelDebug, "Exception caught when creating channel: %s", _channelName.c_str()); + LOG(logLevelDebug, "Exception caught when creating channel '%s': %s", _channelName.c_str(), e.what()); { Lock guard(_mutex); _status = Status(Status::STATUSTYPE_FATAL, "failed to create channel", e.what()); diff --git a/src/server/serverContext.cpp b/src/server/serverContext.cpp index d66b1c5..e735f79 100644 --- a/src/server/serverContext.cpp +++ b/src/server/serverContext.cpp @@ -24,12 +24,10 @@ using std::tr1::static_pointer_cast; namespace epics { namespace pvAccess { -const char* ServerContextImpl::StateNames[] = { "NOT_INITIALIZED", "INITIALIZED", "RUNNING", "SHUTDOWN", "DESTROYED"}; const Version ServerContextImpl::VERSION("pvAccess Server", "cpp", EPICS_PVA_MAJOR_VERSION, EPICS_PVA_MINOR_VERSION, EPICS_PVA_MAINTENANCE_VERSION, EPICS_PVA_DEVELOPMENT_FLAG); ServerContextImpl::ServerContextImpl(): - _state(NOT_INITIALIZED), _beaconAddressList(), _ignoreAddressList(), _autoBeaconAddressList(true), @@ -41,12 +39,9 @@ ServerContextImpl::ServerContextImpl(): _beaconEmitter(), _acceptor(), _transportRegistry(), - _channelProviderRegistry(), - _channelProviderNames(PVACCESS_DEFAULT_PROVIDER), _channelProviders(), _beaconServerStatusProvider(), _startTime() - { epicsTimeGetCurrent(&_startTime); @@ -58,22 +53,6 @@ ServerContextImpl::ServerContextImpl(): initializeLogger(); } -ServerContextImpl::shared_pointer ServerContextImpl::create() -{ - ServerContextImpl::shared_pointer thisPointer(new ServerContextImpl()); - thisPointer->loadConfiguration(); - return thisPointer; -} - -ServerContextImpl::shared_pointer ServerContextImpl::create( - const Configuration::shared_pointer& conf) -{ - ServerContextImpl::shared_pointer thisPointer(new ServerContextImpl()); - thisPointer->configuration = conf; - thisPointer->loadConfiguration(); - return thisPointer; -} - ServerContextImpl::~ServerContextImpl() { dispose(); @@ -89,16 +68,6 @@ const Version& ServerContextImpl::getVersion() return ServerContextImpl::VERSION; } -/* -#ifdef WIN32 - UUID uuid; - UuidCreate ( &uuid ); -#else - uuid_t uuid; - uuid_generate_random ( uuid ); -#endif -*/ - void ServerContextImpl::generateGUID() { // TODO use UUID @@ -115,7 +84,7 @@ void ServerContextImpl::initializeLogger() //createFileLogger("serverContextImpl.log"); } -Configuration::shared_pointer ServerContextImpl::getConfiguration() +Configuration::const_shared_pointer ServerContextImpl::getConfiguration() { Lock guard(_mutex); if (configuration.get() == 0) @@ -135,7 +104,7 @@ Configuration::shared_pointer ServerContextImpl::getConfiguration() */ void ServerContextImpl::loadConfiguration() { - Configuration::shared_pointer config = getConfiguration(); + Configuration::const_shared_pointer config = configuration; // TODO for now just a simple switch int32 debugLevel = config->getPropertyAsInteger(PVACCESS_DEBUG, 0); @@ -167,8 +136,45 @@ void ServerContextImpl::loadConfiguration() _receiveBufferSize = config->getPropertyAsInteger("EPICS_PVA_MAX_ARRAY_BYTES", _receiveBufferSize); _receiveBufferSize = config->getPropertyAsInteger("EPICS_PVAS_MAX_ARRAY_BYTES", _receiveBufferSize); - _channelProviderNames = config->getPropertyAsString("EPICS_PVA_PROVIDER_NAMES", _channelProviderNames); - _channelProviderNames = config->getPropertyAsString("EPICS_PVAS_PROVIDER_NAMES", _channelProviderNames); + if(_channelProviders.empty()) { + std::string providers = config->getPropertyAsString("EPICS_PVA_PROVIDER_NAMES", PVACCESS_DEFAULT_PROVIDER); + providers = config->getPropertyAsString("EPICS_PVAS_PROVIDER_NAMES", providers); + + ChannelProviderRegistry::shared_pointer reg(getChannelProviderRegistry()); + + if (providers == PVACCESS_ALL_PROVIDERS) + { + providers.resize(0); // VxWorks 5.5 omits clear() + + std::auto_ptr names = reg->getProviderNames(); + for (ChannelProviderRegistry::stringVector_t::iterator iter = names->begin(); iter != names->end(); iter++) + { + ChannelProvider::shared_pointer channelProvider = reg->getProvider(*iter); + if (channelProvider) { + _channelProviders.push_back(channelProvider); + } else { + LOG(logLevelDebug, "Provider '%s' all, but missing\n", iter->c_str()); + } + } + + } else { + // split space separated names + std::stringstream ss(providers); + std::string providerName; + while (std::getline(ss, providerName, ' ')) + { + ChannelProvider::shared_pointer channelProvider(reg->getProvider(providerName)); + if (channelProvider) { + _channelProviders.push_back(channelProvider); + } else { + LOG(logLevelWarn, "Requested provider '%s' not found", providerName.c_str()); + } + } + } + } + + if(_channelProviders.empty()) + LOG(logLevelError, "ServerContext configured with not Providers will do nothing!\n"); // // introspect network interfaces @@ -194,77 +200,14 @@ void ServerContextImpl::loadConfiguration() bool ServerContextImpl::isChannelProviderNamePreconfigured() { - Configuration::shared_pointer config = getConfiguration(); + Configuration::const_shared_pointer config = getConfiguration(); return config->hasProperty("EPICS_PVA_PROVIDER_NAMES") || config->hasProperty("EPICS_PVAS_PROVIDER_NAMES"); } -void ServerContextImpl::initialize(ChannelProviderRegistry::shared_pointer const & channelProviderRegistry) +void ServerContextImpl::initialize() { Lock guard(_mutex); - if (!channelProviderRegistry.get()) - { - THROW_BASE_EXCEPTION("channelProviderRegistry == NULL"); - } - if (_state == DESTROYED) - { - THROW_BASE_EXCEPTION("Context destroyed."); - } - else if (_state != NOT_INITIALIZED) - { - THROW_BASE_EXCEPTION("Context already initialized."); - } - - _channelProviderRegistry = channelProviderRegistry; - - - // user all providers - if (_channelProviderNames == PVACCESS_ALL_PROVIDERS) - { - _channelProviderNames.resize(0); // VxWorks 5.5 omits clear() - - std::auto_ptr names = _channelProviderRegistry->getProviderNames(); - for (ChannelProviderRegistry::stringVector_t::iterator iter = names->begin(); iter != names->end(); iter++) - { - ChannelProvider::shared_pointer channelProvider = _channelProviderRegistry->getProvider(*iter); - if (channelProvider) - { - _channelProviders.push_back(channelProvider); - - // compile a list - if (!_channelProviderNames.empty()) - _channelProviderNames += ' '; - _channelProviderNames += *iter; - } - } - } - else - { - // split space separated names - std::stringstream ss(_channelProviderNames); - std::string providerName; - while (std::getline(ss, providerName, ' ')) - { - ChannelProvider::shared_pointer channelProvider = _channelProviderRegistry->getProvider(providerName); - if (channelProvider) - _channelProviders.push_back(channelProvider); - } - } - - //_channelProvider = _channelProviderRegistry->getProvider(_channelProviderNames); - if (_channelProviders.size() == 0) - { - std::string msg = "None of the specified channel providers are available: " + _channelProviderNames + "."; - THROW_BASE_EXCEPTION(msg.c_str()); - } - - internalInitialize(); - - _state = INITIALIZED; -} - -void ServerContextImpl::internalInitialize() -{ // already called in loadConfiguration //osiSockAttach(); @@ -278,51 +221,16 @@ void ServerContextImpl::internalInitialize() _serverPort = ntohs(_acceptor->getBindAddress()->ia.sin_port); // setup broadcast UDP transport - initializeBroadcastTransport(); - - // TODO introduce "tcp" a constant - _beaconEmitter.reset(new BeaconEmitter("tcp", _broadcastTransport, thisServerContext)); -} - -void ServerContextImpl::initializeBroadcastTransport() -{ initializeUDPTransports(true, _udpTransports, _ifaceList, _responseHandler, _broadcastTransport, _broadcastPort, _autoBeaconAddressList, _beaconAddressList, _ignoreAddressList); + + _beaconEmitter.reset(new BeaconEmitter("tcp", _broadcastTransport, thisServerContext)); + + _beaconEmitter->start(); } -void ServerContextImpl::run(int32 seconds) +void ServerContextImpl::run(uint32 seconds) { - if (seconds < 0) - { - THROW_BASE_EXCEPTION("seconds cannot be negative."); - } - - { - Lock guard(_mutex); - - if (_state == NOT_INITIALIZED) - { - THROW_BASE_EXCEPTION("Context not initialized."); - } - else if (_state == DESTROYED) - { - THROW_BASE_EXCEPTION("Context destroyed."); - } - else if (_state == RUNNING) - { - THROW_BASE_EXCEPTION("Context is already running."); - } - else if (_state == SHUTDOWN) - { - THROW_BASE_EXCEPTION("Context was shutdown."); - } - - _state = RUNNING; - } - - // run... - _beaconEmitter->start(); - //TODO review this if(seconds == 0) { @@ -332,48 +240,9 @@ void ServerContextImpl::run(int32 seconds) { _runEvent.wait(seconds); } - - { - Lock guard(_mutex); - _state = SHUTDOWN; - } } void ServerContextImpl::shutdown() -{ - Lock guard(_mutex); - if(_state == DESTROYED) - { - THROW_BASE_EXCEPTION("Context already destroyed."); - } - - // notify to stop running... - _runEvent.signal(); -} - -void ServerContextImpl::destroy() -{ - Lock guard(_mutex); - if (_state == DESTROYED) - { - // silent return - return; - // exception is not OK, since we use - // shared_pointer-s auto-cleanup/destruction - // THROW_BASE_EXCEPTION("Context already destroyed."); - } - - // shutdown if not already - shutdown(); - - // go into destroyed state ASAP - _state = DESTROYED; - - internalDestroy(); -} - - -void ServerContextImpl::internalDestroy() { // stop responding to search requests for (BlockingUDPTransportVector::const_iterator iter = _udpTransports.begin(); @@ -404,6 +273,12 @@ void ServerContextImpl::internalDestroy() // this will also destroy all channels destroyAllTransports(); + + // response handlers hold strong references to us, + // so must break the cycles + _responseHandler.reset(); + + _runEvent.signal(); } void ServerContextImpl::destroyAllTransports() @@ -449,7 +324,7 @@ void ServerContextImpl::destroyAllTransports() } -void ServerContextImpl::printInfo() +void ServerContext::printInfo() { printInfo(cout); } @@ -457,24 +332,29 @@ void ServerContextImpl::printInfo() void ServerContextImpl::printInfo(ostream& str) { Lock guard(_mutex); - str << "VERSION : " << getVersion().getVersionString() << endl \ - << "PROVIDER_NAMES : " << _channelProviderNames << endl \ - << "BEACON_ADDR_LIST : " << _beaconAddressList << endl \ - << "AUTO_BEACON_ADDR_LIST : " << _autoBeaconAddressList << endl \ - << "BEACON_PERIOD : " << _beaconPeriod << endl \ - << "BROADCAST_PORT : " << _broadcastPort << endl \ - << "SERVER_PORT : " << _serverPort << endl \ - << "RCV_BUFFER_SIZE : " << _receiveBufferSize << endl \ - << "IGNORE_ADDR_LIST: " << _ignoreAddressList << endl \ - << "INTF_ADDR_LIST : " << inetAddressToString(_ifaceAddr, false) << endl \ - << "STATE : " << ServerContextImpl::StateNames[_state] << endl; + str << "VERSION : " << getVersion().getVersionString() << endl + << "PROVIDER_NAMES : "; + for(std::vector::const_iterator it = _channelProviders.begin(); + it != _channelProviders.end(); ++it) + { + str<<(*it)->getProviderName()<<", "; + } + str << endl + << "BEACON_ADDR_LIST : " << _beaconAddressList << endl + << "AUTO_BEACON_ADDR_LIST : " << _autoBeaconAddressList << endl + << "BEACON_PERIOD : " << _beaconPeriod << endl + << "BROADCAST_PORT : " << _broadcastPort << endl + << "SERVER_PORT : " << _serverPort << endl + << "RCV_BUFFER_SIZE : " << _receiveBufferSize << endl + << "IGNORE_ADDR_LIST: " << _ignoreAddressList << endl + << "INTF_ADDR_LIST : " << inetAddressToString(_ifaceAddr, false) << endl; } -void ServerContextImpl::dispose() +void ServerContext::dispose() { try { - destroy(); + shutdown(); } catch(std::exception& e) { @@ -491,18 +371,6 @@ void ServerContextImpl::setBeaconServerStatusProvider(BeaconServerStatusProvider _beaconServerStatusProvider = beaconServerStatusProvider; } -bool ServerContextImpl::isInitialized() -{ - Lock guard(_mutex); - return _state == INITIALIZED || _state == RUNNING || _state == SHUTDOWN; -} - -bool ServerContextImpl::isDestroyed() -{ - Lock guard(_mutex); - return _state == DESTROYED; -} - std::string ServerContextImpl::getBeaconAddressList() { return _beaconAddressList; @@ -557,24 +425,6 @@ BlockingUDPTransport::shared_pointer ServerContextImpl::getBroadcastTransport() return _broadcastTransport; } -ChannelProviderRegistry::shared_pointer ServerContextImpl::getChannelProviderRegistry() -{ - return _channelProviderRegistry; -} - -std::string ServerContextImpl::getChannelProviderName() -{ - return _channelProviderNames; -} - -// NOTE: not synced -void ServerContextImpl::setChannelProviderName(std::string channelProviderName) -{ - if (_state != NOT_INITIALIZED) - throw std::logic_error("must be called before initialize"); - _channelProviderNames = channelProviderName; -} - std::vector& ServerContextImpl::getChannelProviders() { return _channelProviders; @@ -620,60 +470,69 @@ std::map >& ServerContextImpl: -struct ThreadRunnerParam { - ServerContextImpl::shared_pointer ctx; - int timeToRun; -}; - -static void threadRunner(void* usr) -{ - ThreadRunnerParam* pusr = static_cast(usr); - ThreadRunnerParam param = *pusr; - delete pusr; - - param.ctx->run(param.timeToRun); -} - - - ServerContext::shared_pointer startPVAServer(std::string const & providerNames, int timeToRun, bool runInSeparateThread, bool printInfo) { - ServerContextImpl::shared_pointer ctx = ServerContextImpl::create(); + ServerContext::shared_pointer ret(ServerContext::create(ServerContext::Config() + .config(ConfigurationBuilder() + .add("EPICS_PVAS_PROVIDER_NAMES", providerNames) + .push_map() + .push_env() + .build()))); + if(printInfo) + ret->printInfo(); - // do not override configuration - if (!ctx->isChannelProviderNamePreconfigured()) - ctx->setChannelProviderName(providerNames); - - ChannelProviderRegistry::shared_pointer channelProviderRegistry = getChannelProviderRegistry(); - ctx->initialize(channelProviderRegistry); - - if (printInfo) - ctx->printInfo(); - - - if (runInSeparateThread) - { - // delete left to the thread (which doesn't) - auto_ptr param(new ThreadRunnerParam()); - param->ctx = ctx; - param->timeToRun = timeToRun; - - // TODO can this fail? - epicsThreadCreate("startPVAServer", - epicsThreadPriorityMedium, - epicsThreadGetStackSize(epicsThreadStackBig), - threadRunner, param.get()); - - param.release(); - // leak... - } - else - { - ctx->run(timeToRun); + if(!runInSeparateThread) { + ret->run(timeToRun); + ret->shutdown(); + } else if(timeToRun!=0) { + LOG(logLevelWarn, "startPVAServer() timeToRun!=0 only supported when runInSeparateThread==false\n"); } - return ctx; + return ret; } +namespace { +struct shutdown_dtor { + ServerContextImpl::shared_pointer wrapped; + shutdown_dtor(const ServerContextImpl::shared_pointer& wrapped) :wrapped(wrapped) {} + void operator()(ServerContext* self) { + wrapped->shutdown(); + if(!wrapped.unique()) + LOG(logLevelWarn, "ServerContextImpl::shutdown() doesn't break all internal ref. loops. use_count=%u\n", (unsigned)wrapped.use_count()); + wrapped.reset(); + } +}; } + +ServerContext::shared_pointer ServerContext::create(const Config &conf) +{ + ServerContextImpl::shared_pointer ret(new ServerContextImpl()); + ret->configuration = conf._conf; + ret->_channelProviders = conf._providers; + + if (!ret->configuration) + { + ConfigurationProvider::shared_pointer configurationProvider = ConfigurationFactory::getProvider(); + ret->configuration = configurationProvider->getConfiguration("pvAccess-server"); + if (!ret->configuration) + { + ret->configuration = configurationProvider->getConfiguration("system"); + } + } + if(!ret->configuration) { + ret->configuration = ConfigurationBuilder().push_env().build(); + } + + ret->loadConfiguration(); + ret->initialize(); + + // wrap the returned shared_ptr so that it's dtor calls ->shutdown() to break internal referance loops + { + ServerContextImpl::shared_pointer wrapper(ret.get(), shutdown_dtor(ret)); + wrapper.swap(ret); + } + + return ret; } + +}} diff --git a/testApp/remote/Makefile b/testApp/remote/Makefile index 83c6f4c..9784d3c 100644 --- a/testApp/remote/Makefile +++ b/testApp/remote/Makefile @@ -21,7 +21,7 @@ testChannelConnect_SRCS += testChannelConnect.cpp TESTPROD_HOST += testServerContext testServerContext_SRCS += testServerContext.cpp - +TESTS += testServerContext PROD_HOST += testServer diff --git a/testApp/remote/channelAccessIFTest.cpp b/testApp/remote/channelAccessIFTest.cpp index 58919f2..e35d731 100644 --- a/testApp/remote/channelAccessIFTest.cpp +++ b/testApp/remote/channelAccessIFTest.cpp @@ -76,13 +76,14 @@ int ChannelAccessIFTest::runAllTest() { .build()); TestServer::shared_pointer tstserv(new TestServer(base_config)); - tstserv->start(); - testDiag("TestServer on ports TCP=%u UDP=%u\n", + + testDiag("TestServer on ports TCP=%u UDP=%u", tstserv->getServerPort(), tstserv->getBroadcastPort()); ConfigurationFactory::registerConfiguration("pvAccess-client", ConfigurationBuilder() .push_config(base_config) + //.add("EPICS_PVA_DEBUG", "3") .add("EPICS_PVA_BROADCAST_PORT", tstserv->getBroadcastPort()) .push_map() .build()); @@ -352,6 +353,7 @@ void ChannelAccessIFTest::test_createChannel() { TR1::shared_ptr channelReq(new SyncChannelRequesterImpl()); Channel::shared_pointer channel = getChannelProvider()->createChannel(TEST_COUNTER_CHANNEL_NAME, channelReq); + testDiag("Channel to '%s', wait for connect", TEST_COUNTER_CHANNEL_NAME.c_str()); bool succStatus = channelReq->waitUntilStateChange(getTimeoutSec()); if (!succStatus) { std::cerr << "[" << TEST_COUNTER_CHANNEL_NAME << "] failed to connect. " << std::endl; diff --git a/testApp/remote/rpcServiceExample.cpp b/testApp/remote/rpcServiceExample.cpp index a62c4bf..5dab449 100644 --- a/testApp/remote/rpcServiceExample.cpp +++ b/testApp/remote/rpcServiceExample.cpp @@ -53,7 +53,7 @@ class SumServiceImpl : // create return structure and set data PVStructure::shared_pointer result = getPVDataCreate()->createPVStructure(resultStructure); - result->getSubField("c")->put(a+b); + result->getSubFieldT("c")->put(a+b); return result; } }; diff --git a/testApp/remote/syncTestRequesters.h b/testApp/remote/syncTestRequesters.h index 8bb9a23..0781cea 100644 --- a/testApp/remote/syncTestRequesters.h +++ b/testApp/remote/syncTestRequesters.h @@ -19,11 +19,10 @@ public: bool waitUntilGetDone(double timeOut) { - bool signaled = waitUntilEvent(timeOut); - if (!signaled) + if (!waitUntilEvent(timeOut)) return false; - Lock lock(m_getStatusMutex); + Lock lock(m_lock); return m_getStatus; } @@ -31,143 +30,123 @@ public: bool waitUntilConnected(double timeOut) { - bool signaled = waitUntilEvent(timeOut); - if (!signaled) + if (!waitUntilEvent(timeOut)) return false; - Lock lock(m_connectedStatusMutex); + Lock lock(m_lock); return m_connectedStatus; } - virtual ~SyncBaseRequester() {} ; + virtual ~SyncBaseRequester() {} protected: - const bool m_debug; - - SyncBaseRequester(bool debug = false): - m_debug(debug), - m_event(new Event()), - m_connectedStatus(false), - m_getStatus(false), - m_putStatus(false) {} + SyncBaseRequester(bool debug = false) + :m_event() + ,m_connectedStatus(false) + ,m_getStatus(false) + ,m_putStatus(false) + ,m_processStatus(false) + {} bool waitUntilPutDone(double timeOut) { - - bool signaled = waitUntilEvent(timeOut); - if (!signaled) + if (!waitUntilEvent(timeOut)) return false; - Lock lock(m_putStatusMutex); + Lock lock(m_lock); return m_putStatus; } bool waitUntilProcessDone(double timeOut) { - - bool signaled = waitUntilEvent(timeOut); - if (!signaled) + if (!waitUntilEvent(timeOut)) return false; - Lock lock(m_processStatusMutex); + Lock lock(m_lock); return m_processStatus; } void setConnectedStatus(bool status) { - Lock lock(m_connectedStatusMutex); + Lock lock(m_lock); m_connectedStatus = status; } bool getConnectedStatus() { - Lock lock(m_connectedStatusMutex); + Lock lock(m_lock); return m_connectedStatus; } void setGetStatus(bool status) { - Lock lock(m_getStatusMutex); + Lock lock(m_lock); m_getStatus = status; } bool getGetStatus() { - Lock lock(m_getStatusMutex); + Lock lock(m_lock); return m_getStatus; } void setPutStatus(bool status) { - Lock lock(m_putStatusMutex); + Lock lock(m_lock); m_putStatus = status; } bool getPutStatus() { - Lock lock(m_putStatusMutex); + Lock lock(m_lock); return m_putStatus; } void setProcessStatus(bool status) { - Lock lock(m_processStatusMutex); + Lock lock(m_lock); m_processStatus = status; } bool getProcessStatus() { - Lock lock(m_processStatusMutex); + Lock lock(m_lock); return m_processStatus; } void resetEvent() { - Lock lock(m_eventMutex); - m_event.reset(new Event()); + m_event.tryWait(); } void signalEvent() { - Lock lock(m_eventMutex); - m_event->signal(); + m_event.signal(); } + // return true if event occurs, false on timeout bool waitUntilEvent(double timeOut) { - std::tr1::shared_ptr event; - { - Lock lock(m_eventMutex); - event = m_event; - } - - bool signaled = event->wait(timeOut); + bool signaled = m_event.wait(timeOut); if (!signaled) { - if (m_debug) - std::cerr << "wait until event timeout" << std::endl; - - return false; + std::cout << "# waited until event timeout" << std::endl; } - return true; + return signaled; } private: - std::tr1::shared_ptr m_event; + epics::pvData::Event m_event; bool m_connectedStatus; bool m_getStatus; bool m_putStatus; bool m_processStatus; - Mutex m_connectedStatusMutex; - Mutex m_getStatusMutex; - Mutex m_putStatusMutex; - Mutex m_processStatusMutex; - Mutex m_eventMutex; + Mutex m_lock; }; @@ -218,8 +197,7 @@ public: const epics::pvData::Status& status, epics::pvAccess::Channel::shared_pointer const & channel) { - if (m_debug) - std::cout << getRequesterName() << "." << "channelCreated(" << status << ")" << std::endl; + std::cout << "#" << getRequesterName() << "." << "channelCreated(" << status << ")" << std::endl; Lock lock(m_pointerMutex); m_status = status; @@ -230,8 +208,7 @@ public: } else { - if (m_debug) - std::cerr << "[" << channel->getChannelName() << "] failed to create a channel: " << std::endl; + std::cerr << "#" << "[" << channel->getChannelName() << "] failed to create a channel: " << std::endl; } } @@ -241,8 +218,7 @@ public: epics::pvAccess::Channel::ConnectionState connectionState) { - if (m_debug) - std::cout << getRequesterName() << "." << "channelStateChange:" << connectionState << std::endl; + std::cout << "#" << getRequesterName() << "." << "channelStateChange:" << connectionState << std::endl; { Lock lock(m_pointerMutex); @@ -288,8 +264,7 @@ public: virtual void channelFindResult(const epics::pvData::Status& status, const epics::pvAccess::ChannelFind::shared_pointer&, bool wasFound) { - if (m_debug) - std::cout << "channelFindResult(" << status << ")" << std::endl; + std::cout << "#" << "channelFindResult(" << status << ")" << std::endl; { Lock lock(m_pointerMutex); @@ -355,8 +330,7 @@ public: virtual void message(string const & message, MessageType messageType) { - if (m_debug) - std::cerr << "[" + std::cerr << "# [" << getRequesterName() << "] message(" << message << ", " @@ -370,8 +344,7 @@ public: const epics::pvData::Status& status,ChannelGet::shared_pointer const & channelGet, epics::pvData::Structure::const_shared_pointer const & /*structure*/) { - if (m_debug) - std::cout << getRequesterName() << "." << "channelGetConnect(" << status << ")" << std::endl; + std::cout << "#" << getRequesterName() << "." << "channelGetConnect(" << status << ")" << std::endl; if (status.isSuccess()) { @@ -393,8 +366,7 @@ public: epics::pvData::PVStructure::shared_pointer const & pvStructure, epics::pvData::BitSet::shared_pointer const & bitSet) { - if (m_debug) - std::cout << getRequesterName() << "." << "getDone(" << status << ")" << std::endl; + std::cout << "#" << getRequesterName() << "." << "getDone(" << status << ")" << std::endl; { Lock lock(m_pointerMutex); @@ -484,8 +456,7 @@ public: virtual void message(string const & message,MessageType messageType) { - if (m_debug) - std::cout << "[" << getRequesterName() << "] message(" << message << ", " + std::cout << "#" << "[" << getRequesterName() << "] message(" << message << ", " << getMessageTypeName(messageType) << ")" << std::endl; } @@ -495,8 +466,7 @@ public: epics::pvData::Structure::const_shared_pointer const & /*structure*/) { - if (m_debug) - std::cout << getRequesterName() << "." << "channelPutConnect(" << status << ")" << std::endl; + std::cout << "#" << getRequesterName() << "." << "channelPutConnect(" << status << ")" << std::endl; if (status.isSuccess()) { @@ -521,8 +491,7 @@ public: epics::pvData::PVStructure::shared_pointer const & pvStructure, epics::pvData::BitSet::shared_pointer const & bitSet) { - if (m_debug) - std::cout << getRequesterName() << "." << "getDone(" << status << ")" << std::endl; + std::cout << "#" << getRequesterName() << "." << "getDone(" << status << ")" << std::endl; { Lock lock(m_pointerMutex); @@ -539,8 +508,7 @@ public: virtual void putDone(const epics::pvData::Status& status, ChannelPut::shared_pointer const & channelPut) { - if (m_debug) - std::cout << getRequesterName() << "." << "putDone(" << status << ")" << std::endl; + std::cout << "#" << getRequesterName() << "." << "putDone(" << status << ")" << std::endl; { Lock lock(m_pointerMutex); @@ -586,16 +554,14 @@ public: virtual void message(string const & message,MessageType /*messageType*/) { - if (m_debug) - std::cout << "[" << getRequesterName() << "] message(" << message << endl; + std::cout << "# [" << getRequesterName() << "] message(" << message << endl; } virtual void getDone(const epics::pvData::Status& status,epics::pvData::FieldConstPtr const & field) { - if (m_debug) - std::cout << getRequesterName() << "." << "getDone(" << status << endl; + std::cout << "#" << getRequesterName() << "." << "getDone(" << status << endl; if (status.isSuccess() && field) { @@ -655,8 +621,7 @@ public: virtual void message(string const & message,MessageType /*messageType*/) { - if (m_debug) - std::cout << "[" << getRequesterName() << "] message(" << message << std::endl; + std::cout << "# [" << getRequesterName() << "] message(" << message << std::endl; } @@ -664,8 +629,7 @@ public: ChannelProcess::shared_pointer const & channelProcess) { - if (m_debug) - std::cout << getRequesterName() << "." << "channelProcessConnect(" << status << ")" << std::endl; + std::cout << "#" << getRequesterName() << "." << "channelProcessConnect(" << status << ")" << std::endl; if (status.isSuccess()) { @@ -687,8 +651,7 @@ public: virtual void processDone(const epics::pvData::Status& status, ChannelProcess::shared_pointer const & channelProcess) { - if (m_debug) - std::cout << getRequesterName() << "." << "processDone(" << status << ")" << std::endl; + std::cout << "#" << getRequesterName() << "." << "processDone(" << status << ")" << std::endl; { Lock lock(m_pointerMutex); @@ -799,8 +762,7 @@ public: virtual void message(string const & message,MessageType messageType) { - if (m_debug) - std::cout << "[" << getRequesterName() << "] message(" << + std::cout << "# [" << getRequesterName() << "] message(" << message << ", " << getMessageTypeName(messageType) << ")" << std::endl; } @@ -810,8 +772,7 @@ public: epics::pvData::Structure::const_shared_pointer const & /*putStructure*/, epics::pvData::Structure::const_shared_pointer const & /*getStructure*/) { - if (m_debug) - std::cout << getRequesterName() << "." << "channelGetPutConnect(" + std::cout << "#" << getRequesterName() << "." << "channelGetPutConnect(" << status << ")" << std::endl; if (status.isSuccess()) @@ -838,8 +799,7 @@ public: epics::pvData::PVStructure::shared_pointer const & getData, epics::pvData::BitSet::shared_pointer const & getBitSet) { - if (m_debug) - std::cout << getRequesterName() << "." << "getGetDone(" << status << ")" << std::endl; + std::cout << "#" << getRequesterName() << "." << "getGetDone(" << status << ")" << std::endl; { Lock lock(m_pointerMutex); @@ -860,8 +820,7 @@ public: epics::pvData::PVStructure::shared_pointer const & putData, epics::pvData::BitSet::shared_pointer const & putBitSet) { - if (m_debug) - std::cout << getRequesterName() << "." << "getPutDone(" << status << ")" << std::endl; + std::cout << "#" << getRequesterName() << "." << "getPutDone(" << status << ")" << std::endl; { Lock lock(m_pointerMutex); @@ -882,8 +841,7 @@ public: epics::pvData::PVStructure::shared_pointer const & getData, epics::pvData::BitSet::shared_pointer const & getBitSet) { - if (m_debug) - std::cout << getRequesterName() << "." << "putGetDone(" << status << ")" << std::endl; + std::cout << "#" << getRequesterName() << "." << "putGetDone(" << status << ")" << std::endl; { Lock lock(m_pointerMutex); @@ -997,8 +955,7 @@ public: virtual void message(string const & message, MessageType messageType) { - if (m_debug) - std::cerr << "[" << getRequesterName() << "] message(" << message << ", " + std::cerr << "# [" << getRequesterName() << "] message(" << message << ", " << getMessageTypeName(messageType) << ")" << std::endl; } @@ -1007,8 +964,7 @@ public: ChannelRPC::shared_pointer const & channelRPC) { - if (m_debug) - std::cout << getRequesterName() << "." << "channelRPCConnect(" + std::cout << "#" << getRequesterName() << "." << "channelRPCConnect(" << status << ")" << std::endl; if (status.isSuccess()) @@ -1034,8 +990,7 @@ public: epics::pvData::PVStructure::shared_pointer const &pvResponse) { - if (m_debug) - std::cout << getRequesterName() << "." << "requestDone(" + std::cout << "#" << getRequesterName() << "." << "requestDone(" << status << ")" << std::endl; { @@ -1126,8 +1081,7 @@ public: bool signaled = waitUntilEvent(timeOut); if (!signaled) { - if (m_debug) - std::cerr << getRequesterName() << ".waitUntilMonitor:" << " timeout occurred" << endl; + std::cerr << "#" << getRequesterName() << ".waitUntilMonitor:" << " timeout occurred" << endl; return false; } @@ -1152,8 +1106,7 @@ public: bool signaled = waitUntilEvent(timeOut); if (!signaled) { - if (m_debug) - std::cerr << getRequesterName() << ".waitUntilMonitor:" << " timeout occurred" << endl; + std::cerr << "#" << getRequesterName() << ".waitUntilMonitor:" << " timeout occurred" << endl; return false; } @@ -1170,8 +1123,7 @@ public: virtual void message(string const & message, MessageType messageType) { - if (m_debug) - std::cerr << "[" << getRequesterName() << "] message(" << message << ", " + std::cerr << "# [" << getRequesterName() << "] message(" << message << ", " << getMessageTypeName(messageType) << ")" << std::endl; } @@ -1179,8 +1131,7 @@ public: virtual void monitorConnect(const epics::pvData::Status& status, Monitor::shared_pointer const & monitor, StructureConstPtr const & /*structure*/) { - if (m_debug) - std::cout << getRequesterName() << "." << "monitorConnect(" << status << ")" << std::endl; + std::cout << "#" << getRequesterName() << "." << "monitorConnect(" << status << ")" << std::endl; if (status.isSuccess()) { @@ -1202,8 +1153,7 @@ public: virtual void monitorEvent(MonitorPtr const & monitor) { - if (m_debug) - std::cout << getRequesterName() << "." << "monitorEvent" << std::endl; + std::cout << "#" << getRequesterName() << "." << "monitorEvent" << std::endl; MonitorElement::shared_pointer element = monitor->poll(); @@ -1223,8 +1173,7 @@ public: virtual void unlisten(MonitorPtr const & /*monitor*/) { - if (m_debug) - std::cout << getRequesterName() << "." << "unlisten" << std::endl; + std::cout << "#" << getRequesterName() << "." << "unlisten" << std::endl; } @@ -1337,8 +1286,7 @@ public: virtual void message(std::string const & message,MessageType messageType) { - if (m_debug) - std::cout << "[" << getRequesterName() << "] message(" << message << ", " + std::cout << "# [" << getRequesterName() << "] message(" << message << ", " << getMessageTypeName(messageType) << ")" << std::endl; } @@ -1347,8 +1295,7 @@ public: ChannelArray::shared_pointer const & channelArray, epics::pvData::Array::const_shared_pointer const & /*array*/) { - if (m_debug) - std::cout << getRequesterName() << ".channelArrayConnect(" << status << ")" << std::endl; + std::cout << "#" << getRequesterName() << ".channelArrayConnect(" << status << ")" << std::endl; if (status.isSuccess()) { { @@ -1371,8 +1318,7 @@ public: ChannelArray::shared_pointer const & channelArray, epics::pvData::PVArray::shared_pointer const & pvArray) { - if (m_debug) - std::cout << getRequesterName() << ".getArrayDone(" << status << ")" << std::endl; + std::cout << "#" << getRequesterName() << ".getArrayDone(" << status << ")" << std::endl; Lock lock(m_pointerMutex); @@ -1387,8 +1333,7 @@ public: virtual void putArrayDone(const epics::pvData::Status& status, ChannelArray::shared_pointer const & channelArray) { - if (m_debug) - std::cout << getRequesterName() << ".putArrayDone(" << status << ")" << std::endl; + std::cout << "#" << getRequesterName() << ".putArrayDone(" << status << ")" << std::endl; Lock lock(m_pointerMutex); @@ -1402,8 +1347,7 @@ public: virtual void setLengthDone(const epics::pvData::Status& status, ChannelArray::shared_pointer const & channelArray) { - if (m_debug) - std::cout << getRequesterName() << ".setLengthDone(" << status << ")" << std::endl; + std::cout << "#" << getRequesterName() << ".setLengthDone(" << status << ")" << std::endl; Lock lock(m_pointerMutex); @@ -1417,8 +1361,7 @@ public: ChannelArray::shared_pointer const & channelArray, size_t length) { - if (m_debug) - std::cout << getRequesterName() << ".getLengthDone(" << status << ")" << std::endl; + std::cout << "#" << getRequesterName() << ".getLengthDone(" << status << ")" << std::endl; Lock lock(m_pointerMutex); diff --git a/testApp/remote/testServer.cpp b/testApp/remote/testServer.cpp index c191bda..ab46846 100644 --- a/testApp/remote/testServer.cpp +++ b/testApp/remote/testServer.cpp @@ -9,7 +9,7 @@ // disable buggy boost enable_shared_from_this assert code #define BOOST_DISABLE_ASSERTS -#include +#include #include #include #include @@ -2755,73 +2755,26 @@ private: string MockServerChannelProvider::PROVIDER_NAME = "local"; -class MockChannelProviderFactory : public ChannelProviderFactory -{ -public: - POINTER_DEFINITIONS(MockChannelProviderFactory); - - virtual std::string getFactoryName() - { - return MockServerChannelProvider::PROVIDER_NAME; - } - - virtual ChannelProvider::shared_pointer sharedInstance() - { - // no shared instance support for mock... - return newInstance(); - } - - virtual ChannelProvider::shared_pointer newInstance() - { - MockServerChannelProvider::shared_pointer channelProvider(new MockServerChannelProvider()); - channelProvider->initialize(); - return channelProvider; - } - -}; - -struct TestServer : public Runnable +struct TestServer { POINTER_DEFINITIONS(TestServer); static TestServer::shared_pointer ctx; - epics::pvAccess::Configuration::shared_pointer conf; - ServerContextImpl::shared_pointer context; - Event startup; - epics::pvData::Thread runner; - MockChannelProviderFactory::shared_pointer factory; + ServerContext::shared_pointer context; TestServer(const epics::pvAccess::Configuration::shared_pointer& conf) - :conf(conf) - ,runner(epics::pvData::Thread::Config(this).name("TestServer").autostart(false)) - ,factory(new MockChannelProviderFactory()) { - registerChannelProviderFactory(factory); - - context = ServerContextImpl::create(conf); - context->initialize(getChannelProviderRegistry()); - } - void start(bool inSameThread = false) - { - if (inSameThread) - { - context->run(conf->getPropertyAsInteger("timeToRun", 0)); // default is no timeout - } - else - { - runner.start(); - startup.wait(); // wait for thread to start - } + ChannelProvider::shared_pointer prov(new MockServerChannelProvider); + static_cast(prov.get())->initialize(); + context = ServerContext::create(ServerContext::Config() + .config(conf) + .provider(prov)); } ~TestServer() { context->shutdown(); - runner.exitWait(); - context->destroy(); - - unregisterChannelProviderFactory(factory); structureChangedListeners.clear(); { @@ -2830,9 +2783,6 @@ struct TestServer : public Runnable } ctx.reset(); - unregisterChannelProviderFactory(factory); - - shutdownSimADCs(); } // Use with EPICS_PVA_SERVER_PORT==0 for dynamic port (unit-tests) @@ -2844,11 +2794,7 @@ struct TestServer : public Runnable { return context->getBroadcastPort(); } - virtual void run() - { - startup.signal(); - context->run(conf->getPropertyAsInteger("timeToRun", 0)); // default is no timeout - } + void waitForShutdown() { context->shutdown(); } @@ -2932,7 +2878,7 @@ int main(int argc, char *argv[]) .build())); TestServer::ctx = srv; srv->context->printInfo(); - srv->start(true); + srv->context->run(epics::pvData::castUnsafe(timeToRun)); cout << "Done" << endl; diff --git a/testApp/remote/testServerContext.cpp b/testApp/remote/testServerContext.cpp index 24332ed..786c87a 100644 --- a/testApp/remote/testServerContext.cpp +++ b/testApp/remote/testServerContext.cpp @@ -2,8 +2,11 @@ * testServerContext.cpp */ -#include +#include #include +#include + +#include using namespace epics::pvAccess; using namespace epics::pvData; @@ -17,7 +20,7 @@ public: return "local"; }; - TestChannelProvider(const std::tr1::shared_ptr&) {} + TestChannelProvider() {} ChannelFind::shared_pointer channelFind(std::string const & /*channelName*/, ChannelFindRequester::shared_pointer const & channelFindRequester) @@ -60,25 +63,27 @@ public: void testServerContext() { - ServerContextImpl::shared_pointer ctx = ServerContextImpl::create(); + ChannelProvider::shared_pointer prov(new TestChannelProvider); + ServerContext::shared_pointer ctx(ServerContext::create(ServerContext::Config() + .provider(prov))); + ServerContext::weak_pointer wctx(ctx); - ChannelProviderRegistry::shared_pointer ca(ChannelProviderRegistry::build()); - ca->add("local"); - ctx->initialize(ca); + testOk(ctx.unique(), "# ServerContext::create() returned non-unique instance use_count=%u", (unsigned)ctx.use_count()); ctx->printInfo(); ctx->run(1); - ctx->destroy(); + ctx.reset(); + + testOk(!wctx.lock(), "# ServerContext cleanup leaves use_count=%u", (unsigned)wctx.use_count()); } -int main() +MAIN(testServerContext) { + testPlan(0); + testServerContext(); - cout << "Done" << endl; - - //epicsExitCallAtExits(); - return (0); + return testDone(); } From 634e50e0115021a046c52ee39e2419c7e0252621 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 31 May 2017 12:18:42 +0200 Subject: [PATCH 021/189] startPVAServer() has to keep the pointer --- src/ioc/PVAServerRegister.cpp | 49 +++++++++++++++++++++++++---------- src/server/pv/serverContext.h | 3 +++ src/server/serverContext.cpp | 2 +- 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/src/ioc/PVAServerRegister.cpp b/src/ioc/PVAServerRegister.cpp index 94d2eec..c2cf898 100644 --- a/src/ioc/PVAServerRegister.cpp +++ b/src/ioc/PVAServerRegister.cpp @@ -34,8 +34,10 @@ using std::cout; using std::endl; -using namespace epics::pvData; -using namespace epics::pvAccess; +namespace pvd = epics::pvData; +namespace pva = epics::pvAccess; + +static pva::ServerContext::shared_pointer the_server; static const iocshArg startPVAServerArg0 = { "providerNames", iocshArgString }; static const iocshArg *startPVAServerArgs[] = { @@ -46,23 +48,44 @@ static const iocshFuncDef startPVAServerFuncDef = { }; static void startPVAServer(const iocshArgBuf *args) { - char *names = args[0].sval; - if(!names) { - startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true); - } else { - std::string providerNames(names); - startPVAServer(providerNames,0,true,true); + try { + if(the_server) { + std::cout<<"PVA server already running\n"; + return; + } + char *names = args[0].sval; + if(!names) { + the_server = pva::startPVAServer(pva::PVACCESS_ALL_PROVIDERS,0,true,true); + } else { + std::string providerNames(names); + the_server = pva::startPVAServer(providerNames,0,true,true); + } + }catch(std::exception& e){ + std::cout<<"Error: "< which will automatically shutdown() when the last reference is released. */ static ServerContext::shared_pointer create(const Config& conf = Config()); }; +// Caller must store the returned pointer to keep the server alive. epicsShareFunc ServerContext::shared_pointer startPVAServer( std::string const & providerNames = PVACCESS_ALL_PROVIDERS, int timeToRun = 0, diff --git a/src/server/serverContext.cpp b/src/server/serverContext.cpp index e735f79..d560dc3 100644 --- a/src/server/serverContext.cpp +++ b/src/server/serverContext.cpp @@ -476,7 +476,7 @@ ServerContext::shared_pointer startPVAServer(std::string const & providerNames, .config(ConfigurationBuilder() .add("EPICS_PVAS_PROVIDER_NAMES", providerNames) .push_map() - .push_env() + .push_env() // environment takes precidence (top of stack) .build()))); if(printInfo) ret->printInfo(); From e72396a022cb4d8088145233379fcbc8029a22e3 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 31 May 2017 13:01:52 +0200 Subject: [PATCH 022/189] auto-start PVA server w/ initHook split of this code into a new library pvAccessIOC which depends on all core libraries. --- Makefile | 3 ++ RELEASE_NOTES.md | 3 +- configure/CONFIG_SITE | 7 ++++ src/Makefile | 8 ----- src/ioc/Makefile | 9 +++-- src/ioc/PVAServerRegister.cpp | 64 +++++++++++++++++++++++++++++++---- 6 files changed, 76 insertions(+), 18 deletions(-) diff --git a/Makefile b/Makefile index c005d8f..e8b3912 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,9 @@ DIRS := configure DIRS += src src_DEPEND_DIRS = configure +DIRS += src/ioc +src/ioc_DEPEND_DIRS = src + DIRS += pvtoolsSrc pvtoolsSrc_DEPEND_DIRS = src diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 23bfdd2..d90f1e8 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,7 +1,8 @@ Release 5.x.x ========== -* +* Add new library pvAccessIOC for use with PVAClientRegister.dbd and PVAServerRegister.dbd. + Necessary to avoid having pvAccess library depend on all IOC core libraries. Release 5.0.0 ========== diff --git a/configure/CONFIG_SITE b/configure/CONFIG_SITE index 40db1d7..452b1eb 100644 --- a/configure/CONFIG_SITE +++ b/configure/CONFIG_SITE @@ -23,6 +23,13 @@ CHECK_RELEASE = YES -include $(TOP)/../CONFIG_SITE.local -include $(TOP)/configure/CONFIG_SITE.local +EPICS_PVA_MAJOR_VERSION = 5 +EPICS_PVA_MINOR_VERSION = 0 +EPICS_PVA_MAINTENANCE_VERSION = 1 +EPICS_PVA_DEVELOPMENT_FLAG = 1 + +SHRLIB_VERSION ?= $(EPICS_PVA_MAJOR_VERSION).$(EPICS_PVA_MINOR_VERSION).$(EPICS_PVA_MAINTENANCE_VERSION) + ifdef WITH_COVERAGE USR_CPPFLAGS += --coverage USR_LDFLAGS += --coverage diff --git a/src/Makefile b/src/Makefile index e00365e..631c60e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -3,11 +3,6 @@ TOP = .. include $(TOP)/configure/CONFIG -EPICS_PVA_MAJOR_VERSION = 5 -EPICS_PVA_MINOR_VERSION = 0 -EPICS_PVA_MAINTENANCE_VERSION = 1 -EPICS_PVA_DEVELOPMENT_FLAG = 1 - EXPANDVARS += EPICS_PVA_MAJOR_VERSION EXPANDVARS += EPICS_PVA_MINOR_VERSION EXPANDVARS += EPICS_PVA_MAINTENANCE_VERSION @@ -29,12 +24,9 @@ include $(PVACCESS_SRC)/rpcClient/Makefile include $(PVACCESS_SRC)/pipelineService/Makefile include $(PVACCESS_SRC)/ca/Makefile include $(PVACCESS_SRC)/mb/Makefile -include $(PVACCESS_SRC)/ioc/Makefile LIBRARY = pvAccess -SHRLIB_VERSION = $(EPICS_PVA_MAJOR_VERSION).$(EPICS_PVA_MINOR_VERSION).$(EPICS_PVA_MAINTENANCE_VERSION) - pvAccess_LIBS += pvData ifdef WITH_MICROBENCH pvAccess_LIBS += pvMB diff --git a/src/ioc/Makefile b/src/ioc/Makefile index 3873271..4812ae8 100644 --- a/src/ioc/Makefile +++ b/src/ioc/Makefile @@ -1,6 +1,7 @@ -# This is a Makefile fragment, see ../Makefile +TOP = ../.. +include $(TOP)/configure/CONFIG -SRC_DIRS += $(PVACCESS_SRC)/ioc +LIBRARY += pvAccessIOC INC += pv/syncChannelFind.h @@ -9,3 +10,7 @@ DBD += PVAClientRegister.dbd LIBSRCS += PVAServerRegister.cpp LIBSRCS += PVAClientRegister.cpp + +pvAccessIOC_LIBS += $(EPICS_BASE_IOC_LIBS) + +include $(TOP)/configure/RULES diff --git a/src/ioc/PVAServerRegister.cpp b/src/ioc/PVAServerRegister.cpp index c2cf898..e566ec0 100644 --- a/src/ioc/PVAServerRegister.cpp +++ b/src/ioc/PVAServerRegister.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -37,8 +38,21 @@ using std::endl; namespace pvd = epics::pvData; namespace pva = epics::pvAccess; +static pvd::Mutex the_server_lock; static pva::ServerContext::shared_pointer the_server; +static void startitup() { + the_server = pva::ServerContext::create(pva::ServerContext::Config() + .config(pva::ConfigurationBuilder() + // default to all providers instead of just "local" + .add("EPICS_PVA_PROVIDER_NAMES", pva::PVACCESS_ALL_PROVIDERS) + .push_map() + // prefer to use EPICS_PVA_PROVIDER_NAMES or EPICS_PVAS_PROVIDER_NAMES + // from environment + .push_env() + .build())); +} + static const iocshArg startPVAServerArg0 = { "providerNames", iocshArgString }; static const iocshArg *startPVAServerArgs[] = { &startPVAServerArg0}; @@ -49,17 +63,19 @@ static const iocshFuncDef startPVAServerFuncDef = { static void startPVAServer(const iocshArgBuf *args) { 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" + " epicsEnvSet(\"EPICS_PVAS_PROVIDER_NAMES\", \"%s\")\n", + names); + } + pvd::Lock G(the_server_lock); if(the_server) { std::cout<<"PVA server already running\n"; return; } - char *names = args[0].sval; - if(!names) { - the_server = pva::startPVAServer(pva::PVACCESS_ALL_PROVIDERS,0,true,true); - } else { - std::string providerNames(names); - the_server = pva::startPVAServer(providerNames,0,true,true); - } + startitup(); }catch(std::exception& e){ std::cout<<"Error: "<printInfo(); + } + }catch(std::exception& e){ + std::cout<<"Error: "< Date: Wed, 31 May 2017 13:09:21 +0200 Subject: [PATCH 023/189] AbstractCodec pure virtual redundant to Transport::close()=0 --- src/remote/pv/codec.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/remote/pv/codec.h b/src/remote/pv/codec.h index e1727af..c9480cf 100644 --- a/src/remote/pv/codec.h +++ b/src/remote/pv/codec.h @@ -192,7 +192,6 @@ public: virtual int write(epics::pvData::ByteBuffer* src) = 0; virtual int read(epics::pvData::ByteBuffer* dst) = 0; virtual bool isOpen() = 0; - virtual void close() = 0; virtual ~AbstractCodec() From 3ad27665e859df663e5694f68d278427b5643108 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 31 May 2017 15:47:46 +0200 Subject: [PATCH 024/189] BlockingTCPTransportCodec::close() wait for threads --- src/remote/codec.cpp | 6 ++++++ src/server/serverContext.cpp | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/src/remote/codec.cpp b/src/remote/codec.cpp index 0b586c5..6889761 100644 --- a/src/remote/codec.cpp +++ b/src/remote/codec.cpp @@ -1032,6 +1032,12 @@ void BlockingTCPTransportCodec::close() { // post close internalPostClose(true); + + // wait for threads + if(!_sendThread.isCurrentThread()) + _sendThread.exitWait(); + if(!_readThread.isCurrentThread()) + _readThread.exitWait(); } } diff --git a/src/server/serverContext.cpp b/src/server/serverContext.cpp index d560dc3..3fe7e26 100644 --- a/src/server/serverContext.cpp +++ b/src/server/serverContext.cpp @@ -306,6 +306,10 @@ void ServerContextImpl::destroyAllTransports() try { transport->close(); + if(!transport.unique()) + LOG(logLevelError, "Closed transport %s still has use_count=%u", + transport->getRemoteName().c_str(), + (unsigned)transport.use_count()); } catch (std::exception &e) { From 3fa6a4e4cc7e620bb7166b135b729042652a1eef Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 31 May 2017 15:48:30 +0200 Subject: [PATCH 025/189] TransportRegistry composed no need for a seperate allocation and shared_ptr --- src/remote/pv/remote.h | 2 +- src/remoteClient/clientContextImpl.cpp | 13 ++++++------- src/server/pv/serverContextImpl.h | 4 ++-- src/server/serverContext.cpp | 15 ++++----------- 4 files changed, 13 insertions(+), 21 deletions(-) diff --git a/src/remote/pv/remote.h b/src/remote/pv/remote.h index ce4d2b5..8c50c2f 100644 --- a/src/remote/pv/remote.h +++ b/src/remote/pv/remote.h @@ -323,7 +323,7 @@ public: virtual epics::pvData::Timer::shared_pointer getTimer() = 0; //virtual TransportRegistry::shared_pointer getTransportRegistry() = 0; - virtual std::tr1::shared_ptr getTransportRegistry() = 0; + virtual TransportRegistry* getTransportRegistry() = 0; diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 0104ee0..71ef89e 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -4313,9 +4313,9 @@ public: return m_timer; } - virtual TransportRegistry::shared_pointer getTransportRegistry() + virtual TransportRegistry* getTransportRegistry() { - return m_transportRegistry; + return &m_transportRegistry; } virtual Transport::shared_pointer getSearchTransport() @@ -4422,7 +4422,6 @@ private: m_timer.reset(new Timer("pvAccess-client timer", lowPriority)); Context::shared_pointer thisPointer = shared_from_this(); m_connector.reset(new BlockingTCPConnector(thisPointer, m_receiveBufferSize, m_connectionTimeout)); - m_transportRegistry.reset(new TransportRegistry()); m_responseHandler.reset(new ClientResponseHandler(shared_from_this())); @@ -4489,7 +4488,7 @@ private: // wait for all transports to cleanly exit int tries = 40; epics::pvData::int32 transportCount; - while ((transportCount = m_transportRegistry->numberOfActiveTransports()) && tries--) + while ((transportCount = m_transportRegistry.numberOfActiveTransports()) && tries--) epicsThreadSleep(0.025); if (transportCount) @@ -4790,7 +4789,7 @@ private: virtual void configure(epics::pvData::PVStructure::shared_pointer configuration) { // remove? - if (m_transportRegistry->numberOfActiveTransports() > 0) + if (m_transportRegistry.numberOfActiveTransports() > 0) throw std::runtime_error("Configure must be called when there is no transports active."); PVInt::shared_pointer pvStrategy = dynamic_pointer_cast(configuration->getSubField("strategy")); @@ -4814,7 +4813,7 @@ private: virtual void flush() { - m_transportRegistry->toArray(m_flushTransports); + m_transportRegistry.toArray(m_flushTransports); TransportRegistry::transportVector_t::const_iterator iter = m_flushTransports.begin(); while (iter != m_flushTransports.end()) (*iter++)->flushSendQueue(); @@ -4897,7 +4896,7 @@ private: * PVA transport (virtual circuit) registry. * This registry contains all active transports - connections to PVA servers. */ - TransportRegistry::shared_pointer m_transportRegistry; + TransportRegistry m_transportRegistry; /** * Response handler. diff --git a/src/server/pv/serverContextImpl.h b/src/server/pv/serverContextImpl.h index b6fef86..363eb06 100644 --- a/src/server/pv/serverContextImpl.h +++ b/src/server/pv/serverContextImpl.h @@ -37,7 +37,7 @@ public: Channel::shared_pointer getChannel(pvAccessID id); Transport::shared_pointer getSearchTransport(); Configuration::const_shared_pointer getConfiguration(); - TransportRegistry::shared_pointer getTransportRegistry(); + TransportRegistry* getTransportRegistry(); std::map >& getSecurityPlugins(); virtual void newServerDetected(); @@ -203,7 +203,7 @@ private: * PVA transport (virtual circuit) registry. * This registry contains all active transports - connections to PVA servers. */ - TransportRegistry::shared_pointer _transportRegistry; + TransportRegistry _transportRegistry; /** * Response handler. diff --git a/src/server/serverContext.cpp b/src/server/serverContext.cpp index 3fe7e26..573a429 100644 --- a/src/server/serverContext.cpp +++ b/src/server/serverContext.cpp @@ -212,7 +212,6 @@ void ServerContextImpl::initialize() //osiSockAttach(); _timer.reset(new Timer("pvAccess-server timer", lowerPriority)); - _transportRegistry.reset(new TransportRegistry()); ServerContextImpl::shared_pointer thisServerContext = shared_from_this(); _responseHandler.reset(new ServerResponseHandler(thisServerContext)); @@ -284,13 +283,7 @@ void ServerContextImpl::shutdown() void ServerContextImpl::destroyAllTransports() { - // not initialized yet - if (!_transportRegistry.get()) - { - return; - } - - std::auto_ptr transports = _transportRegistry->toArray(); + std::auto_ptr transports = _transportRegistry.toArray(); if (transports.get() == 0) return; @@ -324,7 +317,7 @@ void ServerContextImpl::destroyAllTransports() } // now clear all (release) - _transportRegistry->clear(); + _transportRegistry.clear(); } @@ -439,9 +432,9 @@ Timer::shared_pointer ServerContextImpl::getTimer() return _timer; } -TransportRegistry::shared_pointer ServerContextImpl::getTransportRegistry() +epics::pvAccess::TransportRegistry* ServerContextImpl::getTransportRegistry() { - return _transportRegistry; + return &_transportRegistry; } Channel::shared_pointer ServerContextImpl::getChannel(pvAccessID /*id*/) From 8971d2771ce6e7a1accae53466948d512df2e4b1 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 31 May 2017 15:58:15 +0200 Subject: [PATCH 026/189] ServerContextImpl::destroyAllTransports() Better check for ref. leaks --- src/server/serverContext.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/server/serverContext.cpp b/src/server/serverContext.cpp index 573a429..3e81728 100644 --- a/src/server/serverContext.cpp +++ b/src/server/serverContext.cpp @@ -282,27 +282,21 @@ void ServerContextImpl::shutdown() void ServerContextImpl::destroyAllTransports() { + TransportRegistry::transportVector_t transports; + _transportRegistry.toArray(transports); - std::auto_ptr transports = _transportRegistry.toArray(); - if (transports.get() == 0) - return; - - int size = (int)transports->size(); + size_t size = transports.size(); if (size == 0) return; LOG(logLevelInfo, "Server context still has %d transport(s) active and closing...", size); - for (int i = 0; i < size; i++) + for (size_t i = 0; i < size; i++) { - Transport::shared_pointer transport = (*transports)[i]; + const Transport::shared_pointer& transport = transports[i]; try { transport->close(); - if(!transport.unique()) - LOG(logLevelError, "Closed transport %s still has use_count=%u", - transport->getRemoteName().c_str(), - (unsigned)transport.use_count()); } catch (std::exception &e) { @@ -319,6 +313,14 @@ void ServerContextImpl::destroyAllTransports() // now clear all (release) _transportRegistry.clear(); + for (size_t i = 0; i < size; i++) + { + const Transport::shared_pointer& transport = transports[i]; + if(!transport.unique()) + LOG(logLevelError, "Closed transport %s still has use_count=%u", + transport->getRemoteName().c_str(), + (unsigned)transport.use_count()); + } } void ServerContext::printInfo() From 65cdff288fa97a819958ffdd53632bcb0e511504 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 1 Jun 2017 01:54:17 +0200 Subject: [PATCH 027/189] Configuration list keys --- src/utils/configuration.cpp | 12 ++++++++++++ src/utils/pv/configuration.h | 15 +++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/utils/configuration.cpp b/src/utils/configuration.cpp index b0f75eb..d715424 100644 --- a/src/utils/configuration.cpp +++ b/src/utils/configuration.cpp @@ -110,6 +110,12 @@ bool ConfigurationMap::tryGetPropertyAsString(const std::string& name, std::stri return true; } +void ConfigurationMap::addKeys(keys_t& names) const +{ + for(properties_t::const_iterator it=properties.begin(); it!=properties.end(); ++it) + names.insert(it->first); +} + bool ConfigurationEnviron::tryGetPropertyAsString(const std::string& name, std::string* val) const { const char *env = getenv(name.c_str()); @@ -132,6 +138,12 @@ bool ConfigurationStack::tryGetPropertyAsString(const std::string& name, std::st return false; } +void ConfigurationStack::addKeys(keys_t& names) const +{ + for(confs_t::const_iterator it=confs.begin(); it!=confs.end(); ++it) + (*it)->addKeys(names); +} + ConfigurationBuilder::ConfigurationBuilder() :stack(new ConfigurationStack) {} ConfigurationBuilder& ConfigurationBuilder::push_env() diff --git a/src/utils/pv/configuration.h b/src/utils/pv/configuration.h index 34cf8d3..2ec6894 100644 --- a/src/utils/pv/configuration.h +++ b/src/utils/pv/configuration.h @@ -12,6 +12,7 @@ #include #include #include +#include #ifdef epicsExportSharedSymbols # define configurationEpicsExportSharedSymbols @@ -114,9 +115,21 @@ public: bool hasProperty(const std::string &name) const; + typedef std::set keys_t; + /** Return a (partial) list of available key names. + * Does not include key names from the ConfigurationEnviron + */ + keys_t keys() const + { + keys_t ret; + addKeys(ret); + return ret; + } + protected: friend class ConfigurationStack; virtual bool tryGetPropertyAsString(const std::string& name, std::string* val) const = 0; + virtual void addKeys(keys_t&) const {} }; //! Lookup configuration strings from an in memory store @@ -129,6 +142,7 @@ public: ConfigurationMap(const properties_t& p) :properties(p) {} private: virtual bool tryGetPropertyAsString(const std::string& name, std::string* val) const; + virtual void addKeys(keys_t&) const; }; //! Lookup configuration strings from the process environment @@ -147,6 +161,7 @@ class epicsShareClass ConfigurationStack : public Configuration typedef std::vector > confs_t; confs_t confs; virtual bool tryGetPropertyAsString(const std::string& name, std::string* val) const; + virtual void addKeys(keys_t&) const; public: inline void push_back(const confs_t::value_type& conf) { confs.push_back(conf); From 48b3b648efbecdcedce8bb973c64493356b4dc89 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 1 Jun 2017 01:56:46 +0200 Subject: [PATCH 028/189] add ServerContext::getCurrentConfig() --- src/server/pv/serverContext.h | 5 ++++ src/server/pv/serverContextImpl.h | 1 + src/server/serverContext.cpp | 49 +++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/src/server/pv/serverContext.h b/src/server/pv/serverContext.h index 53c7f7b..c89776c 100644 --- a/src/server/pv/serverContext.h +++ b/src/server/pv/serverContext.h @@ -85,6 +85,11 @@ public: */ virtual epics::pvData::int32 getBroadcastPort() = 0; + /** Return a Configuration with the actual values being used, + * including defaults used, and bounds limits applied. + */ + virtual Configuration::shared_pointer getCurrentConfig() = 0; + // ************************************************************************** // // **************************** [ Plugins ] ********************************* // // ************************************************************************** // diff --git a/src/server/pv/serverContextImpl.h b/src/server/pv/serverContextImpl.h index 363eb06..4085653 100644 --- a/src/server/pv/serverContextImpl.h +++ b/src/server/pv/serverContextImpl.h @@ -45,6 +45,7 @@ public: epicsTimeStamp& getStartTime(); + virtual Configuration::shared_pointer getCurrentConfig(); /** * Version. diff --git a/src/server/serverContext.cpp b/src/server/serverContext.cpp index 3e81728..5c49cd3 100644 --- a/src/server/serverContext.cpp +++ b/src/server/serverContext.cpp @@ -198,6 +198,55 @@ void ServerContextImpl::loadConfiguration() epicsSocketDestroy(sock); } +Configuration::shared_pointer +ServerContextImpl::getCurrentConfig() +{ + ConfigurationBuilder B; + + std::ostringstream providerName; + for(size_t i=0; i<_channelProviders.size(); i++) { + if(i>0) + providerName<<" "; + providerName<<_channelProviders[i]->getProviderName(); + } + +#define SET(K, V) B.add(K, V); + + { + char buf[50]; + ipAddrToA(&_ifaceAddr.ia, buf, sizeof(buf)); + buf[sizeof(buf)-1] = '\0'; + SET("EPICS_PVAS_INTF_ADDR_LIST", buf); + } + + SET("EPICS_PVAS_BEACON_ADDR_LIST", getBeaconAddressList()); + SET("EPICS_PVA_ADDR_LIST", getBeaconAddressList()); + + SET("EPICS_PVAS_AUTO_BEACON_ADDR_LIST", + isAutoBeaconAddressList() ? "YES" : "NO"); + SET("EPICS_PVA_AUTO_ADDR_LIST", + isAutoBeaconAddressList() ? "YES" : "NO"); + + SET("EPICS_PVAS_BEACON_PERIOD", getBeaconPeriod()); + SET("EPICS_PVA_BEACON_PERIOD", getBeaconPeriod()); + + SET("EPICS_PVAS_SERVER_PORT", getServerPort()); + SET("EPICS_PVA_SERVER_PORT", getServerPort()); + + SET("EPICS_PVAS_BROADCAST_PORT", getBroadcastPort()); + SET("EPICS_PVA_BROADCAST_PORT", getBroadcastPort()); + + SET("EPICS_PVAS_MAX_ARRAY_BYTES", getReceiveBufferSize()); + SET("EPICS_PVA_MAX_ARRAY_BYTES", getReceiveBufferSize()); + + SET("EPICS_PVAS_PROVIDER_NAMES", providerName.str()); + SET("EPICS_PVA_PROVIDER_NAMES", providerName.str()); + +#undef SET + + return B.push_map().build(); +} + bool ServerContextImpl::isChannelProviderNamePreconfigured() { Configuration::const_shared_pointer config = getConfiguration(); From 4b873fa01511cb3ecc25e83e46aec455118cc44e Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 1 Jun 2017 01:57:30 +0200 Subject: [PATCH 029/189] PVAClientRegister: automatically register "pva" provider --- src/ioc/PVAClientRegister.cpp | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/ioc/PVAClientRegister.cpp b/src/ioc/PVAClientRegister.cpp index f3cafc2..c199d43 100644 --- a/src/ioc/PVAClientRegister.cpp +++ b/src/ioc/PVAClientRegister.cpp @@ -27,29 +27,17 @@ #include #include -using std::cout; -using std::endl; -using namespace epics::pvData; using namespace epics::pvAccess; - -static const iocshFuncDef startPVAClientFuncDef = { - "startPVAClient", 0, 0 -}; - -extern "C" void startPVAClient(const iocshArgBuf *args) +static void stopPVAClient(void*) { - ClientFactory::start(); + ClientFactory::stop(); } - static void registerStartPVAClient(void) { - static int firstTime = 1; - if (firstTime) { - firstTime = 0; - iocshRegister(&startPVAClientFuncDef, startPVAClient); - } + ClientFactory::start(); + epicsAtExit(stopPVAClient, 0); } From 8859c4d4710d977dc231e1fba7465951d2c44991 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 2 Jun 2017 11:25:04 +0200 Subject: [PATCH 030/189] blockingUDPTransport really join thread --- src/remote/blockingUDPTransport.cpp | 4 +--- src/remote/pv/blockingUDP.h | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/remote/blockingUDPTransport.cpp b/src/remote/blockingUDPTransport.cpp index 80f42f7..e8fc8e3 100644 --- a/src/remote/blockingUDPTransport.cpp +++ b/src/remote/blockingUDPTransport.cpp @@ -163,7 +163,7 @@ void BlockingUDPTransport::close(bool waitForThreadToComplete) { // wait for send thread to exit cleanly if (_thread.get() && waitForThreadToComplete) { - if (!_shutdownEvent.wait(5.0)) + if (!_thread->exitWait(5.0)) { LOG(logLevelError, "Receive thread for UDP socket %s has not exited.", @@ -302,8 +302,6 @@ void BlockingUDPTransport::run() { string threadName = "UDP-rx "+inetAddressToString(_bindAddress); LOG(logLevelTrace, "Thread '%s' exiting.", threadName.c_str()); } - - _shutdownEvent.signal(); } bool BlockingUDPTransport::processBuffer(Transport::shared_pointer const & transport, diff --git a/src/remote/pv/blockingUDP.h b/src/remote/pv/blockingUDP.h index 7e57250..ba3d79a 100644 --- a/src/remote/pv/blockingUDP.h +++ b/src/remote/pv/blockingUDP.h @@ -448,7 +448,6 @@ private: */ epics::pvData::Mutex _mutex; epics::pvData::Mutex _sendMutex; - epics::pvData::Event _shutdownEvent; /** * Thread ID From 11cc395bafb5c47ffecade21758b8e333d63aaac Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 2 Jun 2017 12:30:40 +0200 Subject: [PATCH 031/189] more BlockingTCPTransportCodec::close() wait for threads can't wait here as locks are held --- src/remote/codec.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/remote/codec.cpp b/src/remote/codec.cpp index 6889761..0b586c5 100644 --- a/src/remote/codec.cpp +++ b/src/remote/codec.cpp @@ -1032,12 +1032,6 @@ void BlockingTCPTransportCodec::close() { // post close internalPostClose(true); - - // wait for threads - if(!_sendThread.isCurrentThread()) - _sendThread.exitWait(); - if(!_readThread.isCurrentThread()) - _readThread.exitWait(); } } From 6fcfd60bd50092e2263dd00c1cb1cbce68c0f7fd Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 2 Jun 2017 12:32:12 +0200 Subject: [PATCH 032/189] BlockingUDPTransport wrap close() to break ref. loop --- src/remote/blockingUDPConnector.cpp | 21 ++++++++++++++++++++- src/remote/pv/blockingUDP.h | 5 +++++ src/server/serverContext.cpp | 1 + 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/remote/blockingUDPConnector.cpp b/src/remote/blockingUDPConnector.cpp index 44a447c..818c082 100644 --- a/src/remote/blockingUDPConnector.cpp +++ b/src/remote/blockingUDPConnector.cpp @@ -16,6 +16,22 @@ using namespace std; using namespace epics::pvData; +namespace { +struct closer { + epics::pvAccess::Transport::shared_pointer P; + closer(const epics::pvAccess::Transport::shared_pointer& P) :P(P) {} + void operator()(epics::pvAccess::Transport*) { + try{ + P->close(); + }catch(...){ + P.reset(); + throw; + } + P.reset(); + } +}; +} + namespace epics { namespace pvAccess { @@ -72,7 +88,10 @@ Transport::shared_pointer BlockingUDPConnector::connect(TransportClient::shared_ BlockingUDPTransport::shared_pointer transport(new BlockingUDPTransport(_serverFlag, responseHandler, socket, bindAddress, transportRevision)); - return Transport::shared_pointer(transport); + // the worker thread holds a strong ref, which is released by transport->close() + Transport::shared_pointer ret(transport.get(), closer(transport)); + + return ret; } } diff --git a/src/remote/pv/blockingUDP.h b/src/remote/pv/blockingUDP.h index ba3d79a..dbbd310 100644 --- a/src/remote/pv/blockingUDP.h +++ b/src/remote/pv/blockingUDP.h @@ -35,6 +35,8 @@ namespace epics { namespace pvAccess { +class BlockingUDPConnector; + enum InetAddressType { inetAddressType_all, inetAddressType_unicast, inetAddressType_broadcast_multicast }; class BlockingUDPTransport : public epics::pvData::NoDefaultMethods, @@ -46,10 +48,13 @@ class BlockingUDPTransport : public epics::pvData::NoDefaultMethods, public: POINTER_DEFINITIONS(BlockingUDPTransport); +private: + friend class BlockingUDPConnector; BlockingUDPTransport(bool serverFlag, ResponseHandler::shared_pointer const & responseHandler, SOCKET channel, osiSockAddr &bindAddress, short remoteTransportRevision); +public: static shared_pointer create(bool serverFlag, ResponseHandler::shared_pointer const & responseHandler, diff --git a/src/server/serverContext.cpp b/src/server/serverContext.cpp index 5c49cd3..9b128ce 100644 --- a/src/server/serverContext.cpp +++ b/src/server/serverContext.cpp @@ -263,6 +263,7 @@ void ServerContextImpl::initialize() _timer.reset(new Timer("pvAccess-server timer", lowerPriority)); ServerContextImpl::shared_pointer thisServerContext = shared_from_this(); + // we create reference cycles here which are broken by our shutdown() method, _responseHandler.reset(new ServerResponseHandler(thisServerContext)); _acceptor.reset(new BlockingTCPAcceptor(thisServerContext, _responseHandler, _ifaceAddr, _receiveBufferSize)); From f8c8925b834b0708a08476f5c5f1a67ae6ef2393 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 6 Jun 2017 08:18:13 +0200 Subject: [PATCH 033/189] don't swallow exception --- src/remoteClient/clientContextImpl.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 71ef89e..87ebbaa 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -4712,10 +4712,9 @@ private: //static_pointer_cast(t)->setFlushStrategy(m_flushStrategy); return t; } - catch (...) + catch (std::exception& e) { - // TODO log - //printf("failed to get transport\n"); + LOG(logLevelError, "getTransport() fails: %s\n", e.what()); return Transport::shared_pointer(); } } From 860054a7a2aad94b4b89a70e07415e8b7265a0ba Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 6 Jun 2017 08:28:08 +0200 Subject: [PATCH 034/189] ChannelProviderRegistry update add()/remove() add() return created SimpleChannelProviderFactory instance. remove() missing Lock and remove by instance as well as by name. --- src/client/pv/pvAccess.h | 9 ++++++--- src/factory/ChannelAccessFactory.cpp | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/client/pv/pvAccess.h b/src/client/pv/pvAccess.h index e208845..d43711a 100644 --- a/src/client/pv/pvAccess.h +++ b/src/client/pv/pvAccess.h @@ -1237,16 +1237,19 @@ public: //! Add a new Provider which will be built using SimpleChannelProviderFactory template - bool add(const std::string& name, bool replace=true) + ChannelProviderFactory::shared_pointer add(const std::string& name, bool replace=true) { typedef SimpleChannelProviderFactory Factory; typename Factory::shared_pointer fact(new Factory(name)); - return add(fact, replace); + return add(fact, replace) ? fact : typename Factory::shared_pointer(); } - //! Attempt to remove named factory. Return Factory which was removed, or NULL if not found. + //! Attempt to remove a factory with the given name. Return Factory which was removed, or NULL if not found. ChannelProviderFactory::shared_pointer remove(const std::string& name); + //! Attempt to remove a factory. Return true if Factory was previously registered, and now removed. + bool remove(const ChannelProviderFactory::shared_pointer& factory); + //! Drop all factories void clear() { diff --git a/src/factory/ChannelAccessFactory.cpp b/src/factory/ChannelAccessFactory.cpp index 150b5ea..f510fb8 100644 --- a/src/factory/ChannelAccessFactory.cpp +++ b/src/factory/ChannelAccessFactory.cpp @@ -69,6 +69,7 @@ std::auto_ptr ChannelProviderRegistry:: bool ChannelProviderRegistry::add(const ChannelProviderFactory::shared_pointer& fact, bool replace) { + assert(fact); Lock G(mutex); std::string name(fact->getFactoryName()); if(!replace && providers.find(name)!=providers.end()) @@ -79,6 +80,7 @@ bool ChannelProviderRegistry::add(const ChannelProviderFactory::shared_pointer& ChannelProviderFactory::shared_pointer ChannelProviderRegistry::remove(const std::string& name) { + Lock G(mutex); ChannelProviderFactory::shared_pointer ret; providers_t::iterator iter(providers.find(name)); if(iter!=providers.end()) { @@ -88,6 +90,18 @@ ChannelProviderFactory::shared_pointer ChannelProviderRegistry::remove(const std return ret; } +bool ChannelProviderRegistry::remove(const ChannelProviderFactory::shared_pointer& fact) +{ + assert(fact); + Lock G(mutex); + providers_t::iterator iter(providers.find(fact->getFactoryName())); + if(iter!=providers.end() && iter->second==fact) { + providers.erase(iter); + return true; + } + return false; +} + ChannelProviderRegistry::shared_pointer getChannelProviderRegistry() { static Mutex mutex; static ChannelProviderRegistry::shared_pointer global_reg; From 34eeb0717a309c88e94842d0a4ff265cfe745dbb Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 6 Jun 2017 08:50:57 +0200 Subject: [PATCH 035/189] SimpleChannelProviderFactory: weak_ptr to shared instance --- src/client/pv/pvAccess.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/client/pv/pvAccess.h b/src/client/pv/pvAccess.h index d43711a..9e670ba 100644 --- a/src/client/pv/pvAccess.h +++ b/src/client/pv/pvAccess.h @@ -1162,11 +1162,12 @@ struct SimpleChannelProviderFactory : public ChannelProviderFactory virtual ChannelProvider::shared_pointer sharedInstance() { epics::pvData::Lock L(sharedM); - if(!shared) { - std::tr1::shared_ptr empty; - shared.reset(new Provider(empty)); + ChannelProvider::shared_pointer ret(shared.lock()); + if(!ret) { + ret.reset(new Provider(std::tr1::shared_ptr())); + shared = ret; } - return shared; + return ret; } virtual ChannelProvider::shared_pointer newInstance(const std::tr1::shared_ptr& conf) @@ -1178,7 +1179,7 @@ struct SimpleChannelProviderFactory : public ChannelProviderFactory private: const std::string pname; epics::pvData::Mutex sharedM; - std::tr1::shared_ptr shared; + ChannelProvider::weak_pointer shared; }; /** From 6926d911eeb1b8ccb4da14ed7717f381379a7434 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 6 Jun 2017 08:35:03 +0200 Subject: [PATCH 036/189] caProvider: init issues avoid static init order issues ref. count to allow multiple calls to CAClientFactory::start() --- src/ca/caProvider.cpp | 113 +++++++++++++---------------------------- src/ca/pv/caProvider.h | 4 +- 2 files changed, 37 insertions(+), 80 deletions(-) diff --git a/src/ca/caProvider.cpp b/src/ca/caProvider.cpp index f3765ef..dc2a329 100644 --- a/src/ca/caProvider.cpp +++ b/src/ca/caProvider.cpp @@ -9,9 +9,11 @@ /* for CA */ #include #include +#include #define epicsExportSharedSymbols #include +#include #include #include @@ -23,13 +25,20 @@ using namespace epics::pvAccess::ca; 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__); } -std::string CAChannelProvider::PROVIDER_NAME = "ca"; - CAChannelProvider::CAChannelProvider() : current_context(0), destroyed(false) { initialize(); } +CAChannelProvider::CAChannelProvider(const std::tr1::shared_ptr&) + : current_context(0) + , destroyed(false) +{ + // Ignoring Configuration as CA only allows config via. environment, + // and we don't want to change this here. + initialize(); +} + CAChannelProvider::~CAChannelProvider() { // call destroy() to destroy CA context @@ -38,7 +47,7 @@ CAChannelProvider::~CAChannelProvider() std::string CAChannelProvider::getProviderName() { - return PROVIDER_NAME; + return "ca"; } ChannelFind::shared_pointer CAChannelProvider::channelFind( @@ -165,94 +174,42 @@ void CAChannelProvider::initialize() } +static epicsThreadOnceId cafactory_once = EPICS_THREAD_ONCE_INIT; +static struct cafactory_gbl_t { + Mutex mutex; + int count; + cafactory_gbl_t() :count(0u) {} +} *cafactory_gbl; - - - - - - - - -// TODO global static variable (de/initialization order not guaranteed) -static Mutex mutex; -static CAChannelProvider::shared_pointer sharedProvider; - -class CAChannelProviderFactoryImpl : public ChannelProviderFactory +static +void cafactory_init(void*) { -public: - POINTER_DEFINITIONS(CAChannelProviderFactoryImpl); - - virtual std::string getFactoryName() - { - return CAChannelProvider::PROVIDER_NAME; - } - - virtual ChannelProvider::shared_pointer sharedInstance() - { - Lock guard(mutex); - if (!sharedProvider.get()) - { - try { - // TODO use std::make_shared - std::tr1::shared_ptr tp(new CAChannelProvider()); - sharedProvider = tp; - } catch (std::exception &e) { - LOG(logLevelError, "Unhandled exception caught at %s:%d: %s", __FILE__, __LINE__, e.what()); - } catch (...) { - LOG(logLevelError, "Unhandled exception caught at %s:%d.", __FILE__, __LINE__); - } - } - return sharedProvider; - } - - virtual ChannelProvider::shared_pointer newInstance(const std::tr1::shared_ptr& conf) - { - // Ignoring configuration as CA only allows config via. environment, - // and we don't want to change this here. - try { - // TODO use std::make_shared - std::tr1::shared_ptr tp(new CAChannelProvider()); - ChannelProvider::shared_pointer ni = tp; - return ni; - } catch (std::exception &e) { - LOG(logLevelError, "Unhandled exception caught at %s:%d: %s", __FILE__, __LINE__, e.what()); - return ChannelProvider::shared_pointer(); - } catch (...) { - LOG(logLevelError, "Unhandled exception caught at %s:%d.", __FILE__, __LINE__); - return ChannelProvider::shared_pointer(); - } - } - - void destroySharedInstance() - { - if(!sharedProvider) return; - sharedProvider->destroy(); - sharedProvider.reset(); - } -}; - -static CAChannelProviderFactoryImpl::shared_pointer factory; + cafactory_gbl = new cafactory_gbl_t; +} void CAClientFactory::start() { epicsSignalInstallSigAlarmIgnore(); epicsSignalInstallSigPipeIgnore(); - Lock guard(mutex); - if (!factory.get()) - factory.reset(new CAChannelProviderFactoryImpl()); + epicsThreadOnce(&cafactory_once, &cafactory_init, 0); - registerChannelProviderFactory(factory); + Lock guard(cafactory_gbl->mutex); + if(cafactory_gbl->count++==0) { + if(!getChannelProviderRegistry()->add("ca", false)) + LOG(logLevelError, "Unable to register \"ca\" provider\n"); + } } void CAClientFactory::stop() { - Lock guard(mutex); + epicsThreadOnce(&cafactory_once, &cafactory_init, 0); - if (factory.get()) - { - unregisterChannelProviderFactory(factory); - factory->destroySharedInstance(); + Lock guard(cafactory_gbl->mutex); + + if(--cafactory_gbl->count==0) { + getChannelProviderRegistry()->remove("ca"); } + if(cafactory_gbl->count<0) + LOG(logLevelError, "too many calls to CAClientFactory::stop()"); } diff --git a/src/ca/pv/caProvider.h b/src/ca/pv/caProvider.h index 775ded4..d4593dd 100644 --- a/src/ca/pv/caProvider.h +++ b/src/ca/pv/caProvider.h @@ -16,6 +16,7 @@ namespace epics { namespace pvAccess { +class Configuration; namespace ca { class epicsShareClass CAChannelProvider : @@ -25,9 +26,8 @@ class epicsShareClass CAChannelProvider : public: POINTER_DEFINITIONS(CAChannelProvider); - static std::string PROVIDER_NAME; - CAChannelProvider(); + CAChannelProvider(const std::tr1::shared_ptr&); virtual ~CAChannelProvider(); /* --------------- epics::pvAccess::ChannelProvider --------------- */ From de84fadeb75d4bd2bfbbe653a4c488b8be162d50 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 6 Jun 2017 10:35:13 +0200 Subject: [PATCH 037/189] ChannelProviderRegistry::add w/ factory function --- src/client/pv/pvAccess.h | 4 +++ src/factory/ChannelAccessFactory.cpp | 38 ++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/client/pv/pvAccess.h b/src/client/pv/pvAccess.h index 9e670ba..9463b8f 100644 --- a/src/client/pv/pvAccess.h +++ b/src/client/pv/pvAccess.h @@ -1245,6 +1245,10 @@ public: return add(fact, replace) ? fact : typename Factory::shared_pointer(); } + typedef ChannelProvider::shared_pointer (*factoryfn_t)(const std::tr1::shared_ptr&); + + ChannelProviderFactory::shared_pointer add(const std::string& name, factoryfn_t, bool replace=true); + //! Attempt to remove a factory with the given name. Return Factory which was removed, or NULL if not found. ChannelProviderFactory::shared_pointer remove(const std::string& name); diff --git a/src/factory/ChannelAccessFactory.cpp b/src/factory/ChannelAccessFactory.cpp index f510fb8..3762c20 100644 --- a/src/factory/ChannelAccessFactory.cpp +++ b/src/factory/ChannelAccessFactory.cpp @@ -78,6 +78,44 @@ bool ChannelProviderRegistry::add(const ChannelProviderFactory::shared_pointer& return true; } +namespace { +struct FunctionFactory : public ChannelProviderFactory { + const std::string pname; + epics::pvData::Mutex sharedM; + ChannelProvider::weak_pointer shared; + const ChannelProviderRegistry::factoryfn_t fn; + + FunctionFactory(const std::string& name, ChannelProviderRegistry::factoryfn_t fn) + :pname(name), fn(fn) + {} + virtual ~FunctionFactory() {} + virtual std::string getFactoryName() { return pname; } + + virtual ChannelProvider::shared_pointer sharedInstance() + { + epics::pvData::Lock L(sharedM); + ChannelProvider::shared_pointer ret(shared.lock()); + if(!ret) { + ret = fn(std::tr1::shared_ptr()); + shared = ret; + } + return ret; + } + + virtual ChannelProvider::shared_pointer newInstance(const std::tr1::shared_ptr& conf) + { + return fn(conf); + } + +}; +}//namespace + +ChannelProviderFactory::shared_pointer ChannelProviderRegistry::add(const std::string& name, factoryfn_t fn, bool replace) +{ + ChannelProviderFactory::shared_pointer F(new FunctionFactory(name, fn)); + return add(F, replace) ? F : ChannelProviderFactory::shared_pointer(); +} + ChannelProviderFactory::shared_pointer ChannelProviderRegistry::remove(const std::string& name) { Lock G(mutex); From 58b4a5ef644b5fbb906f8072d966e6f9330d37b6 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 6 Jun 2017 10:41:36 +0200 Subject: [PATCH 038/189] ClientFactory::start() avoid custom ChannelProviderFactory --- src/pva/clientFactory.cpp | 65 +------------------------ src/remoteClient/clientContextImpl.cpp | 3 +- src/remoteClient/pv/clientContextImpl.h | 2 - 3 files changed, 3 insertions(+), 67 deletions(-) diff --git a/src/pva/clientFactory.cpp b/src/pva/clientFactory.cpp index 9075e70..6ffdbed 100644 --- a/src/pva/clientFactory.cpp +++ b/src/pva/clientFactory.cpp @@ -18,76 +18,15 @@ using namespace epics::pvData; using namespace epics::pvAccess; -class ChannelProviderFactoryImpl : public ChannelProviderFactory -{ -private: - Mutex m_mutex; - ChannelProvider::shared_pointer m_shared_provider; - -public: - POINTER_DEFINITIONS(ChannelProviderFactoryImpl); - - virtual ~ChannelProviderFactoryImpl() - { - Lock guard(m_mutex); - if (m_shared_provider) - { - ChannelProvider::shared_pointer provider; - m_shared_provider.swap(provider); - // factroy cleans up also shared provider - provider->destroy(); - } - } - - virtual std::string getFactoryName() - { - return ClientContextImpl::PROVIDER_NAME; - } - - virtual ChannelProvider::shared_pointer sharedInstance() - { - Lock guard(m_mutex); - if (!m_shared_provider) - { - epics::pvAccess::Configuration::shared_pointer def; - m_shared_provider = createClientProvider(def); - } - return m_shared_provider; - } - - virtual ChannelProvider::shared_pointer newInstance(const std::tr1::shared_ptr& conf) - { - Lock guard(m_mutex); - return createClientProvider(conf); - } -}; - -static Mutex cprovfact_mutex; -static ChannelProviderFactoryImpl::shared_pointer pva_factory; - void ClientFactory::start() { epicsSignalInstallSigAlarmIgnore(); epicsSignalInstallSigPipeIgnore(); - Lock guard(cprovfact_mutex); - if (!pva_factory) - pva_factory.reset(new ChannelProviderFactoryImpl()); - - registerChannelProviderFactory(pva_factory); + getChannelProviderRegistry()->add("pva", createClientProvider, false); } void ClientFactory::stop() { - Lock guard(cprovfact_mutex); - - if (pva_factory) - { - unregisterChannelProviderFactory(pva_factory); - if(!pva_factory.unique()) { - LOG(logLevelWarn, "ClientFactory::stop() finds shared client context with %u remaining users", - (unsigned)pva_factory.use_count()); - } - pva_factory.reset(); - } + getChannelProviderRegistry()->remove("pva"); } diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 87ebbaa..7bd1f61 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -47,7 +47,6 @@ using namespace epics::pvData; namespace epics { namespace pvAccess { -string ClientContextImpl::PROVIDER_NAME = "pva"; Status ChannelImpl::channelDestroyed( Status::STATUSTYPE_WARNING, "channel destroyed"); Status ChannelImpl::channelDisconnected( @@ -3302,7 +3301,7 @@ public: virtual std::string getProviderName() { - return PROVIDER_NAME; + return "pva"; } virtual ChannelFind::shared_pointer channelFind( diff --git a/src/remoteClient/pv/clientContextImpl.h b/src/remoteClient/pv/clientContextImpl.h index 5d5488b..e8a802c 100644 --- a/src/remoteClient/pv/clientContextImpl.h +++ b/src/remoteClient/pv/clientContextImpl.h @@ -67,8 +67,6 @@ class ClientContextImpl : public Context public: POINTER_DEFINITIONS(ClientContextImpl); - static std::string PROVIDER_NAME; - /** * Get context implementation version. * @return version of the context implementation. From 0468bd0d088355782abdd4baf849a02e850eb570 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 6 Jun 2017 10:55:10 +0200 Subject: [PATCH 039/189] getChannelProviderRegistry() avoid global init order issues --- src/factory/ChannelAccessFactory.cpp | 32 ++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/factory/ChannelAccessFactory.cpp b/src/factory/ChannelAccessFactory.cpp index 3762c20..a82a774 100644 --- a/src/factory/ChannelAccessFactory.cpp +++ b/src/factory/ChannelAccessFactory.cpp @@ -7,6 +7,8 @@ #include #include +#include + #include #include #include @@ -140,15 +142,31 @@ bool ChannelProviderRegistry::remove(const ChannelProviderFactory::shared_pointe return false; } -ChannelProviderRegistry::shared_pointer getChannelProviderRegistry() { - static Mutex mutex; - static ChannelProviderRegistry::shared_pointer global_reg; - Lock guard(mutex); +namespace { +struct providerRegGbl_t { + Mutex mutex; + ChannelProviderRegistry::shared_pointer reg; +} *providerRegGbl; - if(!global_reg) { - global_reg = ChannelProviderRegistry::build(); +epicsThreadOnceId providerRegOnce = EPICS_THREAD_ONCE_INIT; + +void providerRegInit(void*) +{ + providerRegGbl = new providerRegGbl_t; +} + +} // namespace + +ChannelProviderRegistry::shared_pointer getChannelProviderRegistry() +{ + epicsThreadOnce(&providerRegOnce, &providerRegInit, 0); + + Lock guard(providerRegGbl->mutex); + + if(!providerRegGbl->reg) { + providerRegGbl->reg = ChannelProviderRegistry::build(); } - return global_reg; + return providerRegGbl->reg; } void registerChannelProviderFactory(ChannelProviderFactory::shared_pointer const & channelProviderFactory) { From ad2ad17fe5dd462c5b37c9cfe61cc2795feaefc7 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 6 Jun 2017 15:33:49 +0200 Subject: [PATCH 040/189] drop unused --- src/remote/blockingTCPConnector.cpp | 3 +++ src/remoteClient/clientContextImpl.cpp | 7 +------ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/remote/blockingTCPConnector.cpp b/src/remote/blockingTCPConnector.cpp index fb08e78..974c759 100644 --- a/src/remote/blockingTCPConnector.cpp +++ b/src/remote/blockingTCPConnector.cpp @@ -89,6 +89,9 @@ Transport::shared_pointer BlockingTCPConnector::connect(TransportClient::shared_ return transport; } + /* TODO: bound map<> size + * Lazy creates a lock for each 'address' ever encountered. + */ bool lockAcquired = _namedLocker.acquireSynchronizationObject(&address, LOCK_TIMEOUT); if(lockAcquired) { try { diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 7bd1f61..88a4f7c 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -4282,7 +4282,7 @@ public: InternalClientContextImpl(const Configuration::shared_pointer& conf) : m_addressList(""), m_autoAddressList(true), m_connectionTimeout(30.0f), m_beaconPeriod(15.0f), m_broadcastPort(PVA_BROADCAST_PORT), m_receiveBufferSize(MAX_TCP_RECV), - m_namedLocker(), m_lastCID(0), m_lastIOID(0), + m_lastCID(0), m_lastIOID(0), m_version("pvAccess Client", "cpp", EPICS_PVA_MAJOR_VERSION, EPICS_PVA_MINOR_VERSION, @@ -4901,11 +4901,6 @@ private: */ ClientResponseHandler::shared_pointer m_responseHandler; - /** - * Context instance. - */ - NamedLockPattern m_namedLocker; - /** * Context instance. */ From 03344832970c9ee69881503370c784fc21ab9fd2 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 6 Jun 2017 16:23:22 +0200 Subject: [PATCH 041/189] avoid unnecessary globals --- src/remoteClient/clientContextImpl.cpp | 90 ++++++++++++-------------- 1 file changed, 41 insertions(+), 49 deletions(-) diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 88a4f7c..63e2b6e 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -110,10 +110,6 @@ public: static Status invalidBitSetLengthStatus; static Status pvRequestNull; - static PVStructure::shared_pointer nullPVStructure; - static Structure::const_shared_pointer nullStructure; - static BitSet::shared_pointer nullBitSet; - static BitSet::shared_pointer createBitSetFor( PVStructure::shared_pointer const & pvStructure, BitSet::shared_pointer const & existingBitSet) @@ -400,10 +396,6 @@ Status BaseRequestImpl::invalidPutArrayStatus(Status::STATUSTYPE_ERROR, "incompa Status BaseRequestImpl::invalidBitSetLengthStatus(Status::STATUSTYPE_ERROR, "invalid bit-set length"); Status BaseRequestImpl::pvRequestNull(Status::STATUSTYPE_ERROR, "pvRequest == 0"); -PVStructure::shared_pointer BaseRequestImpl::nullPVStructure; -Structure::const_shared_pointer BaseRequestImpl::nullStructure; -BitSet::shared_pointer BaseRequestImpl::nullBitSet; - PVACCESS_REFCOUNT_MONITOR_DEFINE(channelProcess); class ChannelProcessRequestImpl : @@ -574,7 +566,7 @@ private: if (!m_pvRequest) { ChannelGet::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(pvRequestNull, thisPointer, nullStructure)); + EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(pvRequestNull, thisPointer, StructureConstPtr())); return; } @@ -587,7 +579,7 @@ private: resubscribeSubscription(m_channel->checkDestroyedAndGetTransport()); } catch (std::runtime_error &rte) { ChannelGet::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(channelDestroyed, thisPointer, nullStructure)); + EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(channelDestroyed, thisPointer, StructureConstPtr())); BaseRequestImpl::destroy(true); } } @@ -641,7 +633,7 @@ public: if (!status.isSuccess()) { ChannelGet::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(status, thisPointer, nullStructure)); + EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(status, thisPointer, StructureConstPtr())); return; } @@ -665,7 +657,7 @@ public: if (!status.isSuccess()) { - EXCEPTION_GUARD(m_channelGetRequester->getDone(status, thisPtr, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelGetRequester->getDone(status, thisPtr, PVStructurePtr(), BitSetPtr())); return; } @@ -691,11 +683,11 @@ public: { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelGetRequester->getDone(destroyedStatus, thisPtr, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelGetRequester->getDone(destroyedStatus, thisPtr, PVStructurePtr(), BitSetPtr())); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelGetRequester->getDone(notInitializedStatus, thisPtr, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelGetRequester->getDone(notInitializedStatus, thisPtr, PVStructurePtr(), BitSetPtr())); return; } } @@ -713,7 +705,7 @@ public: } */ if (!startRequest(m_lastRequest.get() ? QOS_DESTROY | QOS_GET : QOS_DEFAULT)) { - EXCEPTION_GUARD(m_channelGetRequester->getDone(otherRequestPendingStatus, thisPtr, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelGetRequester->getDone(otherRequestPendingStatus, thisPtr, PVStructurePtr(), BitSetPtr())); return; } @@ -722,7 +714,7 @@ public: //TODO bulk hack m_channel->checkAndGetTransport()->enqueueOnlySendRequest(thisSender); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelGetRequester->getDone(channelNotConnected, thisPtr, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelGetRequester->getDone(channelNotConnected, thisPtr, PVStructurePtr(), BitSetPtr())); } } @@ -796,7 +788,7 @@ private: if (!m_pvRequest) { ChannelPut::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(pvRequestNull, thisPointer, nullStructure)); + EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(pvRequestNull, thisPointer, StructureConstPtr())); return; } @@ -809,7 +801,7 @@ private: resubscribeSubscription(m_channel->checkDestroyedAndGetTransport()); } catch (std::runtime_error &rte) { ChannelPut::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(channelDestroyed, thisPointer, nullStructure)); + EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(channelDestroyed, thisPointer, StructureConstPtr())); BaseRequestImpl::destroy(true); } } @@ -868,7 +860,7 @@ public: if (!status.isSuccess()) { ChannelPut::shared_pointer thisChannelPut = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(status, thisChannelPut, nullStructure)); + EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(status, thisChannelPut, StructureConstPtr())); return; } @@ -892,7 +884,7 @@ public: { if (!status.isSuccess()) { - EXCEPTION_GUARD(m_channelPutRequester->getDone(status, thisPtr, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutRequester->getDone(status, thisPtr, PVStructurePtr(), BitSetPtr())); return; } @@ -917,17 +909,17 @@ public: { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelPutRequester->getDone(destroyedStatus, thisPtr, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutRequester->getDone(destroyedStatus, thisPtr, PVStructurePtr(), BitSetPtr())); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelPutRequester->getDone(notInitializedStatus, thisPtr, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutRequester->getDone(notInitializedStatus, thisPtr, PVStructurePtr(), BitSetPtr())); return; } } if (!startRequest(m_lastRequest.get() ? QOS_GET | QOS_DESTROY : QOS_GET)) { - EXCEPTION_GUARD(m_channelPutRequester->getDone(otherRequestPendingStatus, thisPtr, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutRequester->getDone(otherRequestPendingStatus, thisPtr, PVStructurePtr(), BitSetPtr())); return; } @@ -936,7 +928,7 @@ public: m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelPutRequester->getDone(channelNotConnected, thisPtr, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutRequester->getDone(channelNotConnected, thisPtr, PVStructurePtr(), BitSetPtr())); } } @@ -1057,7 +1049,7 @@ private: if (!m_pvRequest) { ChannelPutGet::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(pvRequestNull, thisPointer, nullStructure, nullStructure)); + EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(pvRequestNull, thisPointer, StructureConstPtr(), StructureConstPtr())); return; } @@ -1067,7 +1059,7 @@ private: resubscribeSubscription(m_channel->checkDestroyedAndGetTransport()); } catch (std::runtime_error &rte) { ChannelPutGet::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(channelDestroyed, thisPointer, nullStructure, nullStructure)); + EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(channelDestroyed, thisPointer, StructureConstPtr(), StructureConstPtr())); BaseRequestImpl::destroy(true); } } @@ -1130,7 +1122,7 @@ public: if (!status.isSuccess()) { ChannelPutGet::shared_pointer thisChannelPutGet = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(status, thisChannelPutGet, nullStructure, nullStructure)); + EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(status, thisChannelPutGet, StructureConstPtr(), StructureConstPtr())); return; } @@ -1156,7 +1148,7 @@ public: { if (!status.isSuccess()) { - EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(status, thisPtr, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(status, thisPtr, PVStructurePtr(), BitSetPtr())); return; } @@ -1173,7 +1165,7 @@ public: { if (!status.isSuccess()) { - EXCEPTION_GUARD(m_channelPutGetRequester->getPutDone(status, thisPtr, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->getPutDone(status, thisPtr, PVStructurePtr(), BitSetPtr())); return; } @@ -1190,7 +1182,7 @@ public: { if (!status.isSuccess()) { - EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(status, thisPtr, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(status, thisPtr, PVStructurePtr(), BitSetPtr())); return; } @@ -1213,29 +1205,29 @@ public: { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(destroyedStatus, thisPtr, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(destroyedStatus, thisPtr, PVStructurePtr(), BitSetPtr())); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(notInitializedStatus, thisPtr, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(notInitializedStatus, thisPtr, PVStructurePtr(), BitSetPtr())); return; } } if (!(*m_putData->getStructure() == *pvPutStructure->getStructure())) { - EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(invalidPutStructureStatus, thisPtr, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(invalidPutStructureStatus, thisPtr, PVStructurePtr(), BitSetPtr())); return; } if (bitSet->size() < m_putDataBitSet->size()) { - EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(invalidBitSetLengthStatus, thisPtr, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(invalidBitSetLengthStatus, thisPtr, PVStructurePtr(), BitSetPtr())); return; } if (!startRequest(m_lastRequest.get() ? QOS_DESTROY : QOS_DEFAULT)) { - EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(otherRequestPendingStatus, thisPtr, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(otherRequestPendingStatus, thisPtr, PVStructurePtr(), BitSetPtr())); return; } @@ -1247,7 +1239,7 @@ public: m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(channelNotConnected, thisPtr, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(channelNotConnected, thisPtr, PVStructurePtr(), BitSetPtr())); } } @@ -1258,17 +1250,17 @@ public: { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(destroyedStatus, thisPtr, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(destroyedStatus, thisPtr, PVStructurePtr(), BitSetPtr())); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(notInitializedStatus, thisPtr, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(notInitializedStatus, thisPtr, PVStructurePtr(), BitSetPtr())); return; } } if (!startRequest(m_lastRequest.get() ? QOS_DESTROY | QOS_GET : QOS_GET)) { - EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(otherRequestPendingStatus, thisPtr, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(otherRequestPendingStatus, thisPtr, PVStructurePtr(), BitSetPtr())); return; } @@ -1276,7 +1268,7 @@ public: m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(channelNotConnected, thisPtr, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(channelNotConnected, thisPtr, PVStructurePtr(), BitSetPtr())); } } @@ -1287,17 +1279,17 @@ public: { Lock guard(m_mutex); if (m_destroyed) { - m_channelPutGetRequester->getPutDone(destroyedStatus, thisPtr, nullPVStructure, nullBitSet); + m_channelPutGetRequester->getPutDone(destroyedStatus, thisPtr, PVStructurePtr(), BitSetPtr()); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelPutGetRequester->getPutDone(notInitializedStatus, thisPtr, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->getPutDone(notInitializedStatus, thisPtr, PVStructurePtr(), BitSetPtr())); return; } } if (!startRequest(m_lastRequest.get() ? QOS_DESTROY | QOS_GET_PUT : QOS_GET_PUT)) { - m_channelPutGetRequester->getPutDone(otherRequestPendingStatus, thisPtr, nullPVStructure, nullBitSet); + m_channelPutGetRequester->getPutDone(otherRequestPendingStatus, thisPtr, PVStructurePtr(), BitSetPtr()); return; } @@ -1305,7 +1297,7 @@ public: m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelPutGetRequester->getPutDone(channelNotConnected, thisPtr, nullPVStructure, nullBitSet)); + EXCEPTION_GUARD(m_channelPutGetRequester->getPutDone(channelNotConnected, thisPtr, PVStructurePtr(), BitSetPtr())); } } @@ -1465,7 +1457,7 @@ public: if (!status.isSuccess()) { - EXCEPTION_GUARD(m_channelRPCRequester->requestDone(status, thisPtr, nullPVStructure)); + EXCEPTION_GUARD(m_channelRPCRequester->requestDone(status, thisPtr, PVStructurePtr())); return; } @@ -1481,17 +1473,17 @@ public: { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelRPCRequester->requestDone(destroyedStatus, thisPtr, nullPVStructure)); + EXCEPTION_GUARD(m_channelRPCRequester->requestDone(destroyedStatus, thisPtr, PVStructurePtr())); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelRPCRequester->requestDone(notInitializedStatus, thisPtr, nullPVStructure)); + EXCEPTION_GUARD(m_channelRPCRequester->requestDone(notInitializedStatus, thisPtr, PVStructurePtr())); return; } } if (!startRequest(m_lastRequest.get() ? QOS_DESTROY : QOS_DEFAULT)) { - EXCEPTION_GUARD(m_channelRPCRequester->requestDone(otherRequestPendingStatus, thisPtr, nullPVStructure)); + EXCEPTION_GUARD(m_channelRPCRequester->requestDone(otherRequestPendingStatus, thisPtr, PVStructurePtr())); return; } @@ -1503,7 +1495,7 @@ public: m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelRPCRequester->requestDone(channelNotConnected, thisPtr, nullPVStructure)); + EXCEPTION_GUARD(m_channelRPCRequester->requestDone(channelNotConnected, thisPtr, PVStructurePtr())); } } From 8febd176bb1106e93fb6e778c9f1df32d5fb7180 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 7 Jun 2017 13:33:10 +0200 Subject: [PATCH 042/189] PVA client ref. loop breaking Adjust ownership of BaseRequestImpl sub-classes. Keep two weak_ptr<>. one (internal) for tracking relations with Channel. one (external) for tracking relations w/ user code, and send Q. external wraps internal, and calls destroy() to break ref. loops involving internal. death to m_thisPointer! --- src/client/pv/monitor.h | 2 +- src/client/pv/pvAccess.h | 2 +- src/remoteClient/clientContextImpl.cpp | 757 ++++++++++++------------- testApp/remote/channelAccessIFTest.cpp | 21 +- 4 files changed, 386 insertions(+), 396 deletions(-) diff --git a/src/client/pv/monitor.h b/src/client/pv/monitor.h index 39b16dd..1b83d50 100644 --- a/src/client/pv/monitor.h +++ b/src/client/pv/monitor.h @@ -54,7 +54,7 @@ class epicsShareClass MonitorElement { * This is used by pvAccess to implement monitors. * @author mrk */ -class epicsShareClass Monitor : public epics::pvData::Destroyable{ +class epicsShareClass Monitor : public virtual epics::pvData::Destroyable{ public: POINTER_DEFINITIONS(Monitor); virtual ~Monitor(){} diff --git a/src/client/pv/pvAccess.h b/src/client/pv/pvAccess.h index 9463b8f..ee788c6 100644 --- a/src/client/pv/pvAccess.h +++ b/src/client/pv/pvAccess.h @@ -138,7 +138,7 @@ struct epicsShareClass ChannelBaseRequester : virtual public epics::pvData::Requ /** * Base interface for all channel requests (aka. Operations). */ -class epicsShareClass ChannelRequest : public epics::pvData::Destroyable, public Lockable, private epics::pvData::NoDefaultMethods { +class epicsShareClass ChannelRequest : public virtual epics::pvData::Destroyable, public Lockable, private epics::pvData::NoDefaultMethods { public: POINTER_DEFINITIONS(ChannelRequest); diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index 63e2b6e..a4a401c 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -47,6 +47,8 @@ using namespace epics::pvData; namespace epics { namespace pvAccess { +class ChannelGetFieldRequestImpl; + Status ChannelImpl::channelDestroyed( Status::STATUSTYPE_WARNING, "channel destroyed"); Status ChannelImpl::channelDisconnected( @@ -62,27 +64,6 @@ typedef std::map IOIDResponseRequestM 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__); } -struct delayed_destroyable_deleter -{ - template void operator()(T * p) - { - try - { - // new owner, this also allows to use shared_from_this() in destroy() method - std::tr1::shared_ptr ptr(p); - ptr->destroy(); - } - catch(std::exception &ex) - { - printf("delayed_destroyable_deleter: unhandled exception: %s", ex.what()); - } - catch(...) - { - printf("delayed_destroyable_deleter: unhandled exception"); - } - } -}; - /** * Base channel request. * @author Matej Sekoranja @@ -91,12 +72,10 @@ class BaseRequestImpl : public DataResponse, public SubscriptionRequest, public TransportSender, - public Destroyable, - public std::tr1::enable_shared_from_this + public virtual Destroyable { public: - typedef std::tr1::shared_ptr shared_pointer; - typedef std::tr1::shared_ptr const_shared_pointer; + POINTER_DEFINITIONS(BaseRequestImpl); static PVDataCreatePtr pvDataCreate; @@ -153,8 +132,51 @@ protected: Mutex m_mutex; - // used to hold ownership until create is called (to support complete async usage) - ResponseRequest::shared_pointer m_thisPointer; + /* ownership here is a bit complicated... + * + * each instance maintains two shared_ptr/weak_ptr + * 1. internal - calls 'delete' when ref count reaches zero + * 2. external - wraps 'internal' ref. calls ->destroy() and releases internal ref. when ref count reaches zero + * + * Any internal ref. loops must be broken by destroy() + * + * Only external refs. are returned by Channel::create*() or passed to *Requester methods. + * + * Internal refs. are held by internal relations which need to ensure memory is not + * prematurely free'd, but should not keep the channel/operation "alive". + * eg. A Channel holds an internal ref to ChannelGet + */ + const BaseRequestImpl::weak_pointer m_this_internal, + m_this_external; + + template + std::tr1::shared_ptr internal_from_this() { + ResponseRequest::shared_pointer P(m_this_internal); + return std::tr1::static_pointer_cast(P); + } + template + std::tr1::shared_ptr external_from_this() { + ResponseRequest::shared_pointer P(m_this_external); + return std::tr1::static_pointer_cast(P); + } + + template + static + typename std::tr1::shared_ptr + build(ChannelImpl::shared_pointer const & channel, + const typename subklass::requester_type::shared_pointer& requester, + const epics::pvData::PVStructure::shared_pointer& pvRequest) + { + std::tr1::shared_ptr internal(new subklass(channel, requester, pvRequest)), + external(internal.get(), + Destroyable::cleaner(internal)); + // only we get to set these, but since this isn't the ctor, we aren't able to + // follow the rules. + const_cast(internal->m_this_internal) = internal; + const_cast(internal->m_this_external) = external; + internal->activate(); + return external; + } bool m_destroyed; bool m_initialized; @@ -163,8 +185,6 @@ protected: AtomicBoolean m_subscribed; - virtual ~BaseRequestImpl() {}; - BaseRequestImpl(ChannelImpl::shared_pointer const & channel, ChannelBaseRequester::shared_pointer const & requester) : m_channel(channel), m_requester(requester), @@ -173,15 +193,16 @@ protected: m_destroyed(false), m_initialized(false), m_subscribed() - { - } + {} - void activate() { + virtual ~BaseRequestImpl() {} + + virtual void activate() { // register response request // ResponseRequest::shared_pointer to this instance must already exist - m_thisPointer = shared_from_this(); - m_ioid = m_channel->getContext()->registerResponseRequest(m_thisPointer); - m_channel->registerResponseRequest(m_thisPointer); + shared_pointer self(m_this_internal); + m_ioid = m_channel->getContext()->registerResponseRequest(self); + m_channel->registerResponseRequest(self); } bool startRequest(int32 qos) { @@ -238,10 +259,6 @@ public: m_mutex.unlock(); } - // we are initialized now, release pointer - // this is safe since at least caller owns it - m_thisPointer.reset(); - initResponse(transport, version, payloadBuffer, qos, status); } else @@ -281,7 +298,7 @@ public: try { startRequest(PURE_CANCEL_REQUEST); - m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); + m_channel->checkAndGetTransport()->enqueueSendRequest(external_from_this()); } catch (std::exception& e) { // noop (do not complain if fails) LOG(logLevelWarn, "Ignore exception during ChanneGet::cancel: %s", e.what()); @@ -320,16 +337,13 @@ public: try { startRequest(PURE_DESTROY_REQUEST); - m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); + m_channel->checkAndGetTransport()->enqueueSendRequest(external_from_this()); } catch (std::exception& e) { // noop (do not complain if fails) LOG(logLevelWarn, "Ignore exception during BaseRequestImpl::destroy: %s", e.what()); } } - - // in case this instance is destroyed uninitialized - m_thisPointer.reset(); } virtual void timeout() { @@ -353,7 +367,7 @@ public: if (transport.get() != 0 && !m_subscribed.get() && startRequest(QOS_INIT)) { m_subscribed.set(); - transport->enqueueSendRequest(shared_from_this()); + transport->enqueueSendRequest(external_from_this()); } } @@ -402,7 +416,7 @@ class ChannelProcessRequestImpl : public BaseRequestImpl, public ChannelProcess { -private: +public: ChannelProcessRequester::shared_pointer m_callback; PVStructure::shared_pointer m_pvRequest; @@ -414,7 +428,7 @@ private: PVACCESS_REFCOUNT_MONITOR_CONSTRUCT(channelProcess); } - void activate() + virtual void activate() { BaseRequestImpl::activate(); @@ -425,23 +439,17 @@ private: try { resubscribeSubscription(m_channel->checkDestroyedAndGetTransport()); } catch (std::runtime_error &rte) { - ChannelProcess::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_callback->channelProcessConnect(channelDestroyed, thisPointer)); + EXCEPTION_GUARD(m_callback->channelProcessConnect(channelDestroyed, external_from_this())); BaseRequestImpl::destroy(true); } } public: - static ChannelProcess::shared_pointer create(ChannelImpl::shared_pointer const & channel, ChannelProcessRequester::shared_pointer const & callback, PVStructure::shared_pointer const & pvRequest) + static ChannelProcess::shared_pointer create(ChannelImpl::shared_pointer const & channel, + ChannelProcessRequester::shared_pointer const & requester, + PVStructure::shared_pointer const & pvRequest) { - // TODO use std::make_shared - std::tr1::shared_ptr tp( - new ChannelProcessRequestImpl(channel, callback, pvRequest), - delayed_destroyable_deleter() - ); - ChannelProcess::shared_pointer thisPointer = tp; - static_cast(thisPointer.get())->activate(); - return thisPointer; + return build(channel, requester, pvRequest); } ~ChannelProcessRequestImpl() @@ -472,18 +480,16 @@ public: } virtual void initResponse(Transport::shared_pointer const & /*transport*/, int8 /*version*/, ByteBuffer* /*payloadBuffer*/, int8 /*qos*/, const Status& status) { - ChannelProcess::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_callback->channelProcessConnect(status, thisPtr)); + EXCEPTION_GUARD(m_callback->channelProcessConnect(status, external_from_this())); } virtual void normalResponse(Transport::shared_pointer const & /*transport*/, int8 /*version*/, ByteBuffer* /*payloadBuffer*/, int8 /*qos*/, const Status& status) { - ChannelProcess::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_callback->processDone(status, thisPtr)); + EXCEPTION_GUARD(m_callback->processDone(status, external_from_this())); } virtual void process() { - ChannelProcess::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); + ChannelProcess::shared_pointer thisPtr(external_from_this()); { Lock guard(m_mutex); @@ -503,7 +509,7 @@ public: } try { - m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); + m_channel->checkAndGetTransport()->enqueueSendRequest(external_from_this()); } catch (std::runtime_error &rte) { stopRequest(); EXCEPTION_GUARD(m_callback->processDone(channelNotConnected, thisPtr)); @@ -543,7 +549,7 @@ class ChannelGetImpl : public BaseRequestImpl, public ChannelGet { -private: +public: ChannelGetRequester::shared_pointer m_channelGetRequester; PVStructure::shared_pointer m_pvRequest; @@ -561,12 +567,11 @@ private: PVACCESS_REFCOUNT_MONITOR_CONSTRUCT(channelGet); } - void activate() + virtual void activate() { if (!m_pvRequest) { - ChannelGet::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(pvRequestNull, thisPointer, StructureConstPtr())); + EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(pvRequestNull, external_from_this(), StructureConstPtr())); return; } @@ -578,22 +583,17 @@ private: try { resubscribeSubscription(m_channel->checkDestroyedAndGetTransport()); } catch (std::runtime_error &rte) { - ChannelGet::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(channelDestroyed, thisPointer, StructureConstPtr())); + EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(channelDestroyed, external_from_this(), StructureConstPtr())); BaseRequestImpl::destroy(true); } } public: - static ChannelGet::shared_pointer create(ChannelImpl::shared_pointer const & channel, ChannelGetRequester::shared_pointer const & channelGetRequester, PVStructure::shared_pointer const & pvRequest) + static ChannelGet::shared_pointer create(ChannelImpl::shared_pointer const & channel, + ChannelGetRequester::shared_pointer const & requester, + PVStructure::shared_pointer const & pvRequest) { - // TODO use std::make_shared - std::tr1::shared_ptr tp( - new ChannelGetImpl(channel, channelGetRequester, pvRequest), - delayed_destroyable_deleter()); - ChannelGet::shared_pointer thisPointer = tp; - static_cast(thisPointer.get())->activate(); - return thisPointer; + return build(channel, requester, pvRequest); } ~ChannelGetImpl() @@ -632,8 +632,7 @@ public: virtual void initResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 /*qos*/, const Status& status) { if (!status.isSuccess()) { - ChannelGet::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(status, thisPointer, StructureConstPtr())); + EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(status, external_from_this(), StructureConstPtr())); return; } @@ -645,19 +644,16 @@ public: } // notify - ChannelGet::shared_pointer thisChannelGet = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(status, thisChannelGet, m_structure->getStructure())); + EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(status, external_from_this(), m_structure->getStructure())); } virtual void normalResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 /*qos*/, const Status& status) { MB_POINT(channelGet, 8, "client channelGet->deserialize (start)"); - ChannelGet::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); - if (!status.isSuccess()) { - EXCEPTION_GUARD(m_channelGetRequester->getDone(status, thisPtr, PVStructurePtr(), BitSetPtr())); + EXCEPTION_GUARD(m_channelGetRequester->getDone(status, external_from_this(), PVStructurePtr(), BitSetPtr())); return; } @@ -670,7 +666,7 @@ public: MB_POINT(channelGet, 9, "client channelGet->deserialize (end), just before channelGet->getDone() is called"); - EXCEPTION_GUARD(m_channelGetRequester->getDone(status, thisPtr, m_structure, m_bitSet)); + EXCEPTION_GUARD(m_channelGetRequester->getDone(status, external_from_this(), m_structure, m_bitSet)); } virtual void get() { @@ -678,7 +674,7 @@ public: MB_INC_AUTO_ID(channelGet); MB_POINT(channelGet, 0, "client channelGet->get()"); - ChannelGet::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); + ChannelGet::shared_pointer thisPtr(external_from_this()); { Lock guard(m_mutex); @@ -710,7 +706,7 @@ public: } try { - m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); + m_channel->checkAndGetTransport()->enqueueSendRequest(external_from_this()); //TODO bulk hack m_channel->checkAndGetTransport()->enqueueOnlySendRequest(thisSender); } catch (std::runtime_error &rte) { stopRequest(); @@ -765,7 +761,7 @@ class ChannelPutImpl : public BaseRequestImpl, public ChannelPut { -private: +public: ChannelPutRequester::shared_pointer m_channelPutRequester; PVStructure::shared_pointer m_pvRequest; @@ -783,12 +779,11 @@ private: PVACCESS_REFCOUNT_MONITOR_CONSTRUCT(channelPut); } - void activate() + virtual void activate() { if (!m_pvRequest) { - ChannelPut::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(pvRequestNull, thisPointer, StructureConstPtr())); + EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(pvRequestNull, external_from_this(), StructureConstPtr())); return; } @@ -800,22 +795,17 @@ private: try { resubscribeSubscription(m_channel->checkDestroyedAndGetTransport()); } catch (std::runtime_error &rte) { - ChannelPut::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(channelDestroyed, thisPointer, StructureConstPtr())); + EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(channelDestroyed, external_from_this(), StructureConstPtr())); BaseRequestImpl::destroy(true); } } public: - static ChannelPut::shared_pointer create(ChannelImpl::shared_pointer const & channel, ChannelPutRequester::shared_pointer const & channelPutRequester, PVStructure::shared_pointer const & pvRequest) + static ChannelPut::shared_pointer create(ChannelImpl::shared_pointer const & channel, + ChannelPutRequester::shared_pointer const & requester, + PVStructure::shared_pointer const & pvRequest) { - // TODO use std::make_shared - std::tr1::shared_ptr tp( - new ChannelPutImpl(channel, channelPutRequester, pvRequest), - delayed_destroyable_deleter()); - ChannelPut::shared_pointer thisPointer = tp; - static_cast(thisPointer.get())->activate(); - return thisPointer; + return build(channel, requester, pvRequest); } ~ChannelPutImpl() @@ -859,8 +849,7 @@ public: virtual void initResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 /*qos*/, const Status& status) { if (!status.isSuccess()) { - ChannelPut::shared_pointer thisChannelPut = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(status, thisChannelPut, StructureConstPtr())); + EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(status, external_from_this(), StructureConstPtr())); return; } @@ -872,13 +861,12 @@ public: } // notify - ChannelPut::shared_pointer thisChannelPut = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(status, thisChannelPut, m_structure->getStructure())); + EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(status, external_from_this(), m_structure->getStructure())); } virtual void normalResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { - ChannelPut::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); + ChannelPut::shared_pointer thisPtr(external_from_this()); if (qos & QOS_GET) { @@ -904,7 +892,7 @@ public: virtual void get() { - ChannelPut::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); + ChannelPut::shared_pointer thisPtr(external_from_this()); { Lock guard(m_mutex); @@ -925,7 +913,7 @@ public: try { - m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); + m_channel->checkAndGetTransport()->enqueueSendRequest(external_from_this()); } catch (std::runtime_error &rte) { stopRequest(); EXCEPTION_GUARD(m_channelPutRequester->getDone(channelNotConnected, thisPtr, PVStructurePtr(), BitSetPtr())); @@ -934,7 +922,7 @@ public: virtual void put(PVStructure::shared_pointer const & pvPutStructure, BitSet::shared_pointer const & pvPutBitSet) { - ChannelPut::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); + ChannelPut::shared_pointer thisPtr(external_from_this()); { Lock guard(m_mutex); @@ -970,7 +958,7 @@ public: *m_bitSet = *pvPutBitSet; m_structure->copyUnchecked(*pvPutStructure, *m_bitSet); unlock(); - m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); + m_channel->checkAndGetTransport()->enqueueSendRequest(external_from_this()); } catch (std::runtime_error &rte) { stopRequest(); EXCEPTION_GUARD(m_channelPutRequester->putDone(channelNotConnected, thisPtr)); @@ -1021,7 +1009,7 @@ class ChannelPutGetImpl : public BaseRequestImpl, public ChannelPutGet { -private: +public: ChannelPutGetRequester::shared_pointer m_channelPutGetRequester; PVStructure::shared_pointer m_pvRequest; @@ -1044,12 +1032,11 @@ private: PVACCESS_REFCOUNT_MONITOR_CONSTRUCT(channelPutGet); } - void activate() + virtual void activate() { if (!m_pvRequest) { - ChannelPutGet::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(pvRequestNull, thisPointer, StructureConstPtr(), StructureConstPtr())); + EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(pvRequestNull, external_from_this(), StructureConstPtr(), StructureConstPtr())); return; } @@ -1058,22 +1045,17 @@ private: try { resubscribeSubscription(m_channel->checkDestroyedAndGetTransport()); } catch (std::runtime_error &rte) { - ChannelPutGet::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(channelDestroyed, thisPointer, StructureConstPtr(), StructureConstPtr())); + EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(channelDestroyed, external_from_this(), StructureConstPtr(), StructureConstPtr())); BaseRequestImpl::destroy(true); } } public: - static ChannelPutGet::shared_pointer create(ChannelImpl::shared_pointer const & channel, ChannelPutGetRequester::shared_pointer const & channelPutGetRequester, PVStructure::shared_pointer const & pvRequest) + static ChannelPutGet::shared_pointer create(ChannelImpl::shared_pointer const & channel, + ChannelPutGetRequester::shared_pointer const & requester, + PVStructure::shared_pointer const & pvRequest) { - // TODO use std::make_shared - std::tr1::shared_ptr tp( - new ChannelPutGetImpl(channel, channelPutGetRequester, pvRequest), - delayed_destroyable_deleter()); - ChannelPutGet::shared_pointer thisPointer = tp; - static_cast(thisPointer.get())->activate(); - return thisPointer; + return build(channel, requester, pvRequest); } ~ChannelPutGetImpl() @@ -1121,8 +1103,7 @@ public: virtual void initResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 /*qos*/, const Status& status) { if (!status.isSuccess()) { - ChannelPutGet::shared_pointer thisChannelPutGet = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(status, thisChannelPutGet, StructureConstPtr(), StructureConstPtr())); + EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(status, external_from_this(), StructureConstPtr(), StructureConstPtr())); return; } @@ -1135,14 +1116,13 @@ public: } // notify - ChannelPutGet::shared_pointer thisChannelPutGet = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(status, thisChannelPutGet, m_putData->getStructure(), m_getData->getStructure())); + EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(status, external_from_this(), m_putData->getStructure(), m_getData->getStructure())); } virtual void normalResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { - ChannelPutGet::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); + ChannelPutGet::shared_pointer thisPtr(external_from_this()); if (qos & QOS_GET) { @@ -1200,7 +1180,7 @@ public: virtual void putGet(PVStructure::shared_pointer const & pvPutStructure, BitSet::shared_pointer const & bitSet) { - ChannelPutGet::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); + ChannelPutGet::shared_pointer thisPtr(external_from_this()); { Lock guard(m_mutex); @@ -1236,7 +1216,7 @@ public: *m_putDataBitSet = *bitSet; m_putData->copyUnchecked(*pvPutStructure, *m_putDataBitSet); unlock(); - m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); + m_channel->checkAndGetTransport()->enqueueSendRequest(external_from_this()); } catch (std::runtime_error &rte) { stopRequest(); EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(channelNotConnected, thisPtr, PVStructurePtr(), BitSetPtr())); @@ -1245,7 +1225,7 @@ public: virtual void getGet() { - ChannelPutGet::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); + ChannelPutGet::shared_pointer thisPtr(external_from_this()); { Lock guard(m_mutex); @@ -1265,7 +1245,7 @@ public: } try { - m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); + m_channel->checkAndGetTransport()->enqueueSendRequest(external_from_this()); } catch (std::runtime_error &rte) { stopRequest(); EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(channelNotConnected, thisPtr, PVStructurePtr(), BitSetPtr())); @@ -1274,7 +1254,7 @@ public: virtual void getPut() { - ChannelPutGet::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); + ChannelPutGet::shared_pointer thisPtr(external_from_this()); { Lock guard(m_mutex); @@ -1294,7 +1274,7 @@ public: } try { - m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); + m_channel->checkAndGetTransport()->enqueueSendRequest(external_from_this()); } catch (std::runtime_error &rte) { stopRequest(); EXCEPTION_GUARD(m_channelPutGetRequester->getPutDone(channelNotConnected, thisPtr, PVStructurePtr(), BitSetPtr())); @@ -1348,7 +1328,7 @@ class ChannelRPCImpl : public BaseRequestImpl, public ChannelRPC { -private: +public: ChannelRPCRequester::shared_pointer m_channelRPCRequester; PVStructure::shared_pointer m_pvRequest; @@ -1365,12 +1345,11 @@ private: PVACCESS_REFCOUNT_MONITOR_CONSTRUCT(channelRPC); } - void activate() + virtual void activate() { if (!m_pvRequest) { - ChannelRPC::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelRPCRequester->channelRPCConnect(pvRequestNull, thisPointer)); + EXCEPTION_GUARD(m_channelRPCRequester->channelRPCConnect(pvRequestNull, external_from_this())); return; } @@ -1380,22 +1359,17 @@ private: try { resubscribeSubscription(m_channel->checkDestroyedAndGetTransport()); } catch (std::runtime_error &rte) { - ChannelRPC::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelRPCRequester->channelRPCConnect(channelDestroyed, thisPointer)); + EXCEPTION_GUARD(m_channelRPCRequester->channelRPCConnect(channelDestroyed, external_from_this())); BaseRequestImpl::destroy(true); } } public: - static ChannelRPC::shared_pointer create(ChannelImpl::shared_pointer const & channel, ChannelRPCRequester::shared_pointer const & channelRPCRequester, PVStructure::shared_pointer const & pvRequest) + static ChannelRPC::shared_pointer create(ChannelImpl::shared_pointer const & channel, + ChannelRPCRequester::shared_pointer const & requester, + PVStructure::shared_pointer const & pvRequest) { - // TODO use std::make_shared - std::tr1::shared_ptr tp( - new ChannelRPCImpl(channel, channelRPCRequester, pvRequest), - delayed_destroyable_deleter()); - ChannelRPC::shared_pointer thisPointer = tp; - static_cast(thisPointer.get())->activate(); - return thisPointer; + return build(channel, requester, pvRequest); } ~ChannelRPCImpl() @@ -1441,19 +1415,17 @@ public: virtual void initResponse(Transport::shared_pointer const & /*transport*/, int8 /*version*/, ByteBuffer* /*payloadBuffer*/, int8 /*qos*/, const Status& status) { if (!status.isSuccess()) { - ChannelRPC::shared_pointer thisChannelRPC = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelRPCRequester->channelRPCConnect(status, thisChannelRPC)); + EXCEPTION_GUARD(m_channelRPCRequester->channelRPCConnect(status, external_from_this())); return; } // notify - ChannelRPC::shared_pointer thisChannelRPC = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelRPCRequester->channelRPCConnect(status, thisChannelRPC)); + EXCEPTION_GUARD(m_channelRPCRequester->channelRPCConnect(status, external_from_this())); } virtual void normalResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 /*qos*/, const Status& status) { - ChannelRPC::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); + ChannelRPC::shared_pointer thisPtr(external_from_this()); if (!status.isSuccess()) { @@ -1468,7 +1440,7 @@ public: virtual void request(epics::pvData::PVStructure::shared_pointer const & pvArgument) { - ChannelRPC::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); + ChannelRPC::shared_pointer thisPtr(external_from_this()); { Lock guard(m_mutex); @@ -1492,7 +1464,7 @@ public: m_structure = pvArgument; m_structureMutex.unlock(); - m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); + m_channel->checkAndGetTransport()->enqueueSendRequest(external_from_this()); } catch (std::runtime_error &rte) { stopRequest(); EXCEPTION_GUARD(m_channelRPCRequester->requestDone(channelNotConnected, thisPtr, PVStructurePtr())); @@ -1544,7 +1516,7 @@ class ChannelArrayImpl : public BaseRequestImpl, public ChannelArray { -private: +public: ChannelArrayRequester::shared_pointer m_channelArrayRequester; PVStructure::shared_pointer m_pvRequest; @@ -1570,12 +1542,11 @@ private: PVACCESS_REFCOUNT_MONITOR_CONSTRUCT(channelArray); } - void activate() + virtual void activate() { if (!m_pvRequest) { - ChannelArray::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelArrayRequester->channelArrayConnect(pvRequestNull, thisPointer, Array::shared_pointer())); + EXCEPTION_GUARD(m_channelArrayRequester->channelArrayConnect(pvRequestNull, external_from_this(), Array::shared_pointer())); return; } @@ -1585,22 +1556,17 @@ private: try { resubscribeSubscription(m_channel->checkDestroyedAndGetTransport()); } catch (std::runtime_error &rte) { - ChannelArray::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelArrayRequester->channelArrayConnect(channelDestroyed, thisPointer, Array::shared_pointer())); + EXCEPTION_GUARD(m_channelArrayRequester->channelArrayConnect(channelDestroyed, external_from_this(), Array::shared_pointer())); BaseRequestImpl::destroy(true); } } public: - static ChannelArray::shared_pointer create(ChannelImpl::shared_pointer const & channel, ChannelArrayRequester::shared_pointer const & channelArrayRequester, PVStructure::shared_pointer const & pvRequest) + static ChannelArray::shared_pointer create(ChannelImpl::shared_pointer const & channel, + ChannelArrayRequester::shared_pointer const & requester, + PVStructure::shared_pointer const & pvRequest) { - // TODO use std::make_shared - std::tr1::shared_ptr tp( - new ChannelArrayImpl(channel, channelArrayRequester, pvRequest), - delayed_destroyable_deleter()); - ChannelArray::shared_pointer thisPointer = tp; - static_cast(thisPointer.get())->activate(); - return thisPointer; + return build(channel, requester, pvRequest); } ~ChannelArrayImpl() @@ -1661,8 +1627,7 @@ public: virtual void initResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 /*qos*/, const Status& status) { if (!status.isSuccess()) { - ChannelArray::shared_pointer thisChannelArray = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelArrayRequester->channelArrayConnect(status, thisChannelArray, Array::shared_pointer())); + EXCEPTION_GUARD(m_channelArrayRequester->channelArrayConnect(status, external_from_this(), Array::shared_pointer())); return; } @@ -1674,19 +1639,18 @@ public: } // notify - ChannelArray::shared_pointer thisChannelArray = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_channelArrayRequester->channelArrayConnect(status, thisChannelArray, m_arrayData->getArray())); + EXCEPTION_GUARD(m_channelArrayRequester->channelArrayConnect(status, external_from_this(), m_arrayData->getArray())); } virtual void normalResponse(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { - ChannelArray::shared_pointer thisChannelArray = dynamic_pointer_cast(shared_from_this()); + ChannelArray::shared_pointer thisPtr(external_from_this()); if (qos & QOS_GET) { if (!status.isSuccess()) { - m_channelArrayRequester->getArrayDone(status, thisChannelArray, PVArray::shared_pointer()); + m_channelArrayRequester->getArrayDone(status, thisPtr, PVArray::shared_pointer()); return; } @@ -1695,21 +1659,21 @@ public: m_arrayData->deserialize(payloadBuffer, transport.get()); } - EXCEPTION_GUARD(m_channelArrayRequester->getArrayDone(status, thisChannelArray, m_arrayData)); + EXCEPTION_GUARD(m_channelArrayRequester->getArrayDone(status, thisPtr, m_arrayData)); } else if (qos & QOS_GET_PUT) { - EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(status, thisChannelArray)); + EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(status, thisPtr)); } else if (qos & QOS_PROCESS) { size_t length = SerializeHelper::readSize(payloadBuffer, transport.get()); - EXCEPTION_GUARD(m_channelArrayRequester->getLengthDone(status, thisChannelArray, length)); + EXCEPTION_GUARD(m_channelArrayRequester->getLengthDone(status, thisPtr, length)); } else { - EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(status, thisChannelArray)); + EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(status, thisPtr)); } } @@ -1718,22 +1682,22 @@ public: // TODO stride == 0 check - ChannelArray::shared_pointer thisChannelArray = dynamic_pointer_cast(shared_from_this()); + ChannelArray::shared_pointer thisPtr(external_from_this()); { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelArrayRequester->getArrayDone(destroyedStatus, thisChannelArray, PVArray::shared_pointer())); + EXCEPTION_GUARD(m_channelArrayRequester->getArrayDone(destroyedStatus, thisPtr, PVArray::shared_pointer())); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelArrayRequester->getArrayDone(notInitializedStatus, thisChannelArray, PVArray::shared_pointer())); + EXCEPTION_GUARD(m_channelArrayRequester->getArrayDone(notInitializedStatus, thisPtr, PVArray::shared_pointer())); return; } } if (!startRequest(m_lastRequest.get() ? QOS_DESTROY | QOS_GET : QOS_GET)) { - EXCEPTION_GUARD(m_channelArrayRequester->getArrayDone(otherRequestPendingStatus, thisChannelArray, PVArray::shared_pointer())); + EXCEPTION_GUARD(m_channelArrayRequester->getArrayDone(otherRequestPendingStatus, thisPtr, PVArray::shared_pointer())); return; } @@ -1744,10 +1708,10 @@ public: m_count = count; m_stride = stride; } - m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); + m_channel->checkAndGetTransport()->enqueueSendRequest(external_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelArrayRequester->getArrayDone(channelNotConnected, thisChannelArray, PVArray::shared_pointer())); + EXCEPTION_GUARD(m_channelArrayRequester->getArrayDone(channelNotConnected, thisPtr, PVArray::shared_pointer())); } } @@ -1755,28 +1719,28 @@ public: // TODO stride == 0 check - ChannelArray::shared_pointer thisChannelArray = dynamic_pointer_cast(shared_from_this()); + ChannelArray::shared_pointer thisPtr(external_from_this()); { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(destroyedStatus, thisChannelArray)); + EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(destroyedStatus, thisPtr)); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(notInitializedStatus, thisChannelArray)); + EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(notInitializedStatus, thisPtr)); return; } } if (!(*m_arrayData->getArray() == *putArray->getArray())) { - EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(invalidPutArrayStatus, thisChannelArray)); + EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(invalidPutArrayStatus, thisPtr)); return; } if (!startRequest(m_lastRequest.get() ? QOS_DESTROY : QOS_DEFAULT)) { - EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(otherRequestPendingStatus, thisChannelArray)); + EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(otherRequestPendingStatus, thisPtr)); return; } @@ -1788,31 +1752,31 @@ public: m_count = count; m_stride = stride; } - m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); + m_channel->checkAndGetTransport()->enqueueSendRequest(external_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(channelNotConnected, thisChannelArray)); + EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(channelNotConnected, thisPtr)); } } virtual void setLength(size_t length) { - ChannelArray::shared_pointer thisChannelArray = dynamic_pointer_cast(shared_from_this()); + ChannelArray::shared_pointer thisPtr(external_from_this()); { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(destroyedStatus, thisChannelArray)); + EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(destroyedStatus, thisPtr)); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(notInitializedStatus, thisChannelArray)); + EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(notInitializedStatus, thisPtr)); return; } } if (!startRequest(m_lastRequest.get() ? QOS_DESTROY | QOS_GET_PUT : QOS_GET_PUT)) { - EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(otherRequestPendingStatus, thisChannelArray)); + EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(otherRequestPendingStatus, thisPtr)); return; } @@ -1821,40 +1785,40 @@ public: Lock lock(m_structureMutex); m_length = length; } - m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); + m_channel->checkAndGetTransport()->enqueueSendRequest(external_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(channelNotConnected, thisChannelArray)); + EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(channelNotConnected, thisPtr)); } } virtual void getLength() { - ChannelArray::shared_pointer thisChannelArray = dynamic_pointer_cast(shared_from_this()); + ChannelArray::shared_pointer thisPtr(external_from_this()); { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelArrayRequester->getLengthDone(destroyedStatus, thisChannelArray, 0)); + EXCEPTION_GUARD(m_channelArrayRequester->getLengthDone(destroyedStatus, thisPtr, 0)); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelArrayRequester->getLengthDone(notInitializedStatus, thisChannelArray, 0)); + EXCEPTION_GUARD(m_channelArrayRequester->getLengthDone(notInitializedStatus, thisPtr, 0)); return; } } if (!startRequest(m_lastRequest.get() ? QOS_DESTROY | QOS_PROCESS : QOS_PROCESS)) { - EXCEPTION_GUARD(m_channelArrayRequester->getLengthDone(otherRequestPendingStatus, thisChannelArray, 0)); + EXCEPTION_GUARD(m_channelArrayRequester->getLengthDone(otherRequestPendingStatus, thisPtr, 0)); return; } try { - m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); + m_channel->checkAndGetTransport()->enqueueSendRequest(external_from_this()); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelArrayRequester->getLengthDone(channelNotConnected, thisChannelArray, 0)); + EXCEPTION_GUARD(m_channelArrayRequester->getLengthDone(channelNotConnected, thisPtr, 0)); } } @@ -1895,147 +1859,6 @@ public: - - -PVACCESS_REFCOUNT_MONITOR_DEFINE(channelGetField); - -// NOTE: this instance is not returned as Request, so it must self-destruct -class ChannelGetFieldRequestImpl : - public DataResponse, - public TransportSender, - public std::tr1::enable_shared_from_this -{ -public: - typedef std::tr1::shared_ptr shared_pointer; - typedef std::tr1::shared_ptr const_shared_pointer; - -private: - ChannelImpl::shared_pointer m_channel; - - GetFieldRequester::shared_pointer m_callback; - string m_subField; - - pvAccessID m_ioid; - - Mutex m_mutex; - bool m_destroyed; - - ResponseRequest::shared_pointer m_thisPointer; - - ChannelGetFieldRequestImpl(ChannelImpl::shared_pointer const & channel, GetFieldRequester::shared_pointer const & callback, string const & subField) : - m_channel(channel), - m_callback(callback), - m_subField(subField), - m_ioid(INVALID_IOID), - m_destroyed(false) - { - PVACCESS_REFCOUNT_MONITOR_CONSTRUCT(channelGetField); - } - - void activate() - { - // register response request - m_thisPointer = shared_from_this(); - m_ioid = m_channel->getContext()->registerResponseRequest(m_thisPointer); - m_channel->registerResponseRequest(m_thisPointer); - - // enqueue send request - try { - m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); - } catch (std::runtime_error &rte) { - EXCEPTION_GUARD(m_callback->getDone(BaseRequestImpl::channelNotConnected, FieldConstPtr())); - } - } - -public: - static shared_pointer create(ChannelImpl::shared_pointer const & channel, GetFieldRequester::shared_pointer const & callback, string const & subField) - { - shared_pointer thisPointer(new ChannelGetFieldRequestImpl(channel, callback, subField), delayed_destroyable_deleter()); - thisPointer->activate(); - return thisPointer; - } - - ~ChannelGetFieldRequestImpl() - { - PVACCESS_REFCOUNT_MONITOR_DESTRUCT(channelGetField); - } - - ChannelBaseRequester::shared_pointer getRequester() { - return m_callback; - } - - pvAccessID getIOID() const { - return m_ioid; - } - - virtual void send(ByteBuffer* buffer, TransportSendControl* control) { - control->startMessage((int8)17, 8); - buffer->putInt(m_channel->getServerChannelID()); - buffer->putInt(m_ioid); - SerializeHelper::serializeString(m_subField, buffer, control); - } - - - virtual Channel::shared_pointer getChannel() - { - return m_channel; - } - - virtual void cancel() { - // TODO - // noop - } - - virtual void timeout() { - cancel(); - } - - void reportStatus(Channel::ConnectionState status) { - // destroy, since channel (parent) was destroyed - if (status == Channel::DESTROYED) - destroy(); - // TODO notify? - } - - virtual void destroy() - { - { - Lock guard(m_mutex); - if (m_destroyed) - return; - m_destroyed = true; - } - - // unregister response request - m_channel->getContext()->unregisterResponseRequest(m_ioid); - m_channel->unregisterResponseRequest(m_ioid); - - m_thisPointer.reset(); - } - - virtual void response(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer) { - - Status status; - status.deserialize(payloadBuffer, transport.get()); - if (status.isSuccess()) - { - // deserialize Field... - FieldConstPtr field = transport->cachedDeserialize(payloadBuffer); - EXCEPTION_GUARD(m_callback->getDone(status, field)); - } - else - { - EXCEPTION_GUARD(m_callback->getDone(status, FieldConstPtr())); - } - - destroy(); - } - - -}; - - - class MonitorStrategy : public Monitor { public: virtual ~MonitorStrategy() {}; @@ -2346,7 +2169,8 @@ class ChannelMonitorImpl : public BaseRequestImpl, public Monitor { -private: +public: + typedef MonitorRequester requester_type; MonitorRequester::shared_pointer m_monitorRequester; bool m_started; @@ -2374,12 +2198,11 @@ private: PVACCESS_REFCOUNT_MONITOR_CONSTRUCT(channelMonitor); } - void activate() + virtual void activate() { if (!m_pvRequest) { - Monitor::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_monitorRequester->monitorConnect(pvRequestNull, thisPointer, StructureConstPtr())); + EXCEPTION_GUARD(m_monitorRequester->monitorConnect(pvRequestNull, external_from_this(), StructureConstPtr())); return; } @@ -2437,8 +2260,7 @@ private: try { resubscribeSubscription(m_channel->checkDestroyedAndGetTransport()); } catch (std::runtime_error &rte) { - Monitor::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_monitorRequester->monitorConnect(channelDestroyed, thisPointer, StructureConstPtr())); + EXCEPTION_GUARD(m_monitorRequester->monitorConnect(channelDestroyed, external_from_this(), StructureConstPtr())); BaseRequestImpl::destroy(true); } } @@ -2449,25 +2271,17 @@ private: startRequest(m_pipeline ? (QOS_INIT | QOS_GET_PUT) : QOS_INIT)) { m_subscribed.set(); - transport->enqueueSendRequest(shared_from_this()); + transport->enqueueSendRequest(external_from_this()); } } public: static Monitor::shared_pointer create( ChannelImpl::shared_pointer const & channel, - MonitorRequester::shared_pointer const & monitorRequester, + MonitorRequester::shared_pointer const & requester, PVStructure::shared_pointer const & pvRequest) { - // TODO use std::make_shared - std::tr1::shared_ptr tp( - new ChannelMonitorImpl( - channel, monitorRequester, - pvRequest), - delayed_destroyable_deleter()); - Monitor::shared_pointer thisPointer = tp; - static_cast(thisPointer.get())->activate(); - return thisPointer; + return build(channel, requester, pvRequest); } ~ChannelMonitorImpl() @@ -2513,8 +2327,7 @@ public: { if (!status.isSuccess()) { - Monitor::shared_pointer thisChannelMonitor = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_monitorRequester->monitorConnect(status, thisChannelMonitor, StructureConstPtr())); + EXCEPTION_GUARD(m_monitorRequester->monitorConnect(status, external_from_this(), StructureConstPtr())); return; } @@ -2527,8 +2340,7 @@ public: bool restoreStartedState = m_started; // notify - Monitor::shared_pointer thisChannelMonitor = dynamic_pointer_cast(shared_from_this()); - EXCEPTION_GUARD(m_monitorRequester->monitorConnect(status, thisChannelMonitor, structure)); + EXCEPTION_GUARD(m_monitorRequester->monitorConnect(status, external_from_this(), structure)); if (restoreStartedState) start(); @@ -2616,7 +2428,7 @@ public: try { - m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); + m_channel->checkAndGetTransport()->enqueueSendRequest(external_from_this()); m_started = true; return Status::Ok; } catch (std::runtime_error &rte) { @@ -2642,7 +2454,7 @@ public: try { - m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); + m_channel->checkAndGetTransport()->enqueueSendRequest(external_from_this()); m_started = false; return Status::Ok; } catch (std::runtime_error &rte) { @@ -3356,7 +3168,7 @@ public: // NOTE it's up to internal code to respond w/ error to requester and return 0 in case of errors } -private: +public: /** * Implementation of Channel. */ @@ -3365,6 +3177,8 @@ private: public std::tr1::enable_shared_from_this, public TimerCallback { + public: + POINTER_DEFINITIONS(InternalChannelImpl); private: /** @@ -3387,6 +3201,12 @@ private: */ ChannelRequester::shared_pointer m_requester; + public: + //! The in-progress GetField operation. + //! held here as the present API doesn't support cancellation + std::tr1::shared_ptr m_getfield; + private: + /** * Process priority. */ @@ -3437,12 +3257,12 @@ private: * Server channel ID. */ pvAccessID m_serverChannelID; - +public: /** * Context sync. mutex. */ Mutex m_channelMutex; - +private: /** * Flag indicting what message to send. */ @@ -3505,12 +3325,14 @@ private: short priority, auto_ptr& addresses) { - // TODO use std::make_shared std::tr1::shared_ptr tp( - new InternalChannelImpl(context, channelID, name, requester, priority, addresses), - delayed_destroyable_deleter()); + new InternalChannelImpl(context, channelID, name, requester, priority, addresses)); ChannelImpl::shared_pointer thisPointer = tp; static_cast(thisPointer.get())->activate(); + { + ChannelImpl::shared_pointer wrap(thisPointer.get(), Destroyable::cleaner(thisPointer)); + thisPointer.swap(wrap); + } return thisPointer; } @@ -3534,6 +3356,8 @@ private: std::cout << "[" << getRequesterName() << "] message(" << message << ", " << getMessageTypeName(messageType) << ")" << std::endl; } + private: + int32_t& getUserValue() { return m_userValue; } @@ -3589,7 +3413,7 @@ private: pvAccessID getChannelID() { return m_channelID; } - +public: virtual ClientContextImpl::shared_pointer getContext() { return m_context; } @@ -4193,10 +4017,7 @@ private: } } - virtual void getField(GetFieldRequester::shared_pointer const & requester,std::string const & subField) - { - ChannelGetFieldRequestImpl::create(shared_from_this(), requester, subField); - } + virtual void getField(GetFieldRequester::shared_pointer const & requester,std::string const & subField); virtual ChannelProcess::shared_pointer createChannelProcess( ChannelProcessRequester::shared_pointer const & channelProcessRequester, @@ -4974,11 +4795,179 @@ private: FlushStrategy m_flushStrategy; }; +PVACCESS_REFCOUNT_MONITOR_DEFINE(channelGetField); + +class ChannelGetFieldRequestImpl : + public DataResponse, + public TransportSender, + public Destroyable, + public std::tr1::enable_shared_from_this +{ +public: + POINTER_DEFINITIONS(ChannelGetFieldRequestImpl); + + const InternalClientContextImpl::InternalChannelImpl::shared_pointer m_channel; + + const GetFieldRequester::shared_pointer m_callback; + string m_subField; + + pvAccessID m_ioid; + + Mutex m_mutex; + bool m_destroyed; + bool m_notified; + + ChannelGetFieldRequestImpl(InternalClientContextImpl::InternalChannelImpl::shared_pointer const & channel, + GetFieldRequester::shared_pointer const & callback, + std::string const & subField) : + m_channel(channel), + m_callback(callback), + m_subField(subField), + m_ioid(INVALID_IOID), + m_destroyed(false), + m_notified(false) + { + PVACCESS_REFCOUNT_MONITOR_CONSTRUCT(channelGetField); + } + + void activate() + { + { + // register response request + ChannelGetFieldRequestImpl::shared_pointer self(shared_from_this()); + m_ioid = m_channel->getContext()->registerResponseRequest(self); + m_channel->registerResponseRequest(self); + { + Lock L(m_channel->m_channelMutex); + m_channel->m_getfield.swap(self); + } + // self goes out of scope, may call GetFieldRequester::getDone() from dtor + } + + // enqueue send request + try { + m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this()); + } catch (std::runtime_error &rte) { + notify(BaseRequestImpl::channelNotConnected, FieldConstPtr()); + } + } + +public: + static void create(InternalClientContextImpl::InternalChannelImpl::shared_pointer const & channel, + GetFieldRequester::shared_pointer const & requester, + std::string const & subField) + { + ChannelGetFieldRequestImpl::shared_pointer self(new ChannelGetFieldRequestImpl(channel, requester, subField)); + self->activate(); + // activate() stores self in channel + } + + virtual ~ChannelGetFieldRequestImpl() + { + destroy(); + notify(BaseRequestImpl::channelDestroyed, FieldConstPtr()); + + PVACCESS_REFCOUNT_MONITOR_DESTRUCT(channelGetField); + } + + void notify(const Status& sts, const FieldConstPtr& field) + { + { + Lock G(m_mutex); + if(m_notified) + return; + m_notified = true; + } + EXCEPTION_GUARD(m_callback->getDone(sts, field)); + } + + ChannelBaseRequester::shared_pointer getRequester() { + return m_callback; + } + + pvAccessID getIOID() const { + return m_ioid; + } + + virtual void send(ByteBuffer* buffer, TransportSendControl* control) { + control->startMessage((int8)17, 8); + buffer->putInt(m_channel->getServerChannelID()); + buffer->putInt(m_ioid); + SerializeHelper::serializeString(m_subField, buffer, control); + } + + + virtual Channel::shared_pointer getChannel() + { + return m_channel; + } + + virtual void cancel() { + // TODO + // noop + } + + virtual void timeout() { + cancel(); + } + + void reportStatus(Channel::ConnectionState status) { + // destroy, since channel (parent) was destroyed + if (status == Channel::DESTROYED) + destroy(); + // TODO notify? + } + + virtual void destroy() + { + { + Lock guard(m_mutex); + if (m_destroyed) + return; + m_destroyed = true; + } + + { + Lock L(m_channel->m_channelMutex); + if(m_channel->m_getfield.get()==this) + m_channel->m_getfield.reset(); + } + + // unregister response request + m_channel->getContext()->unregisterResponseRequest(m_ioid); + m_channel->unregisterResponseRequest(m_ioid); + } + + virtual void response(Transport::shared_pointer const & transport, int8 /*version*/, ByteBuffer* payloadBuffer) { + + Status status; + FieldConstPtr field; + status.deserialize(payloadBuffer, transport.get()); + if (status.isSuccess()) + { + // deserialize Field... + field = transport->cachedDeserialize(payloadBuffer); + } + notify(status, field); + + destroy(); + } + + +}; + + +void InternalClientContextImpl::InternalChannelImpl::getField(GetFieldRequester::shared_pointer const & requester,std::string const & subField) +{ + ChannelGetFieldRequestImpl::create(shared_from_this(), requester, subField); +} + ChannelProvider::shared_pointer createClientProvider(const Configuration::shared_pointer& conf) { - InternalClientContextImpl::shared_pointer t(new InternalClientContextImpl(conf), delayed_destroyable_deleter()); - t->initialize(); - return t; + InternalClientContextImpl::shared_pointer internal(new InternalClientContextImpl(conf)), + external(internal.get(), Destroyable::cleaner(internal)); + internal->initialize(); + return external; } } diff --git a/testApp/remote/channelAccessIFTest.cpp b/testApp/remote/channelAccessIFTest.cpp index e35d731..bf14c0b 100644 --- a/testApp/remote/channelAccessIFTest.cpp +++ b/testApp/remote/channelAccessIFTest.cpp @@ -181,9 +181,9 @@ SyncChannelGetRequesterImpl::shared_pointer ChannelAccessIFTest::syncCreateChann TR1::shared_ptr channelGetReq(new SyncChannelGetRequesterImpl(channel->getChannelName(), debug)); - PVStructure::shared_pointer pvRequest = CreateRequest::create()->createRequest(request); + PVStructure::shared_pointer pvRequest = createRequest(request); - channel->createChannelGet(channelGetReq,pvRequest); + ChannelGet::shared_pointer op(channel->createChannelGet(channelGetReq,pvRequest)); bool succStatus = channelGetReq->waitUntilGetDone(getTimeoutSec()); if (!succStatus) { std::cerr << "[" << channel->getChannelName() << "] failed to get. " << std::endl; @@ -201,9 +201,9 @@ SyncChannelPutRequesterImpl::shared_pointer ChannelAccessIFTest::syncCreateChann channelPutReq(new SyncChannelPutRequesterImpl(channel->getChannelName(), debug)); - PVStructure::shared_pointer pvRequest = CreateRequest::create()->createRequest(request); + PVStructure::shared_pointer pvRequest = createRequest(request); - channel->createChannelPut(channelPutReq,pvRequest); + ChannelPut::shared_pointer op(channel->createChannelPut(channelPutReq,pvRequest)); bool succStatus = channelPutReq->waitUntilConnected(getTimeoutSec()); if (!succStatus) { @@ -221,9 +221,9 @@ SyncChannelPutGetRequesterImpl::shared_pointer ChannelAccessIFTest::syncCreateCh TR1::shared_ptr channelPutGetReq(new SyncChannelPutGetRequesterImpl(debug)); - PVStructure::shared_pointer pvRequest = CreateRequest::create()->createRequest(request); + PVStructure::shared_pointer pvRequest = createRequest(request); - channel->createChannelPutGet(channelPutGetReq,pvRequest); + ChannelPutGet::shared_pointer op(channel->createChannelPutGet(channelPutGetReq,pvRequest)); bool succStatus = channelPutGetReq->waitUntilConnected(getTimeoutSec()); if (!succStatus) { @@ -243,7 +243,7 @@ SyncChannelRPCRequesterImpl::shared_pointer ChannelAccessIFTest::syncCreateChann PVStructure::shared_pointer pvRequest = CreateRequest::create()->createRequest(string()); - channel->createChannelRPC(channelRPCReq, pvRequest); + ChannelRPC::shared_pointer op(channel->createChannelRPC(channelRPCReq, pvRequest)); bool succStatus = channelRPCReq->waitUntilConnected(getTimeoutSec()); if (!succStatus) { @@ -259,9 +259,9 @@ SyncMonitorRequesterImpl::shared_pointer ChannelAccessIFTest::syncCreateChannelM { TR1::shared_ptr monitorReq(new SyncMonitorRequesterImpl(debug)); - PVStructure::shared_pointer pvRequest = CreateRequest::create()->createRequest(request); + PVStructure::shared_pointer pvRequest = createRequest(request); - channel->createMonitor(monitorReq, pvRequest); + Monitor::shared_pointer op(channel->createMonitor(monitorReq, pvRequest)); bool succStatus = monitorReq->waitUntilConnected(getTimeoutSec()); if (!succStatus) { @@ -277,7 +277,7 @@ SyncChannelArrayRequesterImpl::shared_pointer ChannelAccessIFTest::syncCreateCha { TR1::shared_ptr arrayReq(new SyncChannelArrayRequesterImpl(debug)); - channel->createChannelArray(arrayReq, pvRequest); + ChannelArray::shared_pointer op(channel->createChannelArray(arrayReq, pvRequest)); bool succStatus = arrayReq->waitUntilConnected(getTimeoutSec()); if (!succStatus) { @@ -519,6 +519,7 @@ void ChannelAccessIFTest::test_channelGetNoProcess() { return; } + testDiag("start Get"); SyncChannelGetRequesterImpl::shared_pointer channelGetReq = syncCreateChannelGet(channel,request); if (!channelGetReq.get()) { From edcb408e92efcfd663064732b8d5923679a283a0 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 7 Jun 2017 14:24:39 +0200 Subject: [PATCH 043/189] eget/pvget: must keep Monitor alive --- pvtoolsSrc/eget.cpp | 3 ++- pvtoolsSrc/pvget.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pvtoolsSrc/eget.cpp b/pvtoolsSrc/eget.cpp index 00508c6..d3a4d0c 100644 --- a/pvtoolsSrc/eget.cpp +++ b/pvtoolsSrc/eget.cpp @@ -1690,6 +1690,7 @@ int main (int argc, char *argv[]) vector pvs; vector pvsAddress; vector providerNames; + vector operations; if (validURI) { @@ -1865,7 +1866,7 @@ int main (int argc, char *argv[]) if (channelRequesterImpl->waitUntilConnected(timeOut)) { TR1::shared_ptr monitorRequesterImpl(new MonitorRequesterImpl(channel->getChannelName())); - channel->createMonitor(monitorRequesterImpl, pvRequest); + operations.push_back(channel->createMonitor(monitorRequesterImpl, pvRequest)); } else { diff --git a/pvtoolsSrc/pvget.cpp b/pvtoolsSrc/pvget.cpp index 38771c1..6a322f8 100644 --- a/pvtoolsSrc/pvget.cpp +++ b/pvtoolsSrc/pvget.cpp @@ -575,6 +575,7 @@ int main (int argc, char *argv[]) // first connect to all, this allows resource (e.g. TCP connection) sharing vector channels(nPvs); + vector operations(nPvs); for (int n = 0; n < nPvs; n++) { TR1::shared_ptr channelRequesterImpl(new ChannelRequesterImpl(quiet)); @@ -635,7 +636,7 @@ int main (int argc, char *argv[]) channelRequesterImpl->showDisconnectMessage(); TR1::shared_ptr monitorRequesterImpl(new MonitorRequesterImpl(channel->getChannelName())); - Monitor::shared_pointer monitorGet = channel->createMonitor(monitorRequesterImpl, pvRequest); + operations[n] = channel->createMonitor(monitorRequesterImpl, pvRequest); allOK &= true; } } From 9cbc8fdea6ad8874253078d8f15017a4a4f52d63 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 7 Jun 2017 14:36:15 +0200 Subject: [PATCH 044/189] handle multiple ClientFactory::start() --- src/pva/clientFactory.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/pva/clientFactory.cpp b/src/pva/clientFactory.cpp index 6ffdbed..2f43a04 100644 --- a/src/pva/clientFactory.cpp +++ b/src/pva/clientFactory.cpp @@ -7,7 +7,7 @@ #include #include - +#include #include #define epicsExportSharedSymbols @@ -18,15 +18,26 @@ using namespace epics::pvData; using namespace epics::pvAccess; +static +void pva_factory_cleanup(void*) +{ + try { + getChannelProviderRegistry()->remove("pva"); + } catch(std::exception& e) { + LOG(logLevelWarn, "Error when unregister \"pva\" factory"); + } +} + void ClientFactory::start() { epicsSignalInstallSigAlarmIgnore(); epicsSignalInstallSigPipeIgnore(); - getChannelProviderRegistry()->add("pva", createClientProvider, false); + if(getChannelProviderRegistry()->add("pva", createClientProvider, false)) + epicsAtExit(&pva_factory_cleanup, NULL); } void ClientFactory::stop() { - getChannelProviderRegistry()->remove("pva"); + // unregister now done with exit hook } From d0915581b4c6fae5b3ff622e940ada526e44c204 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 7 Jun 2017 19:59:56 +0200 Subject: [PATCH 045/189] rationalize CLI handling of providers --- pvtoolsSrc/eget.cpp | 142 ++++++++++++++++-------------------------- pvtoolsSrc/pvget.cpp | 41 ++++++------ pvtoolsSrc/pvinfo.cpp | 34 +++++----- pvtoolsSrc/pvput.cpp | 21 +++---- 4 files changed, 95 insertions(+), 143 deletions(-) diff --git a/pvtoolsSrc/eget.cpp b/pvtoolsSrc/eget.cpp index d3a4d0c..cc5a803 100644 --- a/pvtoolsSrc/eget.cpp +++ b/pvtoolsSrc/eget.cpp @@ -1664,8 +1664,6 @@ int main (int argc, char *argv[]) bool allOK = true; - Requester::shared_pointer requester(new RequesterImpl("eget")); - // parse URI // try to parse as URI if only one nPvs URI uri; @@ -1682,14 +1680,16 @@ int main (int argc, char *argv[]) serviceRequest = true; } - static string noAddress; + // register "pva" and "ca" providers + ClientFactory::start(); + epics::pvAccess::ca::CAClientFactory::start(); // PVs mode if (!serviceRequest) { vector pvs; vector pvsAddress; - vector providerNames; + vector providers; vector operations; if (validURI) @@ -1714,26 +1714,38 @@ int main (int argc, char *argv[]) // skip trailing '/' pvs.push_back(uri.path.substr(1)); pvsAddress.push_back(uri.host); - providerNames.push_back(uri.protocol); + providers.push_back(getChannelProviderRegistry()->getProvider(uri.protocol)); + if(!providers.back()) { + std::cerr<<"Unknown provider \""< uris; + + if(!fromStream) { + for (int n = 0; optind < argc; n++, optind++) + { + uris.push_back(argv[optind]); + } + } else { + string cn; + while (true) + { + *inputStream >> cn; + if (!(*inputStream)) + break; + uris.push_back(cn); + } + } + + for (size_t n = 0; ngetProvider(uri.protocol)); } else { - pvs.push_back(argv[optind]); - pvsAddress.push_back(noAddress); - providerNames.push_back(defaultProvider); + uri.protocol = defaultProvider; + pvs.push_back(uris[n]); + pvsAddress.push_back(std::string()); + providers.push_back(getChannelProviderRegistry()->getProvider(defaultProvider)); + } + + if(!providers.back()) { + std::cerr<<"Unknown provider \""<createRequest(request); if(pvRequest.get()==0) { @@ -1762,20 +1782,21 @@ int main (int argc, char *argv[]) return 1; } - // register "pva" and "ca" providers - ClientFactory::start(); - epics::pvAccess::ca::CAClientFactory::start(); - // first connect to all, this allows resource (e.g. TCP connection) sharing vector channels(nPvs); for (int n = 0; n < nPvs; n++) { + if(!providers[n]) continue; TR1::shared_ptr channelRequesterImpl(new ChannelRequesterImpl(quiet)); if (pvsAddress[n].empty()) - channels[n] = getChannelProviderRegistry()->getProvider(providerNames[n])->createChannel(pvs[n], channelRequesterImpl); + channels[n] = providers[n]->createChannel(pvs[n], channelRequesterImpl); else - channels[n] = getChannelProviderRegistry()->getProvider(providerNames[n])->createChannel(pvs[n], channelRequesterImpl, + channels[n] = providers[n]->createChannel(pvs[n], channelRequesterImpl, ChannelProvider::PRIORITY_DEFAULT, pvsAddress[n]); + + if(!channels[n]) { + std::cerr<<"No such channel '"<= nPvs) - break; - channel = channels[n]; - } - else - { - string cn; - string ca; - string cp; - - // read next channel name from stream - *inputStream >> cn; - if (!(*inputStream)) - break; - - URI uri; - bool validURI = URI::parse(cn.c_str(), uri); - if (validURI) - { - // TODO this is copy&pase code from above, clean it up - // for now no only pva/ca schema is supported, without authority - // TODO - if (uri.protocol != "pva" && uri.protocol != "ca") - { - std::cerr << "invalid URI scheme '" << uri.protocol << "', only 'pva' and 'ca' are supported" << std::endl; - // TODO - return 1; - } - - if (uri.path.length() <= 1) - { - std::cerr << "invalid URI, empty path" << std::endl; - // TODO - return 1; - } - - // skip trailing '/' - cn = uri.path.substr(1); - ca = uri.host; - cp = uri.protocol; - } - else - { - // leave cn as it is, use default provider - ca = noAddress; - cp = defaultProvider; - } - - - - TR1::shared_ptr channelRequesterImpl(new ChannelRequesterImpl(quiet)); - if (ca.empty()) - channel = getChannelProviderRegistry()->getProvider(cp)->createChannel(cn, channelRequesterImpl); - else - channel = getChannelProviderRegistry()->getProvider(cp)->createChannel(cn, channelRequesterImpl, - ChannelProvider::PRIORITY_DEFAULT, ca); + if(!channel) { + allOK = false; + continue; } if (monitor) @@ -2101,6 +2066,7 @@ int main (int argc, char *argv[]) ClientFactory::start(); ChannelProvider::shared_pointer provider = getChannelProviderRegistry()->getProvider("pva"); + assert(provider); TR1::shared_ptr channelRequesterImpl(new ChannelRequesterImpl(quiet)); Channel::shared_pointer channel = diff --git a/pvtoolsSrc/pvget.cpp b/pvtoolsSrc/pvget.cpp index 6a322f8..73fc59a 100644 --- a/pvtoolsSrc/pvget.cpp +++ b/pvtoolsSrc/pvget.cpp @@ -516,11 +516,12 @@ int main (int argc, char *argv[]) std::cout << std::boolalpha; terseSeparator(fieldSeparator); + ClientFactory::start(); + epics::pvAccess::ca::CAClientFactory::start(); + bool allOK = true; { - Requester::shared_pointer requester(new RequesterImpl("pvget")); - PVStructure::shared_pointer pvRequest = CreateRequest::create()->createRequest(request); if(pvRequest.get()==NULL) { fprintf(stderr, "failed to parse request string\n"); @@ -529,11 +530,10 @@ int main (int argc, char *argv[]) std::vector pvNames; std::vector pvAddresses; - std::vector providerNames; + std::vector providers; pvNames.reserve(nPvs); pvAddresses.reserve(nPvs); - providerNames.reserve(nPvs); for (int n = 0; n < nPvs; n++) { @@ -543,7 +543,7 @@ int main (int argc, char *argv[]) std::string providerName(defaultProvider); std::string pvName(pvs[n]); std::string address(noAddress); - bool usingDefaultProvider = true; + if (validURI) { if (uri.path.length() <= 1) @@ -554,44 +554,41 @@ int main (int argc, char *argv[]) providerName = uri.protocol; pvName = uri.path.substr(1); address = uri.host; - usingDefaultProvider = false; } - if ((providerName != "pva") && (providerName != "ca")) - { - std::cerr << "invalid " - << (usingDefaultProvider ? "default provider" : "URI scheme") - << " '" << providerName - << "', only 'pva' and 'ca' are supported" << std::endl; - return 1; - } pvNames.push_back(pvName); pvAddresses.push_back(address); - providerNames.push_back(providerName); + providers.push_back(getChannelProviderRegistry()->getProvider(providerName)); + if(!providers.back()) { + std::cerr<<"Unknown provider \""< channels(nPvs); vector operations(nPvs); for (int n = 0; n < nPvs; n++) { + if(!providers[n]) continue; TR1::shared_ptr channelRequesterImpl(new ChannelRequesterImpl(quiet)); if (pvAddresses[n].empty()) - channels[n] = getChannelProviderRegistry()->getProvider( - providerNames[n])->createChannel(pvNames[n], channelRequesterImpl); + channels[n] = providers[n]->createChannel(pvNames[n], channelRequesterImpl); else - channels[n] = getChannelProviderRegistry()->getProvider( - providerNames[n])->createChannel(pvNames[n], channelRequesterImpl, + channels[n] = providers[n]->createChannel(pvNames[n], channelRequesterImpl, ChannelProvider::PRIORITY_DEFAULT, pvAddresses[n]); + if(!channels[n]) { + std::cerr<<"Can't create channel \""<getProviderName()<<"\n"; + allOK = false; + } } // for now a simple iterating sync implementation, guarantees order for (int n = 0; n < nPvs; n++) { Channel::shared_pointer channel = channels[n]; + if(!channel) continue; + TR1::shared_ptr channelRequesterImpl = TR1::dynamic_pointer_cast(channel->getChannelRequester()); if (channelRequesterImpl->waitUntilConnected(timeOut)) diff --git a/pvtoolsSrc/pvinfo.cpp b/pvtoolsSrc/pvinfo.cpp index 2ba35cc..1f6c1c2 100644 --- a/pvtoolsSrc/pvinfo.cpp +++ b/pvtoolsSrc/pvinfo.cpp @@ -137,22 +137,22 @@ int main (int argc, char *argv[]) bool allOK = true; + ClientFactory::start(); + epics::pvAccess::ca::CAClientFactory::start(); + { std::vector pvNames; std::vector pvAddresses; - std::vector providerNames; + std::vector providers; pvNames.reserve(nPvs); pvAddresses.reserve(nPvs); - providerNames.reserve(nPvs); for (int n = 0; n < nPvs; n++) { URI uri; bool validURI = URI::parse(pvs[n], uri); - TR1::shared_ptr channelRequesterImpl(new ChannelRequesterImpl()); - std::string providerName(defaultProvider); std::string pvName(pvs[n]); std::string address(noAddress); @@ -170,33 +170,27 @@ int main (int argc, char *argv[]) usingDefaultProvider = false; } - if ((providerName != "pva") && (providerName != "ca")) - { - std::cerr << "invalid " - << (usingDefaultProvider ? "default provider" : "URI scheme") - << " '" << providerName - << "', only 'pva' and 'ca' are supported" << std::endl; - return 1; - } pvNames.push_back(pvName); pvAddresses.push_back(address); - providerNames.push_back(providerName); + providers.push_back(getChannelProviderRegistry()->getProvider(providerName)); + if(!providers.back()) + { + std::cerr << "unknown provider name '" << providerName + << "', only 'pva' and 'ca' are supported" << std::endl; + allOK = false; + } } - ClientFactory::start(); - epics::pvAccess::ca::CAClientFactory::start(); - // first connect to all, this allows resource (e.g. TCP connection) sharing vector channels(nPvs); for (int n = 0; n < nPvs; n++) { + if(!providers[n]) continue; TR1::shared_ptr channelRequesterImpl(new ChannelRequesterImpl()); if (pvAddresses[n].empty()) - channels[n] = getChannelProviderRegistry()->getProvider( - providerNames[n])->createChannel(pvNames[n], channelRequesterImpl); + channels[n] = providers[n]->createChannel(pvNames[n], channelRequesterImpl); else - channels[n] = getChannelProviderRegistry()->getProvider( - providerNames[n])->createChannel(pvNames[n], channelRequesterImpl, + channels[n] = providers[n]->createChannel(pvNames[n], channelRequesterImpl, ChannelProvider::PRIORITY_DEFAULT, pvAddresses[n]); } diff --git a/pvtoolsSrc/pvput.cpp b/pvtoolsSrc/pvput.cpp index 9eb9e89..5062c19 100644 --- a/pvtoolsSrc/pvput.cpp +++ b/pvtoolsSrc/pvput.cpp @@ -642,12 +642,12 @@ int main (int argc, char *argv[]) usingDefaultProvider = false; } - if ((providerName != "pva") && (providerName != "ca")) - { - std::cerr << "invalid " - << (usingDefaultProvider ? "default provider" : "URI scheme") - << " '" << providerName - << "', only 'pva' and 'ca' are supported" << std::endl; + ClientFactory::start(); + epics::pvAccess::ca::CAClientFactory::start(); + + ChannelProvider::shared_pointer provider(getChannelProviderRegistry()->getProvider(providerName)); + if(!provider) { + std::cerr << "Unknown provider '"<getProvider( - providerName)->createChannel(pvName, channelRequesterImpl); + channel = provider->createChannel(pvName, channelRequesterImpl); else - channel = getChannelProviderRegistry()->getProvider( - providerName)->createChannel(pvName, channelRequesterImpl, + channel = provider->createChannel(pvName, channelRequesterImpl, ChannelProvider::PRIORITY_DEFAULT, address); if (channelRequesterImpl->waitUntilConnected(timeOut)) From 33e842db2ec4bd42085977d3ade93cc36d5382bd Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 8 Jun 2017 16:23:15 +0200 Subject: [PATCH 046/189] boilerplate reduction --- src/remoteClient/clientContextImpl.cpp | 88 ++++++-------------------- src/server/responseHandlers.cpp | 5 +- 2 files changed, 21 insertions(+), 72 deletions(-) diff --git a/src/remoteClient/clientContextImpl.cpp b/src/remoteClient/clientContextImpl.cpp index a4a401c..28d0e58 100644 --- a/src/remoteClient/clientContextImpl.cpp +++ b/src/remoteClient/clientContextImpl.cpp @@ -159,7 +159,7 @@ protected: ResponseRequest::shared_pointer P(m_this_external); return std::tr1::static_pointer_cast(P); } - +public: template static typename std::tr1::shared_ptr @@ -177,7 +177,7 @@ protected: internal->activate(); return external; } - +protected: bool m_destroyed; bool m_initialized; @@ -445,13 +445,6 @@ public: } public: - static ChannelProcess::shared_pointer create(ChannelImpl::shared_pointer const & channel, - ChannelProcessRequester::shared_pointer const & requester, - PVStructure::shared_pointer const & pvRequest) - { - return build(channel, requester, pvRequest); - } - ~ChannelProcessRequestImpl() { PVACCESS_REFCOUNT_MONITOR_DESTRUCT(channelProcess); @@ -589,13 +582,6 @@ public: } public: - static ChannelGet::shared_pointer create(ChannelImpl::shared_pointer const & channel, - ChannelGetRequester::shared_pointer const & requester, - PVStructure::shared_pointer const & pvRequest) - { - return build(channel, requester, pvRequest); - } - ~ChannelGetImpl() { PVACCESS_REFCOUNT_MONITOR_DESTRUCT(channelGet); @@ -801,13 +787,6 @@ public: } public: - static ChannelPut::shared_pointer create(ChannelImpl::shared_pointer const & channel, - ChannelPutRequester::shared_pointer const & requester, - PVStructure::shared_pointer const & pvRequest) - { - return build(channel, requester, pvRequest); - } - ~ChannelPutImpl() { PVACCESS_REFCOUNT_MONITOR_DESTRUCT(channelPut); @@ -1365,13 +1344,6 @@ public: } public: - static ChannelRPC::shared_pointer create(ChannelImpl::shared_pointer const & channel, - ChannelRPCRequester::shared_pointer const & requester, - PVStructure::shared_pointer const & pvRequest) - { - return build(channel, requester, pvRequest); - } - ~ChannelRPCImpl() { PVACCESS_REFCOUNT_MONITOR_DESTRUCT(channelRPC); @@ -1562,13 +1534,6 @@ public: } public: - static ChannelArray::shared_pointer create(ChannelImpl::shared_pointer const & channel, - ChannelArrayRequester::shared_pointer const & requester, - PVStructure::shared_pointer const & pvRequest) - { - return build(channel, requester, pvRequest); - } - ~ChannelArrayImpl() { PVACCESS_REFCOUNT_MONITOR_DESTRUCT(channelArray); @@ -2276,14 +2241,6 @@ public: } public: - static Monitor::shared_pointer create( - ChannelImpl::shared_pointer const & channel, - MonitorRequester::shared_pointer const & requester, - PVStructure::shared_pointer const & pvRequest) - { - return build(channel, requester, pvRequest); - } - ~ChannelMonitorImpl() { PVACCESS_REFCOUNT_MONITOR_DESTRUCT(channelMonitor); @@ -4020,52 +3977,52 @@ public: virtual void getField(GetFieldRequester::shared_pointer const & requester,std::string const & subField); virtual ChannelProcess::shared_pointer createChannelProcess( - ChannelProcessRequester::shared_pointer const & channelProcessRequester, + ChannelProcessRequester::shared_pointer const & requester, epics::pvData::PVStructure::shared_pointer const & pvRequest) { - return ChannelProcessRequestImpl::create(shared_from_this(), channelProcessRequester, pvRequest); + return BaseRequestImpl::build(shared_from_this(), requester, pvRequest); } virtual ChannelGet::shared_pointer createChannelGet( - ChannelGetRequester::shared_pointer const & channelGetRequester, + ChannelGetRequester::shared_pointer const & requester, epics::pvData::PVStructure::shared_pointer const & pvRequest) { - return ChannelGetImpl::create(shared_from_this(), channelGetRequester, pvRequest); + return BaseRequestImpl::build(shared_from_this(), requester, pvRequest); } virtual ChannelPut::shared_pointer createChannelPut( - ChannelPutRequester::shared_pointer const & channelPutRequester, + ChannelPutRequester::shared_pointer const & requester, epics::pvData::PVStructure::shared_pointer const & pvRequest) { - return ChannelPutImpl::create(shared_from_this(), channelPutRequester, pvRequest); + return BaseRequestImpl::build(shared_from_this(), requester, pvRequest); } virtual ChannelPutGet::shared_pointer createChannelPutGet( - ChannelPutGetRequester::shared_pointer const & channelPutGetRequester, + ChannelPutGetRequester::shared_pointer const & requester, epics::pvData::PVStructure::shared_pointer const & pvRequest) { - return ChannelPutGetImpl::create(shared_from_this(), channelPutGetRequester, pvRequest); + return BaseRequestImpl::build(shared_from_this(), requester, pvRequest); } virtual ChannelRPC::shared_pointer createChannelRPC( - ChannelRPCRequester::shared_pointer const & channelRPCRequester, + ChannelRPCRequester::shared_pointer const & requester, epics::pvData::PVStructure::shared_pointer const & pvRequest) { - return ChannelRPCImpl::create(shared_from_this(), channelRPCRequester, pvRequest); + return BaseRequestImpl::build(shared_from_this(), requester, pvRequest); } virtual Monitor::shared_pointer createMonitor( - MonitorRequester::shared_pointer const & monitorRequester, + MonitorRequester::shared_pointer const & requester, epics::pvData::PVStructure::shared_pointer const & pvRequest) { - return ChannelMonitorImpl::create(shared_from_this(), monitorRequester, pvRequest); + return BaseRequestImpl::build(shared_from_this(), requester, pvRequest); } virtual ChannelArray::shared_pointer createChannelArray( - ChannelArrayRequester::shared_pointer const & channelArrayRequester, + ChannelArrayRequester::shared_pointer const & requester, epics::pvData::PVStructure::shared_pointer const & pvRequest) { - return ChannelArrayImpl::create(shared_from_this(), channelArrayRequester, pvRequest); + return BaseRequestImpl::build(shared_from_this(), requester, pvRequest); } @@ -4853,15 +4810,6 @@ public: } public: - static void create(InternalClientContextImpl::InternalChannelImpl::shared_pointer const & channel, - GetFieldRequester::shared_pointer const & requester, - std::string const & subField) - { - ChannelGetFieldRequestImpl::shared_pointer self(new ChannelGetFieldRequestImpl(channel, requester, subField)); - self->activate(); - // activate() stores self in channel - } - virtual ~ChannelGetFieldRequestImpl() { destroy(); @@ -4959,7 +4907,9 @@ public: void InternalClientContextImpl::InternalChannelImpl::getField(GetFieldRequester::shared_pointer const & requester,std::string const & subField) { - ChannelGetFieldRequestImpl::create(shared_from_this(), requester, subField); + ChannelGetFieldRequestImpl::shared_pointer self(new ChannelGetFieldRequestImpl(shared_from_this(), requester, subField)); + self->activate(); + // activate() stores self in channel } ChannelProvider::shared_pointer createClientProvider(const Configuration::shared_pointer& conf) diff --git a/src/server/responseHandlers.cpp b/src/server/responseHandlers.cpp index 18b8d49..297f0c0 100644 --- a/src/server/responseHandlers.cpp +++ b/src/server/responseHandlers.cpp @@ -2909,9 +2909,8 @@ ChannelRPCRequester::shared_pointer ServerChannelRPCRequesterImpl::create( { // TODO use std::make_shared std::tr1::shared_ptr tp(new ServerChannelRPCRequesterImpl(context, channel, ioid, transport)); - ChannelRPCRequester::shared_pointer thisPointer = tp; - static_cast(thisPointer.get())->activate(pvRequest); - return thisPointer; + tp->activate(pvRequest); + return tp; } void ServerChannelRPCRequesterImpl::activate(PVStructure::shared_pointer const & pvRequest) From 7f4d48a1765034b0ad418f20ced9e78293d2ead7 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 8 Jun 2017 16:25:26 +0200 Subject: [PATCH 047/189] note ref. loop in response handlers --- src/server/pv/responseHandlers.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/server/pv/responseHandlers.h b/src/server/pv/responseHandlers.h index 8c2b3d1..7efbab3 100644 --- a/src/server/pv/responseHandlers.h +++ b/src/server/pv/responseHandlers.h @@ -329,6 +329,7 @@ public: void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); private: + // Note: this forms a reference loop, which is broken in destroy() ChannelGet::shared_pointer _channelGet; epics::pvData::PVStructure::shared_pointer _pvStructure; epics::pvData::BitSet::shared_pointer _bitSet; @@ -383,6 +384,7 @@ public: epics::pvData::PVStructure::shared_pointer getPutPVStructure(); void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); private: + // Note: this forms a reference loop, which is broken in destroy() ChannelPut::shared_pointer _channelPut; epics::pvData::BitSet::shared_pointer _bitSet; epics::pvData::PVStructure::shared_pointer _pvStructure; @@ -447,6 +449,7 @@ public: void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); private: + // Note: this forms a reference loop, which is broken in destroy() ChannelPutGet::shared_pointer _channelPutGet; epics::pvData::PVStructure::shared_pointer _pvPutStructure; epics::pvData::BitSet::shared_pointer _pvPutBitSet; @@ -502,6 +505,7 @@ public: Monitor::shared_pointer getChannelMonitor(); void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); private: + // Note: this forms a reference loop, which is broken in destroy() Monitor::shared_pointer _channelMonitor; epics::pvData::StructureConstPtr _structure; epics::pvData::Status _status; @@ -561,6 +565,7 @@ public: void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); private: + // Note: this forms a reference loop, which is broken in destroy() ChannelArray::shared_pointer _channelArray; epics::pvData::PVArray::shared_pointer _pvArray; @@ -655,6 +660,7 @@ public: void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); private: + // Note: this forms a reference loop, which is broken in destroy() ChannelProcess::shared_pointer _channelProcess; epics::pvData::Status _status; }; @@ -770,6 +776,7 @@ public: void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); private: + // Note: this forms a reference loop, which is broken in destroy() ChannelRPC::shared_pointer _channelRPC; epics::pvData::PVStructure::shared_pointer _pvResponse; epics::pvData::Status _status; From fabb85c5e335ef725cbae0ad69edf5209c737985 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 8 Jun 2017 18:56:00 +0200 Subject: [PATCH 048/189] stupid typo oops --- src/factory/ChannelAccessFactory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/factory/ChannelAccessFactory.cpp b/src/factory/ChannelAccessFactory.cpp index a82a774..406773b 100644 --- a/src/factory/ChannelAccessFactory.cpp +++ b/src/factory/ChannelAccessFactory.cpp @@ -75,7 +75,7 @@ bool ChannelProviderRegistry::add(const ChannelProviderFactory::shared_pointer& Lock G(mutex); std::string name(fact->getFactoryName()); if(!replace && providers.find(name)!=providers.end()) - throw false; + return false; providers[name] = fact; return true; } From 3e37781d8547d727cc79eec0e18ed0a78f241273 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 8 Jun 2017 20:35:43 +0200 Subject: [PATCH 049/189] update RPCClient Addition ctor to use specific Provider (w/ custom config). Start connect immediately. Remove need to issueConnect()/waitConnect(). --- src/rpcClient/pv/rpcClient.h | 39 ++- src/rpcClient/rpcClient.cpp | 440 ++++++++++++++-------------- testApp/remote/rpcClientExample.cpp | 63 ++-- 3 files changed, 266 insertions(+), 276 deletions(-) diff --git a/src/rpcClient/pv/rpcClient.h b/src/rpcClient/pv/rpcClient.h index fd26e4c..3dcde89 100644 --- a/src/rpcClient/pv/rpcClient.h +++ b/src/rpcClient/pv/rpcClient.h @@ -40,14 +40,6 @@ class epicsShareClass RPCClient public: POINTER_DEFINITIONS(RPCClient); - /** - * Create a RPCClient. - * - * @param serviceName the service name - * @return the RPCClient interface - */ - static shared_pointer create(const std::string & serviceName); - /** * Create a RPCClient. * @@ -56,7 +48,16 @@ public: * @return the RPCClient interface */ static shared_pointer create(const std::string & serviceName, - epics::pvData::PVStructure::shared_pointer const & pvRequest); + epics::pvData::PVStructure::shared_pointer const & pvRequest = epics::pvData::PVStructure::shared_pointer()); + + RPCClient(const std::string & serviceName, + epics::pvData::PVStructure::shared_pointer const & pvRequest); + + RPCClient(const ChannelProvider::shared_pointer& provider, + const std::string & serviceName, + epics::pvData::PVStructure::shared_pointer const & pvRequest); + + ~RPCClient() {destroy();} /** * Performs complete blocking RPC call, opening a channel and connecting to the @@ -136,15 +137,21 @@ public: */ epics::pvData::PVStructure::shared_pointer waitResponse(double timeout = RPCCLIENT_DEFAULT_TIMEOUT); - virtual ~RPCClient() {} +private: + void construct(const ChannelProvider::shared_pointer& provider, + const std::string & serviceName, + epics::pvData::PVStructure::shared_pointer const & pvRequest); -protected: - RPCClient(const std::string & serviceName, - epics::pvData::PVStructure::shared_pointer const & pvRequest); - - std::string m_serviceName; + const std::string m_serviceName; Channel::shared_pointer m_channel; - epics::pvData::PVStructure::shared_pointer m_pvRequest; + ChannelRPC::shared_pointer m_rpc; + const epics::pvData::PVStructure::shared_pointer m_pvRequest; + + struct RPCRequester; + std::tr1::shared_ptr m_rpc_requester; + + RPCClient(const RPCClient&); + RPCClient& operator=(const RPCClient&); }; } diff --git a/src/rpcClient/rpcClient.cpp b/src/rpcClient/rpcClient.cpp index 55d5749..38917ca 100644 --- a/src/rpcClient/rpcClient.cpp +++ b/src/rpcClient/rpcClient.cpp @@ -7,8 +7,10 @@ #include #include +#include #include #include +#include #define epicsExportSharedSymbols #include @@ -18,10 +20,39 @@ #include "pv/rpcClient.h" +#if 0 +# define TRACE(msg) std::cerr<<"TRACE: "<getChannelName() << "] channel create: " << status << std::endl; - } - } - else - { - std::cerr << "[" << channel->getChannelName() << "] failed to create a channel: " << status << std::endl; - - { - Lock lock(m_mutex); - m_status = status; - } - m_connectionEvent.signal(); - } - } - - void channelStateChange( - Channel::shared_pointer const & channel, - Channel::ConnectionState connectionState) - { - if (connectionState == Channel::CONNECTED) - { - bool rpcAlreadyConnectedOnce = false; - { - Lock lock(m_mutex); - rpcAlreadyConnectedOnce = (m_channelRPC.get() != 0); - } - - if (!rpcAlreadyConnectedOnce) - { - channel->createChannelRPC(shared_from_this(), m_pvRequest); - } - } - /* - else if (connectionState != Channel::DESTROYED) - { - std::cerr << "[" << channel->getChannelName() << "] channel state change: " << Channel::ConnectionStateNames[connectionState] << std::endl; - } - */ - } + virtual std::string getRequesterName() { return "RPCClient::RPCRequester"; } virtual void channelRPCConnect( - const epics::pvData::Status & status, - ChannelRPC::shared_pointer const & channelRPC) + const pvd::Status& status, + ChannelRPC::shared_pointer const & operation) { - if (status.isSuccess()) + bool lastreq, inprog; + pvd::PVStructure::shared_pointer args; { - if (!status.isOK()) - std::cerr << "[" << channelRPC->getChannel()->getChannelName() << "] channel RPC create: " << status << std::endl; + pvd::Lock L(mutex); + TRACE("status="<getChannel()->getChannelName() << "] failed to create channel RPC: " << status << std::endl; + if(inprog && args) { + TRACE("request deferred: "<lastRequest(); + operation->request(args); } - - { - Lock lock(m_mutex); - m_status = status; - m_channelRPC = channelRPC; - } - - m_connectionEvent.signal(); + event.signal(); } virtual void requestDone( - const epics::pvData::Status & status, - ChannelRPC::shared_pointer const & channelRPC, - epics::pvData::PVStructure::shared_pointer const & pvResponse) + const pvd::Status& status, + ChannelRPC::shared_pointer const & operation, + pvd::PVStructure::shared_pointer const & pvResponse) { - if (status.isSuccess()) + TRACE("status="<getChannel()->getChannelName() << "] channel RPC: " << status << std::endl; + pvd::Lock L(mutex); + if(!inprogress) { + std::cerr<<"pva provider give RPC requestDone() when no request in progress\n"; + } else { + resp_status = status; + last_data = pvResponse; + if(resp_status.isSuccess() && !last_data) { + resp_status = pvd::Status::error("No reply data"); + } + inprogress = false; + } } - else + event.signal(); + } + + virtual void channelDisconnect(bool destroy) + { + TRACE("destroy="<getChannel()->getChannelName() << "] failed to RPC: " << status << std::endl; + pvd::Lock L(mutex); + resp_status = conn_status = pvd::Status::error("Connection lost"); + last_data.reset(); + next_args.reset(); + inprogress = false; } - - { - Lock lock(m_mutex); - m_status = status; - m_response = pvResponse; - } - - m_event.signal(); - } - - bool waitForResponse(double timeOut) - { - return m_event.wait(timeOut); - } - - bool waitUntilRPCConnected(double timeOut) - { - if (isRPCConnected()) - return true; - - return m_connectionEvent.wait(timeOut); - } - - bool isRPCConnected() - { - Lock lock(m_mutex); - return (m_channelRPC.get() != 0); - } - - PVStructure::shared_pointer & getResponse() - { - Lock lock(m_mutex); - return m_response; - } - - Status & getStatus() - { - Lock lock(m_mutex); - return m_status; - } - - void request(PVStructure::shared_pointer const & pvArgument, bool lastRequest) - { - ChannelRPC::shared_pointer rpc; - { - Lock lock(m_mutex); - rpc = m_channelRPC; - } - - if (!rpc) - throw std::runtime_error("channel RPC not connected"); - - if (lastRequest) - rpc->lastRequest(); - - rpc->request(pvArgument); + event.signal(); } }; @@ -213,18 +149,47 @@ public: - - - - - - RPCClient::RPCClient(const std::string & serviceName, - PVStructure::shared_pointer const & pvRequest) - : m_serviceName(serviceName), m_pvRequest(pvRequest) + pvd::PVStructure::shared_pointer const & pvRequest) + : m_serviceName(serviceName), m_pvRequest(pvRequest ? pvRequest : pvd::createRequest("")) { + ClientFactory::start(); + ChannelProvider::shared_pointer provider(getChannelProviderRegistry()->getProvider("pva")); + if(!provider) + throw std::logic_error("Unknown Provider"); + construct(provider, serviceName, pvRequest); } +RPCClient::RPCClient(const ChannelProvider::shared_pointer& provider, + const std::string & serviceName, + epics::pvData::PVStructure::shared_pointer const & pvRequest) +{ + construct(provider, serviceName, pvRequest); +} + +void RPCClient::construct(const ChannelProvider::shared_pointer& provider, + const std::string & serviceName, + epics::pvData::PVStructure::shared_pointer const & pvRequest) +{ + assert(provider); + + DummyChannelRequester::shared_pointer dummy(new DummyChannelRequester); + m_channel = provider->createChannel(serviceName, dummy); + { + pvd::Lock L(dummy->mutex); + if(!dummy->status.isSuccess()) + throw std::runtime_error(dummy->status.getMessage()); + } + if(!m_channel) + throw std::logic_error("provider createChannel() succeeds w/ NULL Channel"); + + m_rpc_requester.reset(new RPCRequester); + m_rpc = m_channel->createChannelRPC(m_rpc_requester, m_pvRequest); + if(!m_rpc) + throw std::logic_error("channel createChannelRPC() NULL"); +} + + void RPCClient::destroy() { if (m_channel) @@ -232,43 +197,43 @@ void RPCClient::destroy() m_channel->destroy(); m_channel.reset(); } + if (m_rpc) + { + m_rpc->destroy(); + m_rpc.reset(); + } } bool RPCClient::connect(double timeout) { - if (m_channel && - TR1::dynamic_pointer_cast(m_channel->getChannelRequester())->isRPCConnected()) - return true; - issueConnect(); return waitConnect(timeout); } void RPCClient::issueConnect() { - ChannelProvider::shared_pointer provider = getChannelProviderRegistry()->getProvider("pva"); - - // TODO try to reuse ChannelRequesterImpl instance (i.e. create only once) - TR1::shared_ptr channelRequesterImpl(new ChannelAndRPCRequesterImpl(m_pvRequest)); - m_channel = provider->createChannel(m_serviceName, channelRequesterImpl); } bool RPCClient::waitConnect(double timeout) { - if (!m_channel) - throw std::runtime_error("issueConnect() must be called before waitConnect()"); - - TR1::shared_ptr channelRequesterImpl = - TR1::dynamic_pointer_cast(m_channel->getChannelRequester()); - - return channelRequesterImpl->waitUntilRPCConnected(timeout) && - channelRequesterImpl->isRPCConnected(); + pvd::Lock L(m_rpc_requester->mutex); + TRACE("timeout="<conn_status.isSuccess()) { + L.unlock(); + if(!m_rpc_requester->event.wait(timeout)) { + TRACE("TIMEOUT"); + return false; + } + L.lock(); + } + TRACE("Connected"); + return true; } -PVStructure::shared_pointer RPCClient::request( - PVStructure::shared_pointer const & pvArgument, +pvd::PVStructure::shared_pointer RPCClient::request( + pvd::PVStructure::shared_pointer const & pvArgument, double timeout, bool lastRequest) { @@ -278,65 +243,88 @@ PVStructure::shared_pointer RPCClient::request( return waitResponse(timeout); // TODO reduce timeout for a time spent on connect } else - throw epics::pvAccess::RPCRequestException(Status::STATUSTYPE_ERROR, "connection timeout"); + throw epics::pvAccess::RPCRequestException(pvd::Status::STATUSTYPE_ERROR, "connection timeout"); } void RPCClient::issueRequest( - PVStructure::shared_pointer const & pvArgument, + pvd::PVStructure::shared_pointer const & pvArgument, bool lastRequest) { - if (!m_channel) - throw std::runtime_error("channel not connected"); - - TR1::shared_ptr channelRequesterImpl = - TR1::dynamic_pointer_cast(m_channel->getChannelRequester()); - - channelRequesterImpl->request(pvArgument, lastRequest); -} - -PVStructure::shared_pointer RPCClient::waitResponse(double timeout) -{ - TR1::shared_ptr channelRequesterImpl = - TR1::dynamic_pointer_cast(m_channel->getChannelRequester()); - - if (channelRequesterImpl->waitForResponse(timeout)) { - Status & status = channelRequesterImpl->getStatus(); - if (status.isSuccess()) - { - // release response structure - PVStructure::shared_pointer & response = channelRequesterImpl->getResponse(); - PVStructure::shared_pointer retVal = response; - response.reset(); - return retVal; + pvd::Lock L(m_rpc_requester->mutex); + TRACE("conn_status="<conn_status + <<" resp_status="<resp_status + <<" args:\n"<inprogress) + throw std::logic_error("Request already in progress"); + m_rpc_requester->inprogress = true; + m_rpc_requester->resp_status = pvd::Status::error("No Data"); + if(!m_rpc_requester->conn_status.isSuccess()) { + TRACE("defer"); + m_rpc_requester->last = lastRequest; + m_rpc_requester->next_args = pvArgument; + return; } - else - throw epics::pvAccess::RPCRequestException(status.getType(), status.getMessage()); + TRACE("request args: "<lastRequest(); + m_rpc->request(pvArgument); } -RPCClient::shared_pointer RPCClient::create(const std::string & serviceName) +pvd::PVStructure::shared_pointer RPCClient::waitResponse(double timeout) { - PVStructure::shared_pointer pvRequest = - CreateRequest::create()->createRequest(""); - return create(serviceName, pvRequest); + pvd::Lock L(m_rpc_requester->mutex); + TRACE("timeout="<inprogress) + throw std::logic_error("No request in progress"); + + while(m_rpc_requester->inprogress) + { + L.unlock(); + if(!m_rpc_requester->event.wait(timeout)) { + TRACE("TIMEOUT"); + throw RPCRequestException(pvd::Status::STATUSTYPE_ERROR, "RPC timeout"); + } + L.lock(); + } + TRACE("Complete: conn_status="<conn_status + <<" resp_status="<resp_status + <<" data:\n"<last_data); + + if(!m_rpc_requester->conn_status.isSuccess()) + throw RPCRequestException(pvd::Status::STATUSTYPE_ERROR, m_rpc_requester->conn_status.getMessage()); + + if(!m_rpc_requester->resp_status.isSuccess()) + throw RPCRequestException(pvd::Status::STATUSTYPE_ERROR, m_rpc_requester->resp_status.getMessage()); + + // consume last_data so that we can't possibly return it twice + pvd::PVStructure::shared_pointer data; + data.swap(m_rpc_requester->last_data); + + if(!data) + throw std::logic_error("No reply data?!?"); + + // copy it so that the caller need not worry about whether it will overwritten + // when the next request is issued + pvd::PVStructure::shared_pointer ret(pvd::getPVDataCreate()->createPVStructure(data->getStructure())); + ret->copyUnchecked(*data); + + return ret; } RPCClient::shared_pointer RPCClient::create(const std::string & serviceName, - PVStructure::shared_pointer const & pvRequest) + pvd::PVStructure::shared_pointer const & pvRequest) { - ClientFactory::start(); return RPCClient::shared_pointer(new RPCClient(serviceName, pvRequest)); } -PVStructure::shared_pointer RPCClient::sendRequest(const std::string & serviceName, - PVStructure::shared_pointer const & queryRequest, +pvd::PVStructure::shared_pointer RPCClient::sendRequest(const std::string & serviceName, + pvd::PVStructure::shared_pointer const & queryRequest, double timeOut) { - RPCClient::shared_pointer client = RPCClient::create(serviceName); - return client->request(queryRequest, timeOut); + RPCClient client(serviceName, queryRequest); + return client.request(queryRequest, timeOut); } diff --git a/testApp/remote/rpcClientExample.cpp b/testApp/remote/rpcClientExample.cpp index 21e1b74..2d6c2f4 100644 --- a/testApp/remote/rpcClientExample.cpp +++ b/testApp/remote/rpcClientExample.cpp @@ -24,48 +24,43 @@ int main() request->getSubField("a")->put("3.14"); request->getSubField("b")->put("2.71"); - // simplest way + std::cout<<"simplest way\n"; try { PVStructure::shared_pointer result = RPCClient::sendRequest("sum", request, TIMEOUT); - std::cout << *result << std::endl; - } catch (RPCRequestException &e) - { - std::cout << e.what() << std::endl; - return 1; - } - - - // simple sync way, allows multiple RPC calls on the clinet instance - try - { - RPCClient::shared_pointer client = RPCClient::create("sum"); - PVStructure::shared_pointer result = client->request(request, TIMEOUT); - std::cout << *result << std::endl; - } catch (RPCRequestException &e) - { - std::cout << e.what() << std::endl; - return 1; - } - - // async way, allows multiple RPC calls on the clinet instance - try - { - RPCClient::shared_pointer client = RPCClient::create("sum"); - client->issueConnect(); - if (client->waitConnect(TIMEOUT)) - { - client->issueRequest(request); - PVStructure::shared_pointer result = client->waitResponse(TIMEOUT); - std::cout << *result << std::endl; - } - else - throw std::runtime_error("connection timeout"); + std::cout << "Error: " << *result << std::endl; } catch (std::exception &e) { std::cout << e.what() << std::endl; return 1; } + + std::cout<<"simple sync way, allows multiple RPC calls on the client instance\n"; + try + { + RPCClient::shared_pointer client = RPCClient::create("sum"); + PVStructure::shared_pointer result = client->request(request, TIMEOUT); + std::cout << *result << std::endl; + } catch (std::exception &e) + { + std::cout << "Error: " << e.what() << std::endl; + return 1; + } + + std::cout<<"async way, allows multiple RPC calls on the client instance\n"; + try + { + RPCClient::shared_pointer client = RPCClient::create("sum"); + client->issueRequest(request); + // go get some coffee + PVStructure::shared_pointer result = client->waitResponse(TIMEOUT); + std::cout << *result << std::endl; + } catch (std::exception &e) + { + std::cout << "Error:" << e.what() << std::endl; + return 1; + } + return 0; } From 3a190cb5721aee2a097ac1f7f10e489956559231 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 8 Jun 2017 20:37:20 +0200 Subject: [PATCH 050/189] deprecate RPCClient::sendRequest() Changes to provider factory registery make this very inefficient (build a new client context of each request) --- src/rpcClient/pv/rpcClient.h | 2 +- testApp/remote/rpcClientExample.cpp | 12 ------------ 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/src/rpcClient/pv/rpcClient.h b/src/rpcClient/pv/rpcClient.h index 3dcde89..36ac806 100644 --- a/src/rpcClient/pv/rpcClient.h +++ b/src/rpcClient/pv/rpcClient.h @@ -70,7 +70,7 @@ public: * @throws RPCRequestException exception thrown on error on timeout. */ static epics::pvData::PVStructure::shared_pointer sendRequest(const std::string & serviceName, - epics::pvData::PVStructure::shared_pointer const &request, double timeOut = RPCCLIENT_DEFAULT_TIMEOUT); + epics::pvData::PVStructure::shared_pointer const &request, double timeOut = RPCCLIENT_DEFAULT_TIMEOUT) EPICS_DEPRECATED; diff --git a/testApp/remote/rpcClientExample.cpp b/testApp/remote/rpcClientExample.cpp index 2d6c2f4..7d38b21 100644 --- a/testApp/remote/rpcClientExample.cpp +++ b/testApp/remote/rpcClientExample.cpp @@ -24,18 +24,6 @@ int main() request->getSubField("a")->put("3.14"); request->getSubField("b")->put("2.71"); - std::cout<<"simplest way\n"; - try - { - PVStructure::shared_pointer result = RPCClient::sendRequest("sum", request, TIMEOUT); - std::cout << "Error: " << *result << std::endl; - } catch (std::exception &e) - { - std::cout << e.what() << std::endl; - return 1; - } - - std::cout<<"simple sync way, allows multiple RPC calls on the client instance\n"; try { From a453dd75feee2f8809b9a3c63c4d206ba572386f Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 16 Jun 2017 17:47:41 +0200 Subject: [PATCH 051/189] docs --- .gitignore | 2 - documentation/.gitignore | 5 + documentation/Doxyfile | 2408 ++++++++++++++++++++++++++++ documentation/client_ownership.dot | 51 + documentation/mainpage.h | 17 + documentation/ownership.dot | 8 + documentation/providers.h | 224 +++ src/client/pv/monitor.h | 3 + src/client/pv/pvAccess.h | 33 +- 9 files changed, 2739 insertions(+), 12 deletions(-) create mode 100644 documentation/.gitignore create mode 100644 documentation/Doxyfile create mode 100644 documentation/client_ownership.dot create mode 100644 documentation/mainpage.h create mode 100644 documentation/ownership.dot create mode 100644 documentation/providers.h diff --git a/.gitignore b/.gitignore index f46cdcc..5430c36 100644 --- a/.gitignore +++ b/.gitignore @@ -5,8 +5,6 @@ include/ db/ dbd/ html/ -documentation/html -documentation/*.tag envPaths configure/*.local !configure/ExampleRELEASE.local diff --git a/documentation/.gitignore b/documentation/.gitignore new file mode 100644 index 0000000..b39b9d7 --- /dev/null +++ b/documentation/.gitignore @@ -0,0 +1,5 @@ +*.tag +*.db +*.tmp +html/ +latex/ diff --git a/documentation/Doxyfile b/documentation/Doxyfile new file mode 100644 index 0000000..7cdb4b7 --- /dev/null +++ b/documentation/Doxyfile @@ -0,0 +1,2408 @@ +# Doxyfile 1.8.8 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = pvAccessCPP + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is included in +# the documentation. The maximum height of the logo should not exceed 55 pixels +# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo +# to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = . + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = YES + +# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = ../src \ + ../pvtoolsSrc \ + ./ + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = ../src + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a +# new page for each member. If set to NO, the documentation of a member will be +# part of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. When set to YES local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO these classes will be included in the various overviews. This option has +# no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the +# todo list. This list is created by putting \todo commands in the +# documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the +# test list. This list is created by putting \test commands in the +# documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES the list +# will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = NO + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO doxygen will only warn about wrong or incomplete parameter +# documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. +# Note: If this tag is empty the current directory is searched. + +INPUT = ../src/client/pv \ + ../src/utils/pv \ + ../src/pva/pv \ + . + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank the +# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, +# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, +# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, +# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, +# *.qsf, *.as and *.js. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.for \ + *.tcl \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.as \ + *.js + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER ) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the +# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the +# cost of reduced performance. This can be particularly helpful with template +# rich C++ code for which doxygen's built-in parser lacks the necessary type +# information. +# Note: The availability of this option depends on whether or not doxygen was +# compiled with the --with-libclang option. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = YES + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefor more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra stylesheet files is of importance (e.g. the last +# stylesheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the stylesheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler ( hhc.exe). If non-empty +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated ( +# YES) or that it should be included in the master .chm file ( NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated ( +# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /