pvac user internal/external refs.

This commit is contained in:
Michael Davidsaver
2017-11-22 14:14:05 -06:00
parent 250826ffb9
commit 6055dbb983
5 changed files with 99 additions and 19 deletions
+15 -4
View File
@@ -27,7 +27,8 @@ Timeout::Timeout()
:std::runtime_error("Timeout")
{}
struct ClientChannel::Impl : public pva::ChannelRequester
struct ClientChannel::Impl : public pva::ChannelRequester,
public pvac::detail::wrapped_shared_from_this<ClientChannel::Impl>
{
epicsMutex mutex;
pva::Channel::shared_pointer channel;
@@ -40,6 +41,15 @@ struct ClientChannel::Impl : public pva::ChannelRequester
Impl() {REFTRACE_INCREMENT(num_instances);}
virtual ~Impl() {REFTRACE_DECREMENT(num_instances);}
// called automatically via wrapped_shared_from_this
void cancel()
{
// ClientChannel destroy implicitly removes all callbacks,
// but doesn't destroy the Channel or cancel Operations
Guard G(mutex);
listeners.clear();
}
virtual std::string getRequesterName() OVERRIDE FINAL { return "ClientChannel::Impl"; }
virtual void channelCreated(const pvd::Status& status, pva::Channel::shared_pointer const & channel) OVERRIDE FINAL {}
@@ -49,7 +59,7 @@ struct ClientChannel::Impl : public pva::ChannelRequester
listeners_t notify;
{
Guard G(mutex);
notify = listeners;
notify = listeners; // copy vector
}
ConnectEvent evt;
evt.connected = connectionState==pva::Channel::CONNECTED;
@@ -103,13 +113,14 @@ void Operation::cancel()
ClientChannel::ClientChannel(const std::tr1::shared_ptr<pva::ChannelProvider>& provider,
const std::string& name,
const Options& opt)
:impl(new Impl)
:impl(Impl::build())
{
if(name.empty())
THROW_EXCEPTION2(std::logic_error, "empty channel name not allowed");
if(!provider)
THROW_EXCEPTION2(std::logic_error, "NULL ChannelProvider");
impl->channel = provider->createChannel(name, impl, opt.priority, opt.address);
impl->channel = provider->createChannel(name, impl->internal_shared_from_this(),
opt.priority, opt.address);
if(!impl->channel)
throw std::runtime_error("ChannelProvider failed to create Channel");
}
+10 -6
View File
@@ -25,7 +25,8 @@ typedef epicsGuardRelease<epicsMutex> UnGuard;
namespace {
struct GetPutter : public pva::ChannelPutRequester,
public pvac::Operation::Impl
public pvac::Operation::Impl,
public pvac::detail::wrapped_shared_from_this<GetPutter>
{
mutable epicsMutex mutex;
@@ -42,7 +43,7 @@ struct GetPutter : public pva::ChannelPutRequester,
{REFTRACE_INCREMENT(num_instances);}
GetPutter(pvac::ClientChannel::PutCallback* cb) :started(false), getcb(0), putcb(cb)
{REFTRACE_INCREMENT(num_instances);}
virtual ~GetPutter() {cancel();REFTRACE_DECREMENT(num_instances);}
virtual ~GetPutter() {REFTRACE_DECREMENT(num_instances);}
void callEvent(Guard& G, pvac::GetEvent::event_t evt = pvac::GetEvent::Fail)
{
@@ -69,6 +70,7 @@ struct GetPutter : public pva::ChannelPutRequester,
return op ? op->getChannel()->getChannelName() : "<dead>";
}
// called automatically via wrapped_shared_from_this
virtual void cancel() OVERRIDE FINAL
{
Guard G(mutex);
@@ -191,11 +193,12 @@ ClientChannel::get(ClientChannel::GetCallback* cb,
if(!pvRequest)
pvRequest = pvd::createRequest("field()");
std::tr1::shared_ptr<GetPutter> ret(new GetPutter(cb));
std::tr1::shared_ptr<GetPutter> ret(GetPutter::build(cb));
{
Guard G(ret->mutex);
ret->op = getChannel()->createChannelPut(ret, std::tr1::const_pointer_cast<pvd::PVStructure>(pvRequest));
ret->op = getChannel()->createChannelPut(ret->internal_shared_from_this(),
std::tr1::const_pointer_cast<pvd::PVStructure>(pvRequest));
}
return Operation(ret);
@@ -209,11 +212,12 @@ ClientChannel::put(PutCallback* cb,
if(!pvRequest)
pvRequest = pvd::createRequest("field()");
std::tr1::shared_ptr<GetPutter> ret(new GetPutter(cb));
std::tr1::shared_ptr<GetPutter> ret(GetPutter::build(cb));
{
Guard G(ret->mutex);
ret->op = getChannel()->createChannelPut(ret, std::tr1::const_pointer_cast<pvd::PVStructure>(pvRequest));
ret->op = getChannel()->createChannelPut(ret->internal_shared_from_this(),
std::tr1::const_pointer_cast<pvd::PVStructure>(pvRequest));
}
return Operation(ret);
+7 -4
View File
@@ -23,7 +23,8 @@ typedef epicsGuardRelease<epicsMutex> UnGuard;
namespace pvac {
struct Monitor::Impl : public pva::MonitorRequester
struct Monitor::Impl : public pva::MonitorRequester,
public pvac::detail::wrapped_shared_from_this<Monitor::Impl>
{
mutable epicsMutex mutex;
pva::Channel::shared_pointer chan;
@@ -43,7 +44,7 @@ struct Monitor::Impl : public pva::MonitorRequester
,seenEmpty(false)
,cb(cb)
{REFTRACE_INCREMENT(num_instances);}
virtual ~Impl() {cancel();REFTRACE_DECREMENT(num_instances);}
virtual ~Impl() {REFTRACE_DECREMENT(num_instances);}
void callEvent(Guard& G, MonitorEvent::event_t evt = MonitorEvent::Fail)
{
@@ -78,6 +79,7 @@ struct Monitor::Impl : public pva::MonitorRequester
}
}
// called automatically via wrapped_shared_from_this
void cancel()
{
operation_type::shared_pointer temp;
@@ -218,12 +220,13 @@ ClientChannel::monitor(MonitorCallback *cb,
if(!pvRequest)
pvRequest = pvd::createRequest("field()");
std::tr1::shared_ptr<Monitor::Impl> ret(new Monitor::Impl(cb));
std::tr1::shared_ptr<Monitor::Impl> ret(Monitor::Impl::build(cb));
ret->chan = getChannel();
{
Guard G(ret->mutex);
ret->op = ret->chan->createMonitor(ret, std::tr1::const_pointer_cast<pvd::PVStructure>(pvRequest));
ret->op = ret->chan->createMonitor(ret->internal_shared_from_this(),
std::tr1::const_pointer_cast<pvd::PVStructure>(pvRequest));
}
return Monitor(ret);
+8 -5
View File
@@ -12,7 +12,7 @@
#define epicsExportSharedSymbols
#include "pv/logger.h"
#include "pva/client.h"
#include "clientpvt.h"
#include "pv/pvAccess.h"
namespace pvd = epics::pvData;
@@ -23,7 +23,8 @@ typedef epicsGuardRelease<epicsMutex> UnGuard;
namespace {
struct RPCer : public pva::ChannelRPCRequester,
public pvac::Operation::Impl
public pvac::Operation::Impl,
public pvac::detail::wrapped_shared_from_this<RPCer>
{
mutable epicsMutex mutex;
@@ -40,7 +41,7 @@ struct RPCer : public pva::ChannelRPCRequester,
RPCer(pvac::ClientChannel::GetCallback* cb,
const pvd::PVStructure::const_shared_pointer& args) :started(false), cb(cb), args(args)
{REFTRACE_INCREMENT(num_instances);}
virtual ~RPCer() {cancel();REFTRACE_DECREMENT(num_instances);}
virtual ~RPCer() {REFTRACE_DECREMENT(num_instances);}
void callEvent(Guard& G, pvac::GetEvent::event_t evt = pvac::GetEvent::Fail)
{
@@ -79,6 +80,7 @@ struct RPCer : public pva::ChannelRPCRequester,
return op ? op->getChannel()->getChannelName() : "<dead>";
}
// called automatically via wrapped_shared_from_this
virtual void cancel()
{
Guard G(mutex);
@@ -155,11 +157,12 @@ ClientChannel::rpc(GetCallback* cb,
if(!pvRequest)
pvRequest = pvd::createRequest("field()");
std::tr1::shared_ptr<RPCer> ret(new RPCer(cb, arguments));
std::tr1::shared_ptr<RPCer> ret(RPCer::build(cb, arguments));
{
Guard G(ret->mutex);
ret->op = getChannel()->createChannelRPC(ret, std::tr1::const_pointer_cast<pvd::PVStructure>(pvRequest));
ret->op = getChannel()->createChannelRPC(ret->internal_shared_from_this(),
std::tr1::const_pointer_cast<pvd::PVStructure>(pvRequest));
}
return Operation(ret);
+59
View File
@@ -1,9 +1,68 @@
#ifndef CLIENTPVT_H
#define CLIENTPVT_H
#include <pv/sharedPtr.h>
#include <pva/client.h>
namespace pvac{namespace detail{
/* Like std::tr1::enable_shared_from_this
* with the notion of internal vs. external references.
* External references wrap an internal reference.
* When the last external reference is dropped,
* then Base::cancel() is called, but the object isn't free'd
* until all internal references are dropped as well.
*/
template<typename Base>
struct wrapped_shared_from_this {
private:
std::tr1::weak_ptr<Base> myselfptr;
struct canceller {
std::tr1::shared_ptr<Base> ptr;
canceller(const std::tr1::shared_ptr<Base>& ptr) :ptr(ptr) {}
void operator()(Base *) {
std::tr1::shared_ptr<Base> P;
P.swap(ptr);
P->cancel();
}
};
public:
std::tr1::shared_ptr<Base> internal_shared_from_this() {
std::tr1::shared_ptr<Base> ret(myselfptr);
if(!ret)
throw std::tr1::bad_weak_ptr();
return ret;
}
static
std::tr1::shared_ptr<Base> build() {
std::tr1::shared_ptr<Base> inner(new Base),
ret(inner.get(), canceller(inner));
inner->myselfptr = inner;
return ret;
}
template<typename A>
static
std::tr1::shared_ptr<Base> build(A a) {
std::tr1::shared_ptr<Base> inner(new Base(a)),
ret(inner.get(), canceller(inner));
inner->myselfptr = inner;
return ret;
}
template<typename A, typename B>
static
std::tr1::shared_ptr<Base> build(A a, B b) {
std::tr1::shared_ptr<Base> inner(new Base(a, b)),
ret(inner.get(), canceller(inner));
inner->myselfptr = inner;
return ret;
}
};
void registerRefTrack();
void registerRefTrackGet();