add pva/server.h
This commit is contained in:
@ -768,6 +768,7 @@ WARN_LOGFILE =
|
|||||||
INPUT = ../src/client/pv \
|
INPUT = ../src/client/pv \
|
||||||
../src/client/pva \
|
../src/client/pva \
|
||||||
../src/server/pv \
|
../src/server/pv \
|
||||||
|
../src/server/pva \
|
||||||
../src/rpcClient/pv \
|
../src/rpcClient/pv \
|
||||||
../src/rpcService/pv \
|
../src/rpcService/pv \
|
||||||
../src/utils/pv \
|
../src/utils/pv \
|
||||||
|
@ -55,3 +55,9 @@ This example demonstrates a client which sets up a persistent Monitor operation.
|
|||||||
@include monitorme.cpp
|
@include monitorme.cpp
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
/** @page examples_mailbox Server Mailbox Example
|
||||||
|
This example creates a server with one or more pvas::SharedPV::buildMailbox()
|
||||||
|
instances.
|
||||||
|
|
||||||
|
@include mailbox.cpp
|
||||||
|
*/
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
- @ref pvarelease_notes
|
- @ref pvarelease_notes
|
||||||
- API documentation
|
- API documentation
|
||||||
- @ref pvac page
|
- @ref pvac page
|
||||||
|
- @ref pvas page
|
||||||
- @ref providers page
|
- @ref providers page
|
||||||
- @ref pvtools
|
- @ref pvtools
|
||||||
|
|
||||||
@ -21,7 +22,7 @@
|
|||||||
- @ref examples_getme
|
- @ref examples_getme
|
||||||
- @ref examples_putme
|
- @ref examples_putme
|
||||||
- @ref examples_monitorme
|
- @ref examples_monitorme
|
||||||
|
- @ref examples_mailbox
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#endif /* MAINPAGE_H */
|
#endif /* MAINPAGE_H */
|
||||||
|
@ -29,6 +29,10 @@
|
|||||||
using namespace epics::pvData;
|
using namespace epics::pvData;
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
|
namespace pvas {
|
||||||
|
void registerRefTrackServer();
|
||||||
|
}
|
||||||
|
|
||||||
namespace epics {
|
namespace epics {
|
||||||
namespace pvAccess {
|
namespace pvAccess {
|
||||||
|
|
||||||
@ -220,6 +224,7 @@ void providerRegInit(void*)
|
|||||||
registerRefCounter("ChannelRequest (ABC)", &ChannelRequest::num_instances);
|
registerRefCounter("ChannelRequest (ABC)", &ChannelRequest::num_instances);
|
||||||
registerRefCounter("ResponseHandler (ABC)", &ResponseHandler::num_instances);
|
registerRefCounter("ResponseHandler (ABC)", &ResponseHandler::num_instances);
|
||||||
registerRefCounter("MonitorFIFO", &MonitorFIFO::num_instances);
|
registerRefCounter("MonitorFIFO", &MonitorFIFO::num_instances);
|
||||||
|
pvas::registerRefTrackServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
ChannelProviderRegistry::shared_pointer ChannelProviderRegistry::clients()
|
ChannelProviderRegistry::shared_pointer ChannelProviderRegistry::clients()
|
||||||
|
@ -4,6 +4,7 @@ SRC_DIRS += $(PVACCESS_SRC)/server
|
|||||||
|
|
||||||
INC += pv/serverContext.h
|
INC += pv/serverContext.h
|
||||||
INC += pv/beaconServerStatusProvider.h
|
INC += pv/beaconServerStatusProvider.h
|
||||||
|
INC += pva/server.h
|
||||||
|
|
||||||
pvAccess_SRCS += responseHandlers.cpp
|
pvAccess_SRCS += responseHandlers.cpp
|
||||||
pvAccess_SRCS += serverContext.cpp
|
pvAccess_SRCS += serverContext.cpp
|
||||||
@ -11,3 +12,4 @@ pvAccess_SRCS += serverChannelImpl.cpp
|
|||||||
pvAccess_SRCS += baseChannelRequester.cpp
|
pvAccess_SRCS += baseChannelRequester.cpp
|
||||||
pvAccess_SRCS += beaconEmitter.cpp
|
pvAccess_SRCS += beaconEmitter.cpp
|
||||||
pvAccess_SRCS += beaconServerStatusProvider.cpp
|
pvAccess_SRCS += beaconServerStatusProvider.cpp
|
||||||
|
pvAccess_SRCS += server.cpp
|
||||||
|
222
src/server/pva/server.h
Normal file
222
src/server/pva/server.h
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
/*
|
||||||
|
* Copyright information and license terms for this software can be
|
||||||
|
* found in the file LICENSE that is included with the distribution
|
||||||
|
*/
|
||||||
|
#ifndef PVA_SERVER_H
|
||||||
|
#define PVA_SERVER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <shareLib.h>
|
||||||
|
#include <pv/sharedPtr.h>
|
||||||
|
#include <pv/sharedVector.h>
|
||||||
|
|
||||||
|
namespace epics{namespace pvAccess{
|
||||||
|
class ChannelProvider;
|
||||||
|
class Channel;
|
||||||
|
class ChannelRequester;
|
||||||
|
}} // epics::pvAccess
|
||||||
|
|
||||||
|
//! See @ref pvas API
|
||||||
|
namespace pvas {
|
||||||
|
|
||||||
|
/** @addtogroup pvas Server API
|
||||||
|
*
|
||||||
|
* PVA Server Providers, for use with a PVA epics::pvAccess::ServerContext
|
||||||
|
*
|
||||||
|
* These are implementations of epics::pvAccess::ChannelProvider which manage "PVs",
|
||||||
|
* which are sources of epics::pvAccess::Channel instances. Typically SharedPV .
|
||||||
|
*
|
||||||
|
* Two containers are provided StaticProvider, and for some special cases DynamicProvider.
|
||||||
|
* It is recommended to use StaticProvider where possible, with DynamicProvider for exception cases.
|
||||||
|
*
|
||||||
|
* A StaticProvider maintains an internal lookup table of StaticProvider::ChannelBuilder (aka. SharedPV).
|
||||||
|
* This table is manipulated by StaticProvider::add() and StaticProvider::remove(), which can
|
||||||
|
* be called at any time.
|
||||||
|
*
|
||||||
|
* A DynamicProvider does not maintain an internal lookup table. Instead it provides
|
||||||
|
* the DynamicProvider::Handler interface, through which remote search and connection
|
||||||
|
* requests are delivered.
|
||||||
|
*
|
||||||
|
* See @ref examples_mailbox for a working example.
|
||||||
|
*
|
||||||
|
@code
|
||||||
|
namespace pva = epics::pvAccess;
|
||||||
|
pvas::SharedPV::shared_pointer pv(pvas::SharedPV::buildMailbox());
|
||||||
|
pvas::StaticProvider sprov("arbitrary");
|
||||||
|
pva::ServerContext::shared_pointer server(
|
||||||
|
pva::ServerContext::create(
|
||||||
|
pva::ServerContext::Config() .provider(sprov.provider()) ));
|
||||||
|
sprov->add("pv:name", pv);
|
||||||
|
@endcode
|
||||||
|
*
|
||||||
|
* @section pvas_sharedptr Server API shared_ptr Ownership
|
||||||
|
*
|
||||||
|
* shared_ptr<> relationships internal to server API classes.
|
||||||
|
* Solid red lines are shared_ptr<>.
|
||||||
|
* Dashed red lines are shared_ptr<> which may exist safely in user code.
|
||||||
|
* Rectangles are public API classes. Circles are internal classes.
|
||||||
|
* "ChannelProvider" is an arbitrary ChannelProvider, possibly StaticProvider or DynamicProvider.
|
||||||
|
*
|
||||||
|
@dot "Internal shared_ptr<> relationships.
|
||||||
|
digraph sspv {
|
||||||
|
SharedPV [shape="box"];
|
||||||
|
SharedPVHandler [label="SharedPV::Handler", shape="box"];
|
||||||
|
SharedChannel [shape="ellipse"];
|
||||||
|
ChannelOp [label="SharedPut/RPC/MonitorFIFO", shape="ellipse"];
|
||||||
|
|
||||||
|
DynamicProvider [shape="box"];
|
||||||
|
DynamicHandler [label="DynamicProvider::Handler", shape="box"];
|
||||||
|
StaticProvider [shape="ellipse"];
|
||||||
|
|
||||||
|
ChannelRequester [shape="ellipse"];
|
||||||
|
ChannelProvider [shape="box"];
|
||||||
|
|
||||||
|
ServerContext [shape="box"];
|
||||||
|
|
||||||
|
ChannelProvider -> SharedPV [color="red", style="dashed"];
|
||||||
|
DynamicProvider -> DynamicHandler [color="red"];
|
||||||
|
StaticProvider -> SharedPV [color="red"];
|
||||||
|
ServerContext -> ChannelProvider [color="red"];
|
||||||
|
ServerContext -> DynamicProvider [color="red"];
|
||||||
|
ServerContext -> StaticProvider [color="red"];
|
||||||
|
ServerContext -> ChannelRequester [color="red"];
|
||||||
|
ServerContext -> SharedChannel [color="red"];
|
||||||
|
ServerContext -> ChannelOp [color="red"];
|
||||||
|
SharedPV -> SharedPVHandler [color="red"];
|
||||||
|
SharedChannel -> SharedPV [color="red"];
|
||||||
|
ChannelOp -> SharedChannel [color="red"];
|
||||||
|
}
|
||||||
|
@enddot
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @brief A Provider based on a list of SharedPV instance.
|
||||||
|
*
|
||||||
|
* SharedPV instances may be added/removed at any time. So it is only "static"
|
||||||
|
* in the sense that the list of PV names is known to StaticProvider at all times.
|
||||||
|
*
|
||||||
|
* @see @ref pvas_sharedptr
|
||||||
|
*/
|
||||||
|
class epicsShareClass StaticProvider {
|
||||||
|
public:
|
||||||
|
POINTER_DEFINITIONS(StaticProvider);
|
||||||
|
struct Impl;
|
||||||
|
private:
|
||||||
|
std::tr1::shared_ptr<Impl> impl; // const after ctor
|
||||||
|
public:
|
||||||
|
|
||||||
|
//! Interface for something which can provide Channels. aka A "PV". Typically a SharedPV
|
||||||
|
struct epicsShareClass ChannelBuilder {
|
||||||
|
POINTER_DEFINITIONS(ChannelBuilder);
|
||||||
|
virtual ~ChannelBuilder();
|
||||||
|
virtual std::tr1::shared_ptr<epics::pvAccess::Channel> connect(const std::tr1::shared_ptr<epics::pvAccess::ChannelProvider>& provider,
|
||||||
|
const std::string& name,
|
||||||
|
const std::tr1::shared_ptr<epics::pvAccess::ChannelRequester>& requester) =0;
|
||||||
|
virtual void close(bool destroy=false) =0;
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
typedef std::map<std::string, std::tr1::shared_ptr<ChannelBuilder> > builders_t;
|
||||||
|
public:
|
||||||
|
|
||||||
|
//! Build a new, empty, provider.
|
||||||
|
//! @param name Provider Name. Only relevant if registerAsServer() is called, then must be unique in this process.
|
||||||
|
explicit StaticProvider(const std::string& name);
|
||||||
|
~StaticProvider();
|
||||||
|
|
||||||
|
//! Call Channelbuilder::close(destroy) for all currently added ChannelBuilders.
|
||||||
|
//! @see SharedPV::close()
|
||||||
|
//! @note Provider locking rules apply (@see provider_roles_requester_locking).
|
||||||
|
void close(bool destroy=false);
|
||||||
|
|
||||||
|
//! Add a PV (eg. SharedPV) to this provider.
|
||||||
|
void add(const std::string& name,
|
||||||
|
const std::tr1::shared_ptr<ChannelBuilder>& builder);
|
||||||
|
//! Remove a PV. Closes any open Channels to it.
|
||||||
|
//! @returns the PV which has been removed.
|
||||||
|
//! @note Provider locking rules apply (@see provider_roles_requester_locking).
|
||||||
|
std::tr1::shared_ptr<ChannelBuilder> remove(const std::string& name);
|
||||||
|
|
||||||
|
//! Fetch the underlying ChannelProvider. Usually to build a ServerContext around.
|
||||||
|
std::tr1::shared_ptr<epics::pvAccess::ChannelProvider> provider() const;
|
||||||
|
|
||||||
|
// iterate through currently add()'d PVs. Iteraters are invalidated by concurrent add() or remove()
|
||||||
|
builders_t::const_iterator begin() const;
|
||||||
|
builders_t::const_iterator end() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief A Provider which has no pre-configured list of names.
|
||||||
|
*
|
||||||
|
* Through an associated Handler, this provider sees all searchs, and may claim
|
||||||
|
* them.
|
||||||
|
*
|
||||||
|
* @see @ref pvas_sharedptr
|
||||||
|
*/
|
||||||
|
class epicsShareClass DynamicProvider {
|
||||||
|
public:
|
||||||
|
POINTER_DEFINITIONS(DynamicProvider);
|
||||||
|
struct Impl;
|
||||||
|
private:
|
||||||
|
std::tr1::shared_ptr<Impl> impl; // const after ctor
|
||||||
|
public:
|
||||||
|
//! A single client serach request. May be associated with more than one name
|
||||||
|
class Search {
|
||||||
|
friend struct Impl;
|
||||||
|
bool isclaimed;
|
||||||
|
std::string cname;
|
||||||
|
Search(const std::string& name) :isclaimed(false),cname(name) {}
|
||||||
|
public:
|
||||||
|
//! The name being queried
|
||||||
|
const std::string& name() const { return cname; }
|
||||||
|
//! Stake a claim.
|
||||||
|
bool claimed() const { return isclaimed; }
|
||||||
|
//! Has been claimed()
|
||||||
|
void claim() { isclaimed = true; }
|
||||||
|
};
|
||||||
|
typedef std::vector<Search> search_type;
|
||||||
|
|
||||||
|
/** Callbacks associated with DynamicProvider.
|
||||||
|
*
|
||||||
|
* For the purposes of locking, this class is a Requester (see @ref provider_roles_requester_locking).
|
||||||
|
* It's methods will not be called with locks held. It may call
|
||||||
|
* methods which lock.
|
||||||
|
*/
|
||||||
|
struct epicsShareClass Handler {
|
||||||
|
POINTER_DEFINITIONS(Handler);
|
||||||
|
typedef epics::pvData::shared_vector<std::string> names_type;
|
||||||
|
virtual ~Handler() {}
|
||||||
|
//! Called with name(s) which some client is searching for
|
||||||
|
virtual void hasChannels(search_type& name) =0;
|
||||||
|
//! Called when a client is requesting a list of channel names we provide. Callee should set dynamic=false if this list is exhaustive.
|
||||||
|
virtual void listChannels(names_type& names, bool& dynamic) {}
|
||||||
|
//! Called when a client is attempting to open a new channel to this SharedPV
|
||||||
|
virtual std::tr1::shared_ptr<epics::pvAccess::Channel> createChannel(const std::tr1::shared_ptr<epics::pvAccess::ChannelProvider>& provider,
|
||||||
|
const std::string& name,
|
||||||
|
const std::tr1::shared_ptr<epics::pvAccess::ChannelRequester>& requester) =0;
|
||||||
|
//! Called when the last reference to a DynamicProvider is released. Should close any channels.
|
||||||
|
virtual void destroy() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Build a new provider.
|
||||||
|
//! @param name Provider Name. Only relevant if registerAsServer() is called, then must be unique in this process.
|
||||||
|
//! @param handler Our callbacks. Internally stored a shared_ptr (strong reference).
|
||||||
|
DynamicProvider(const std::string& name,
|
||||||
|
const std::tr1::shared_ptr<Handler>& handler);
|
||||||
|
~DynamicProvider();
|
||||||
|
|
||||||
|
Handler::shared_pointer getHandler() const;
|
||||||
|
|
||||||
|
//void close();
|
||||||
|
|
||||||
|
//! Fetch the underlying ChannelProvider. Usually to build a ServerContext around.
|
||||||
|
std::tr1::shared_ptr<epics::pvAccess::ChannelProvider> provider() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! @}
|
||||||
|
|
||||||
|
} // namespace pvas
|
||||||
|
|
||||||
|
#endif // PVA_SERVER_H
|
270
src/server/server.cpp
Normal file
270
src/server/server.cpp
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
/*
|
||||||
|
* Copyright information and license terms for this software can be
|
||||||
|
* found in the file LICENSE that is included with the distribution
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <epicsMutex.h>
|
||||||
|
#include <epicsGuard.h>
|
||||||
|
|
||||||
|
#define epicsExportSharedSymbols
|
||||||
|
#include "pva/server.h"
|
||||||
|
#include "pv/pvAccess.h"
|
||||||
|
#include "pv/reftrack.h"
|
||||||
|
|
||||||
|
namespace pvd = epics::pvData;
|
||||||
|
namespace pva = epics::pvAccess;
|
||||||
|
|
||||||
|
typedef epicsGuard<epicsMutex> Guard;
|
||||||
|
typedef epicsGuardRelease<epicsMutex> UnGuard;
|
||||||
|
|
||||||
|
namespace pvas {
|
||||||
|
|
||||||
|
struct StaticProvider::Impl : public pva::ChannelProvider
|
||||||
|
{
|
||||||
|
POINTER_DEFINITIONS(Impl);
|
||||||
|
|
||||||
|
static size_t num_instances;
|
||||||
|
|
||||||
|
const std::string name;
|
||||||
|
pva::ChannelFind::shared_pointer finder; // const after ctor
|
||||||
|
std::tr1::weak_ptr<Impl> internal_self, external_self; // const after ctor
|
||||||
|
|
||||||
|
mutable epicsMutex mutex;
|
||||||
|
|
||||||
|
typedef StaticProvider::builders_t builders_t;
|
||||||
|
builders_t builders;
|
||||||
|
|
||||||
|
Impl(const std::string& name)
|
||||||
|
:name(name)
|
||||||
|
{
|
||||||
|
REFTRACE_INCREMENT(num_instances);
|
||||||
|
}
|
||||||
|
virtual ~Impl() {
|
||||||
|
REFTRACE_DECREMENT(num_instances);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void destroy() OVERRIDE FINAL {}
|
||||||
|
|
||||||
|
virtual std::string getProviderName() OVERRIDE FINAL { return name; }
|
||||||
|
virtual pva::ChannelFind::shared_pointer channelFind(std::string const & name,
|
||||||
|
pva::ChannelFindRequester::shared_pointer const & requester) OVERRIDE FINAL
|
||||||
|
{
|
||||||
|
bool found;
|
||||||
|
|
||||||
|
{
|
||||||
|
Guard G(mutex);
|
||||||
|
|
||||||
|
found = builders.find(name)!=builders.end();
|
||||||
|
}
|
||||||
|
requester->channelFindResult(pvd::Status(), finder, found);
|
||||||
|
return finder;
|
||||||
|
}
|
||||||
|
virtual pva::ChannelFind::shared_pointer channelList(pva::ChannelListRequester::shared_pointer const & requester) OVERRIDE FINAL
|
||||||
|
{
|
||||||
|
epics::pvData::PVStringArray::svector names;
|
||||||
|
{
|
||||||
|
Guard G(mutex);
|
||||||
|
names.reserve(builders.size());
|
||||||
|
for(builders_t::const_iterator it(builders.begin()), end(builders.end()); it!=end; ++it) {
|
||||||
|
names.push_back(it->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
requester->channelListResult(pvd::Status(), finder, pvd::freeze(names), false);
|
||||||
|
return finder;
|
||||||
|
}
|
||||||
|
virtual pva::Channel::shared_pointer createChannel(std::string const & name,
|
||||||
|
pva::ChannelRequester::shared_pointer const & requester,
|
||||||
|
short priority, std::string const & address) OVERRIDE FINAL
|
||||||
|
{
|
||||||
|
pva::Channel::shared_pointer ret;
|
||||||
|
pvd::Status sts;
|
||||||
|
|
||||||
|
{
|
||||||
|
Guard G(mutex);
|
||||||
|
builders_t::const_iterator it(builders.find(name));
|
||||||
|
if(it!=builders.end())
|
||||||
|
ret = it->second->connect(Impl::shared_pointer(internal_self), name, requester);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!ret) {
|
||||||
|
sts = pvd::Status::error("No such channel");
|
||||||
|
}
|
||||||
|
|
||||||
|
requester->channelCreated(sts, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t StaticProvider::Impl::num_instances;
|
||||||
|
|
||||||
|
StaticProvider::ChannelBuilder::~ChannelBuilder() {}
|
||||||
|
|
||||||
|
StaticProvider::StaticProvider(const std::string &name)
|
||||||
|
:impl(new Impl(name))
|
||||||
|
{
|
||||||
|
impl->internal_self = impl;
|
||||||
|
impl->finder = pva::ChannelFind::buildDummy(impl);
|
||||||
|
// wrap ref to call destroy when all external refs (from DyamicProvider::impl) are released.
|
||||||
|
impl.reset(impl.get(), pvd::Destroyable::cleaner(impl));
|
||||||
|
impl->external_self = impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
StaticProvider::~StaticProvider() { close(); }
|
||||||
|
|
||||||
|
void StaticProvider::close(bool destroy)
|
||||||
|
{
|
||||||
|
Impl::builders_t pvs;
|
||||||
|
{
|
||||||
|
Guard G(impl->mutex);
|
||||||
|
if(destroy) {
|
||||||
|
pvs.swap(impl->builders); // consume
|
||||||
|
} else {
|
||||||
|
pvs = impl->builders; // just copy, close() is a relatively rare action
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(Impl::builders_t::iterator it(pvs.begin()), end(pvs.end()); it!=end; ++it) {
|
||||||
|
it->second->close(destroy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tr1::shared_ptr<epics::pvAccess::ChannelProvider> StaticProvider::provider() const
|
||||||
|
{
|
||||||
|
return Impl::shared_pointer(impl->internal_self);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StaticProvider::add(const std::string& name,
|
||||||
|
const std::tr1::shared_ptr<ChannelBuilder>& builder)
|
||||||
|
{
|
||||||
|
Guard G(impl->mutex);
|
||||||
|
if(impl->builders.find(name)!=impl->builders.end())
|
||||||
|
throw std::logic_error("Duplicate PV name");
|
||||||
|
impl->builders[name] = builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tr1::shared_ptr<StaticProvider::ChannelBuilder> StaticProvider::remove(const std::string& name)
|
||||||
|
{
|
||||||
|
std::tr1::shared_ptr<StaticProvider::ChannelBuilder> ret;
|
||||||
|
{
|
||||||
|
Guard G(impl->mutex);
|
||||||
|
Impl::builders_t::iterator it(impl->builders.find(name));
|
||||||
|
if(it!=impl->builders.end()) {
|
||||||
|
ret = it->second;
|
||||||
|
impl->builders.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(ret)
|
||||||
|
ret->close(true);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
StaticProvider::builders_t::const_iterator StaticProvider::begin() const {
|
||||||
|
Guard G(impl->mutex);
|
||||||
|
return impl->builders.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
StaticProvider::builders_t::const_iterator StaticProvider::end() const {
|
||||||
|
Guard G(impl->mutex);
|
||||||
|
return impl->builders.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct DynamicProvider::Impl : public pva::ChannelProvider
|
||||||
|
{
|
||||||
|
POINTER_DEFINITIONS(Impl);
|
||||||
|
|
||||||
|
static size_t num_instances;
|
||||||
|
|
||||||
|
const std::string name;
|
||||||
|
const std::tr1::shared_ptr<Handler> handler;
|
||||||
|
pva::ChannelFind::shared_pointer finder; // const after ctor
|
||||||
|
std::tr1::weak_ptr<Impl> internal_self, external_self; // const after ctor
|
||||||
|
|
||||||
|
mutable epicsMutex mutex;
|
||||||
|
|
||||||
|
Impl(const std::string& name,
|
||||||
|
const std::tr1::shared_ptr<Handler>& handler)
|
||||||
|
:name(name)
|
||||||
|
,handler(handler)
|
||||||
|
{
|
||||||
|
REFTRACE_INCREMENT(num_instances);
|
||||||
|
}
|
||||||
|
virtual ~Impl() {
|
||||||
|
REFTRACE_DECREMENT(num_instances);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void destroy() OVERRIDE FINAL {
|
||||||
|
handler->destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string getProviderName() OVERRIDE FINAL { return name; }
|
||||||
|
virtual pva::ChannelFind::shared_pointer channelFind(std::string const & name,
|
||||||
|
pva::ChannelFindRequester::shared_pointer const & requester) OVERRIDE FINAL
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
{
|
||||||
|
search_type search;
|
||||||
|
search.push_back(DynamicProvider::Search(name));
|
||||||
|
|
||||||
|
handler->hasChannels(search);
|
||||||
|
|
||||||
|
found = !search.empty() && search[0].name()==name && search[0].claimed();
|
||||||
|
}
|
||||||
|
requester->channelFindResult(pvd::Status(), finder, found);
|
||||||
|
return finder;
|
||||||
|
}
|
||||||
|
virtual pva::ChannelFind::shared_pointer channelList(pva::ChannelListRequester::shared_pointer const & requester) OVERRIDE FINAL
|
||||||
|
{
|
||||||
|
epics::pvData::PVStringArray::svector names;
|
||||||
|
bool dynamic = true;
|
||||||
|
handler->listChannels(names, dynamic);
|
||||||
|
requester->channelListResult(pvd::Status(), finder, pvd::freeze(names), dynamic);
|
||||||
|
return finder;
|
||||||
|
}
|
||||||
|
virtual pva::Channel::shared_pointer createChannel(std::string const & name,
|
||||||
|
pva::ChannelRequester::shared_pointer const & requester,
|
||||||
|
short priority, std::string const & address) OVERRIDE FINAL
|
||||||
|
{
|
||||||
|
pva::Channel::shared_pointer ret;
|
||||||
|
pvd::Status sts;
|
||||||
|
|
||||||
|
ret = handler->createChannel(ChannelProvider::shared_pointer(internal_self), name, requester);
|
||||||
|
|
||||||
|
requester->channelCreated(sts, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t DynamicProvider::Impl::num_instances;
|
||||||
|
|
||||||
|
DynamicProvider::DynamicProvider(const std::string &name,
|
||||||
|
const std::tr1::shared_ptr<Handler> &handler)
|
||||||
|
:impl(new Impl(name, handler))
|
||||||
|
{
|
||||||
|
impl->internal_self = impl;
|
||||||
|
impl->finder = pva::ChannelFind::buildDummy(impl);
|
||||||
|
// wrap ref to call destroy when all external refs (from DyamicProvider::impl) are released.
|
||||||
|
impl.reset(impl.get(), pvd::Destroyable::cleaner(impl));
|
||||||
|
impl->external_self = impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicProvider::~DynamicProvider() {}
|
||||||
|
|
||||||
|
DynamicProvider::Handler::shared_pointer DynamicProvider::getHandler() const
|
||||||
|
{
|
||||||
|
return impl->handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tr1::shared_ptr<epics::pvAccess::ChannelProvider> DynamicProvider::provider() const
|
||||||
|
{
|
||||||
|
return Impl::shared_pointer(impl->internal_self);
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerRefTrackServer()
|
||||||
|
{
|
||||||
|
epics::registerRefCounter("pvas::StaticProvider", &StaticProvider::Impl::num_instances);
|
||||||
|
epics::registerRefCounter("pvas::DynamicProvider", &DynamicProvider::Impl::num_instances);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace pvas
|
Reference in New Issue
Block a user