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)
This commit is contained in:
Michael Davidsaver
2017-09-05 15:45:36 -05:00
parent e8adc57897
commit 33fb103a4b
2 changed files with 225 additions and 5 deletions

View File

@@ -925,6 +925,8 @@ public:
* @post Returned shared_ptr<ChannelProcess> 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<ChannelGet> 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<ChannelPut> 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<ChannelPutGet> 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<ChannelRPC> 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<Monitor> 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 <code>ChannelArray</code> instance.
*
* @note The default implementation yields a not implemented error
*/
virtual ChannelArray::shared_pointer createChannelArray(
ChannelArrayRequester::shared_pointer const & requester,

View File

@@ -4,6 +4,8 @@
* in file LICENSE that is included with this distribution.
*/
#include <epicsMutex.h>
#include <epicsGuard.h>
#include <pv/reftrack.h>
#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<Process2PutProxy> operation; // enclosing Process2PutProxy
epicsMutex mutex;
epics::pvData::PVStructurePtr dummy;
Req(const ChannelProcessRequester::weak_pointer& req,
const std::tr1::weak_ptr<Process2PutProxy>& 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<epicsMutex> 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<Process2PutProxy> op(operation.lock());
if(!op) return;
{
epicsGuard<epicsMutex> 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<Process2PutProxy> 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<Req> 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<Channel> 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<epicsMutex> 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<Process2PutProxy> 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<epicsMutex> 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<Get2PutProxy> operation; // enclosing Get2PutProxy
epicsMutex mutex;
Req(const ChannelGetRequester::weak_pointer& req,
const std::tr1::weak_ptr<Get2PutProxy>& 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<Get2PutProxy> op(operation.lock());
if(!op) return;
{
epicsGuard<epicsMutex> 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<Get2PutProxy> op(operation.lock());
if(req && op)
req->getDone(status, op, pvStructure, bitSet);
}
};
ChannelPut::shared_pointer op; // the put we wrap
std::tr1::shared_ptr<Get2PutProxy::Req> op_request; // keep our Req alive
Get2PutProxy() {}
virtual ~Get2PutProxy() {}
virtual void destroy() OVERRIDE FINAL
{ op->destroy(); }
virtual std::tr1::shared_ptr<Channel> 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<Get2PutProxy> 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<epicsMutex> G(ret->op_request->mutex);
ret->op = op;
}
return ret;
}