From 33fb103a4b71f257e41e0a8c2e6dcc59f0a56b65 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 5 Sep 2017 15:45:36 -0500 Subject: [PATCH] defaults ChanneGet/Process use ChannelPut provide default implementations of Channel::createChannelGet() and Channel::createChannelProcess() which proxy to Channel::createChannelPut(). Get uses ChannelPut::get(). Process uses ChannelPut::put() with an empty bit set (no data) --- src/client/pv/pvAccess.h | 14 +++ src/client/pvAccess.cpp | 216 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 225 insertions(+), 5 deletions(-) diff --git a/src/client/pv/pvAccess.h b/src/client/pv/pvAccess.h index 61d6022..28a5c14 100644 --- a/src/client/pv/pvAccess.h +++ b/src/client/pv/pvAccess.h @@ -925,6 +925,8 @@ public: * @post Returned shared_ptr will have unique()==true. * * @return A non-NULL ChannelProcess unless channelProcessConnect() called with an Error + * + * @note The default implementation proxies using createChannelPut() and ChannelPut::put() with no data (empty bit set) */ virtual ChannelProcess::shared_pointer createChannelProcess( ChannelProcessRequester::shared_pointer const & requester, @@ -944,6 +946,8 @@ public: * @post Returned shared_ptr will have unique()==true. * * @return A non-NULL ChannelGet unless channelGetConnect() called with an Error + * + * @note The default implementation proxies to createChannelPut() */ virtual ChannelGet::shared_pointer createChannelGet( ChannelGetRequester::shared_pointer const & requester, @@ -963,6 +967,8 @@ public: * @post Returned shared_ptr will have unique()==true. * * @return A non-NULL ChannelPut unless channelPutConnect() called with an Error + * + * @note The default implementation yields a not implemented error */ virtual ChannelPut::shared_pointer createChannelPut( ChannelPutRequester::shared_pointer const & requester, @@ -982,6 +988,8 @@ public: * @post Returned shared_ptr will have unique()==true. * * @return A non-NULL ChannelPutGet unless channelPutGetConnect() called with an Error + * + * @note The default implementation yields a not implemented error */ virtual ChannelPutGet::shared_pointer createChannelPutGet( ChannelPutGetRequester::shared_pointer const & requester, @@ -1001,6 +1009,8 @@ public: * @post Returned shared_ptr will have unique()==true. * * @return A non-NULL ChannelRPC unless channelRPCConnect() called with an Error + * + * @note The default implementation yields a not implemented error */ virtual ChannelRPC::shared_pointer createChannelRPC( ChannelRPCRequester::shared_pointer const & requester, @@ -1020,6 +1030,8 @@ public: * @post Returned shared_ptr will have unique()==true. * * @return A non-NULL Monitor unless monitorConnect() called with an Error + * + * @note The default implementation yields a not implemented error */ virtual Monitor::shared_pointer createMonitor( MonitorRequester::shared_pointer const & requester, @@ -1044,6 +1056,8 @@ public: * @param channelArrayRequester The ChannelArrayRequester * @param pvRequest Additional options (e.g. triggering). * @return ChannelArray instance. + * + * @note The default implementation yields a not implemented error */ virtual ChannelArray::shared_pointer createChannelArray( ChannelArrayRequester::shared_pointer const & requester, diff --git a/src/client/pvAccess.cpp b/src/client/pvAccess.cpp index 165563f..a943f85 100644 --- a/src/client/pvAccess.cpp +++ b/src/client/pvAccess.cpp @@ -4,6 +4,8 @@ * in file LICENSE that is included with this distribution. */ +#include +#include #include #define epicsExportSharedSymbols @@ -54,22 +56,226 @@ AccessRights Channel::getAccessRights(epics::pvData::PVField::shared_pointer con return readWrite; } +namespace { +/* allow createChannelProcess() to use a ChannelPut w/o data */ +struct Process2PutProxy : public ChannelProcess +{ + struct Req : public ChannelPutRequester + { + const ChannelProcessRequester::weak_pointer requester; // was passed to createChannelProcess() + const std::tr1::weak_ptr operation; // enclosing Process2PutProxy + + epicsMutex mutex; + epics::pvData::PVStructurePtr dummy; + + Req(const ChannelProcessRequester::weak_pointer& req, + const std::tr1::weak_ptr& op) + :requester(req), operation(op) + {} + virtual ~Req() {} + + virtual std::string getRequesterName() OVERRIDE FINAL { + ChannelProcessRequester::shared_pointer req(requester.lock()); + return req ? req->getRequesterName() : ""; + } + + virtual void channelDisconnect(bool destroy) OVERRIDE FINAL { + epics::pvData::PVStructurePtr dummy; + { + epicsGuard G(mutex); + this->dummy.swap(dummy); + } + ChannelProcessRequester::shared_pointer req(requester.lock()); + if(req) + req->channelDisconnect(destroy); + } + + virtual void channelPutConnect( + const epics::pvData::Status& status, + ChannelPut::shared_pointer const & channelPut, + epics::pvData::Structure::const_shared_pointer const & structure) OVERRIDE FINAL + { + epics::pvData::PVStructurePtr dummy(epics::pvData::getPVDataCreate()->createPVStructure(structure)); + ChannelProcessRequester::shared_pointer req(requester.lock()); + std::tr1::shared_ptr op(operation.lock()); + if(!op) return; + { + epicsGuard G(mutex); + this->dummy = dummy; + op->op = channelPut; + } + if(req) + req->channelProcessConnect(status, op); + } + + virtual void putDone( + const epics::pvData::Status& status, + ChannelPut::shared_pointer const & channelPut) OVERRIDE FINAL + { + ChannelProcessRequester::shared_pointer req(requester.lock()); + std::tr1::shared_ptr op(operation.lock()); + if(req && op) + req->processDone(status, op); + } + + virtual 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) OVERRIDE FINAL + { /* never called */ } + }; + + ChannelPut::shared_pointer op; // the op we wrap + std::tr1::shared_ptr op_request; // keep our Req alive + + epics::pvData::BitSetPtr empty; + + Process2PutProxy() :empty(new epics::pvData::BitSet) {} + virtual ~Process2PutProxy() {} + + virtual void destroy() OVERRIDE FINAL + { op->destroy(); } + virtual std::tr1::shared_ptr getChannel() OVERRIDE FINAL + { return op->getChannel(); } + virtual void cancel() OVERRIDE FINAL + { op->cancel(); } + virtual void lastRequest() OVERRIDE FINAL + { op->lastRequest(); } + virtual void process() OVERRIDE FINAL + { + epics::pvData::PVStructurePtr blob; + { + epicsGuard G(op_request->mutex); + blob = op_request->dummy; + } + if(!blob) { + ChannelProcessRequester::shared_pointer req(op_request->requester.lock()); + ChannelProcess::shared_pointer op(op_request->operation.lock()); + req->processDone(epics::pvData::Status::error("Not connected"), op); + } else { + empty->clear(); + op->put(blob, empty); + } + } +}; +}//namespace + ChannelProcess::shared_pointer Channel::createChannelProcess( ChannelProcessRequester::shared_pointer const & requester, epics::pvData::PVStructure::shared_pointer const & pvRequest) { - ChannelProcess::shared_pointer ret; - requester->channelProcessConnect(pvd::Status(pvd::Status::STATUSTYPE_FATAL, "Not Implemented"), ret); + std::tr1::shared_ptr ret(new Process2PutProxy); + ret->op_request.reset(new Process2PutProxy::Req(requester, ret)); + + ChannelPut::shared_pointer op(createChannelPut(ret->op_request, pvRequest)); + if(!op) { + ret.reset(); + } else { + epicsGuard G(ret->op_request->mutex); + ret->op = op; + } + return ret; } +namespace { +/** Allow createChannelGet() to use createChannelPut() + */ +struct Get2PutProxy : public ChannelGet +{ + struct Req : public ChannelPutRequester + { + const ChannelGetRequester::weak_pointer requester; // was passed to createChannelGet() + const std::tr1::weak_ptr operation; // enclosing Get2PutProxy + + epicsMutex mutex; + + Req(const ChannelGetRequester::weak_pointer& req, + const std::tr1::weak_ptr& op) + :requester(req), operation(op) + {} + virtual ~Req() {} + + virtual std::string getRequesterName() OVERRIDE FINAL { + ChannelGetRequester::shared_pointer req(requester.lock()); + return req ? req->getRequesterName() : ""; + } + + virtual void channelDisconnect(bool destroy) OVERRIDE FINAL { + ChannelGetRequester::shared_pointer req(requester.lock()); + if(req) + req->channelDisconnect(destroy); + } + + virtual void channelPutConnect( + const epics::pvData::Status& status, + ChannelPut::shared_pointer const & channelPut, + epics::pvData::Structure::const_shared_pointer const & structure) OVERRIDE FINAL + { + ChannelGetRequester::shared_pointer req(requester.lock()); + std::tr1::shared_ptr op(operation.lock()); + if(!op) return; + { + epicsGuard G(mutex); + op->op = channelPut; + } + if(req) + req->channelGetConnect(status, op, structure); + } + + virtual void putDone( + const epics::pvData::Status& status, + ChannelPut::shared_pointer const & channelPut) OVERRIDE FINAL + { /* never called */ } + + virtual 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) OVERRIDE FINAL + { + ChannelGetRequester::shared_pointer req(requester.lock()); + std::tr1::shared_ptr op(operation.lock()); + if(req && op) + req->getDone(status, op, pvStructure, bitSet); + } + }; + + ChannelPut::shared_pointer op; // the put we wrap + std::tr1::shared_ptr op_request; // keep our Req alive + + Get2PutProxy() {} + virtual ~Get2PutProxy() {} + + virtual void destroy() OVERRIDE FINAL + { op->destroy(); } + virtual std::tr1::shared_ptr getChannel() OVERRIDE FINAL + { return op->getChannel(); } + virtual void cancel() OVERRIDE FINAL + { op->cancel(); } + virtual void lastRequest() OVERRIDE FINAL + { op->lastRequest(); } + virtual void get() OVERRIDE FINAL + { op->get(); } +}; +}// namespace + ChannelGet::shared_pointer Channel::createChannelGet( ChannelGetRequester::shared_pointer const & requester, epics::pvData::PVStructure::shared_pointer const & pvRequest) { - ChannelGet::shared_pointer ret; - requester->channelGetConnect(pvd::Status(pvd::Status::STATUSTYPE_FATAL, "Not Implemented"), - ret, pvd::StructureConstPtr()); + std::tr1::shared_ptr ret(new Get2PutProxy); + ret->op_request.reset(new Get2PutProxy::Req(requester, ret)); + + ChannelPut::shared_pointer op(createChannelPut(ret->op_request, pvRequest)); + if(!op) { + ret.reset(); + } else { + epicsGuard G(ret->op_request->mutex); + ret->op = op; + } + return ret; }