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
This commit is contained in:
Michael Davidsaver
2017-05-31 11:40:51 +02:00
parent 0fbbcc2d9f
commit ce25f0b175
16 changed files with 299 additions and 735 deletions

View File

@@ -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<PipelineChannelProvider> 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<ThreadRunnerParam*>(usr);
ThreadRunnerParam param = *pusr;
delete pusr;
param.server->run(param.timeToRun);
}
/// Method requires usage of std::tr1::shared_ptr<PipelineServer>. This instance must be
/// owned by a shared_ptr instance.
void PipelineServer::runInNewThread(int seconds)
{
std::auto_ptr<ThreadRunnerParam> 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)

View File

@@ -21,7 +21,7 @@
#include <pv/pvAccess.h>
#include <pv/pipelineService.h>
#include <pv/serverContextImpl.h>
#include <pv/serverContext.h>
#include <shareLib.h>
@@ -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

View File

@@ -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.

View File

@@ -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);

View File

@@ -36,7 +36,6 @@ class epicsShareClass RPCServer :
private:
std::tr1::shared_ptr<ServerContext> m_serverContext;
ChannelProviderFactory::shared_pointer m_channelProviderFactory;
ChannelProvider::shared_pointer m_channelProviderImpl;
// TODO no thread poll implementation

View File

@@ -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<RPCChannelProvider> 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<ServerContextImpl*>(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)

View File

@@ -14,6 +14,7 @@
#include <pv/pvaConstants.h>
#include <pv/pvaVersion.h>
#include <pv/pvAccess.h>
#include <pv/configuration.h>
#include <shareLib.h>
@@ -26,8 +27,7 @@ namespace pvAccess {
class epicsShareClass ServerContext
{
public:
typedef std::tr1::shared_ptr<ServerContext> shared_pointer;
typedef std::tr1::shared_ptr<const ServerContext> const_shared_pointer;
POINTER_DEFINITIONS(ServerContext);
/**
* Destructor
@@ -46,37 +46,22 @@ public:
*/
virtual const Version& getVersion() = 0;
/**
* Set <code>ChannelProviderRegistry</code> 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 <code>0</code>
* the method would block until <code>destroy()</code> 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 <code>destroy()</code> 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<ChannelProvider::shared_pointer> _providers;
public:
Config() {}
Config& config(const Configuration::const_shared_pointer& c) { _conf = c; return *this; }
Config& providers(const std::vector<ChannelProvider::shared_pointer>& 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(

View File

@@ -1,6 +1,7 @@
#ifndef SERVERCONTEXTIMPL_H
#define SERVERCONTEXTIMPL_H
#include <pv/thread.h>
#include <pv/blockingUDP.h>
#include <pv/blockingTCP.h>
#include <pv/beaconEmitter.h>
@@ -15,33 +16,27 @@ class epicsShareClass ServerContextImpl :
public Context,
public std::tr1::enable_shared_from_this<ServerContextImpl>
{
friend class ServerContext;
public:
typedef std::tr1::shared_ptr<ServerContextImpl> shared_pointer;
typedef std::tr1::shared_ptr<const ServerContextImpl> 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<std::string, std::tr1::shared_ptr<SecurityPlugin> >& 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 <code>State</code>
*/
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;
};
}

View File

@@ -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());

View File

@@ -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<ChannelProviderRegistry::stringVector_t> 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<ChannelProviderRegistry::stringVector_t> 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<ChannelProvider::shared_pointer>::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<ChannelProvider::shared_pointer>& ServerContextImpl::getChannelProviders()
{
return _channelProviders;
@@ -620,60 +470,69 @@ std::map<std::string, std::tr1::shared_ptr<SecurityPlugin> >& ServerContextImpl:
struct ThreadRunnerParam {
ServerContextImpl::shared_pointer ctx;
int timeToRun;
};
static void threadRunner(void* usr)
{
ThreadRunnerParam* pusr = static_cast<ThreadRunnerParam*>(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<ThreadRunnerParam> 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;
}
}}

View File

@@ -21,7 +21,7 @@ testChannelConnect_SRCS += testChannelConnect.cpp
TESTPROD_HOST += testServerContext
testServerContext_SRCS += testServerContext.cpp
TESTS += testServerContext
PROD_HOST += testServer

View File

@@ -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<SyncChannelRequesterImpl> 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;

View File

@@ -53,7 +53,7 @@ class SumServiceImpl :
// create return structure and set data
PVStructure::shared_pointer result = getPVDataCreate()->createPVStructure(resultStructure);
result->getSubField<PVDouble>("c")->put(a+b);
result->getSubFieldT<PVDouble>("c")->put(a+b);
return result;
}
};

View File

@@ -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<epics::pvData::Event> 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<epics::pvData::Event> 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);

View File

@@ -9,7 +9,7 @@
// disable buggy boost enable_shared_from_this assert code
#define BOOST_DISABLE_ASSERTS
#include <pv/serverContextImpl.h>
#include <pv/serverContext.h>
#include <pv/clientContextImpl.h>
#include <epicsExit.h>
#include <pv/standardPVField.h>
@@ -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<MockServerChannelProvider*>(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<epicsUInt32>(timeToRun));
cout << "Done" << endl;

View File

@@ -2,8 +2,11 @@
* testServerContext.cpp
*/
#include <pv/serverContextImpl.h>
#include <pv/serverContext.h>
#include <epicsExit.h>
#include <testMain.h>
#include <epicsUnitTest.h>
using namespace epics::pvAccess;
using namespace epics::pvData;
@@ -17,7 +20,7 @@ public:
return "local";
};
TestChannelProvider(const std::tr1::shared_ptr<Configuration>&) {}
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<TestChannelProvider>("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();
}