diff --git a/pvAccessApp/pva/pvaConstants.h b/pvAccessApp/pva/pvaConstants.h index d453540..1dd07bf 100644 --- a/pvAccessApp/pva/pvaConstants.h +++ b/pvAccessApp/pva/pvaConstants.h @@ -68,6 +68,9 @@ namespace pvAccess { /** Default PVA provider name. */ const epics::pvData::String PVACCESS_DEFAULT_PROVIDER = "local"; + /** "All-providers registered" PVA provider name. */ + const epics::pvData::String PVACCESS_ALL_PROVIDERS = ""; + /** Name of the system env. variable to turn on debugging. */ const epics::pvData::String PVACCESS_DEBUG = "EPICS_PVA_DEBUG"; } diff --git a/pvAccessApp/remoteClient/clientContextImpl.cpp b/pvAccessApp/remoteClient/clientContextImpl.cpp index ec724c6..7e45e1d 100644 --- a/pvAccessApp/remoteClient/clientContextImpl.cpp +++ b/pvAccessApp/remoteClient/clientContextImpl.cpp @@ -3991,7 +3991,7 @@ namespace epics { m_addressList(""), m_autoAddressList(true), m_connectionTimeout(30.0f), m_beaconPeriod(15.0f), m_broadcastPort(PVA_BROADCAST_PORT), m_receiveBufferSize(MAX_TCP_RECV), m_namedLocker(), m_lastCID(0), m_lastIOID(0), - m_version("pvAccess Client", "cpp", 1, 2, 0, true), + m_version("pvAccess Client", "cpp", 4, 3, 0, false), m_contextState(CONTEXT_NOT_INITIALIZED), m_configuration(new SystemConfigurationImpl()), m_flushStrategy(DELAYED) diff --git a/pvAccessApp/server/serverContext.cpp b/pvAccessApp/server/serverContext.cpp index 729b295..d74904b 100644 --- a/pvAccessApp/server/serverContext.cpp +++ b/pvAccessApp/server/serverContext.cpp @@ -18,7 +18,7 @@ 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", 1, 2, 0, true); +const Version ServerContextImpl::VERSION("pvAccess Server", "cpp", 4, 3, 0, false); ServerContextImpl::ServerContextImpl(): _state(NOT_INITIALIZED), @@ -118,6 +118,12 @@ void ServerContextImpl::loadConfiguration() _channelProviderNames = config->getPropertyAsString("EPICS_PVAS_PROVIDER_NAMES", _channelProviderNames); } +bool ServerContextImpl::isChannelProviderNamePreconfigured() +{ + Configuration::shared_pointer config = getConfiguration(); + return config->hasProperty("EPICS_PVA_PROVIDER_NAMES") || config->hasProperty("EPICS_PVAS_PROVIDER_NAMES"); +} + void ServerContextImpl::initialize(ChannelAccess::shared_pointer const & channelAccess) { Lock guard(_mutex); @@ -138,13 +144,37 @@ void ServerContextImpl::initialize(ChannelAccess::shared_pointer const & channel _channelAccess = channelAccess; - // split comma separated names - std::stringstream ss(_channelProviderNames); - std::string providerName; - while (std::getline(ss, providerName, ',')) { - ChannelProvider::shared_pointer channelProvider = _channelAccess->getProvider(providerName); - if (channelProvider) - _channelProviders.push_back(channelProvider); + // user all providers + if (_channelProviderNames == PVACCESS_ALL_PROVIDERS) + { + _channelProviderNames.clear(); + + std::auto_ptr names = _channelAccess->getProviderNames(); + for (ChannelAccess::stringVector_t::iterator iter = names->begin(); iter != names->end(); iter++) + { + ChannelProvider::shared_pointer channelProvider = _channelAccess->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 = _channelAccess->getProvider(providerName); + if (channelProvider) + _channelProviders.push_back(channelProvider); + } } //_channelProvider = _channelAccess->getProvider(_channelProviderNames); @@ -564,5 +594,60 @@ void ServerContextImpl::newServerDetected() } + +struct ThreadRunnerParam { + ServerContextImpl::shared_pointer ctx; + int timeToRun; +}; + +static void threadRunner(void* usr) +{ + ThreadRunnerParam* pusr = static_cast(usr); + ThreadRunnerParam param = *pusr; + delete pusr; + + param.ctx->run(param.timeToRun); +} + + + +ServerContext::shared_pointer startPVAServer(String const & providerNames, int timeToRun, bool runInSeparateThread, bool printInfo) +{ + ServerContextImpl::shared_pointer ctx = ServerContextImpl::create(); + + // do not override configuration + if (providerNames == PVACCESS_ALL_PROVIDERS && !ctx->isChannelProviderNamePreconfigured()) + ctx->setChannelProviderName(providerNames); + + ChannelAccess::shared_pointer channelAccess = getChannelAccess(); + ctx->initialize(channelAccess); + + if (printInfo) + ctx->printInfo(); + + + if (runInSeparateThread) + { + // delete left to the thread + auto_ptr param(new ThreadRunnerParam()); + param->ctx = ctx; + param->timeToRun = timeToRun; + + // TODO can this fail? + epicsThreadCreate("startPVAServer", + epicsThreadPriorityMedium, + epicsThreadGetStackSize(epicsThreadStackBig), + threadRunner, param.get()); + + param.release(); + } + else + { + ctx->run(timeToRun); + } + + return ctx; +} + } } diff --git a/pvAccessApp/server/serverContext.h b/pvAccessApp/server/serverContext.h index d395eb0..99ffac9 100644 --- a/pvAccessApp/server/serverContext.h +++ b/pvAccessApp/server/serverContext.h @@ -39,7 +39,7 @@ public: */ virtual const Version& getVersion() = 0; - /** + /** * Set ChannelAccess implementation and initialize server. * @param channelAccess implementation of channel access to be served. */ @@ -114,7 +114,7 @@ public: //**************** derived from ServerContext ****************// const Version& getVersion(); - void initialize(ChannelAccess::shared_pointer const & channelAccess); + void initialize(ChannelAccess::shared_pointer const & channelAccess); void run(epics::pvData::int32 seconds); void shutdown(); void destroy(); @@ -274,6 +274,12 @@ public: */ std::vector getChannelProviders(); + /** + * Return true if channel provider name is provided by configuration (e.g. system env. var.). + * @return true if channel provider name is provided by configuration (e.g. system env. var.) + */ + bool isChannelProviderNamePreconfigured(); + private: /** * Initialization status. @@ -406,7 +412,11 @@ private: Configuration::shared_pointer configuration; }; - +extern ServerContext::shared_pointer startPVAServer( + epics::pvData::String const & providerNames = PVACCESS_ALL_PROVIDERS, + int timeToRun = 0, + bool runInSeparateThread = false, + bool printInfo = false); } } diff --git a/pvAccessApp/utils/configuration.cpp b/pvAccessApp/utils/configuration.cpp index e52f446..ebb9cdf 100644 --- a/pvAccessApp/utils/configuration.cpp +++ b/pvAccessApp/utils/configuration.cpp @@ -80,6 +80,11 @@ string Properties::getProperty(const string &key, const string &defaultValue) return defaultValue; } +bool Properties::hasProperty(const string &key) +{ + return (_properties.find(key) != _properties.end()); +} + void Properties::load() { _properties.clear(); @@ -333,6 +338,11 @@ string SystemConfigurationImpl::getPropertyAsString(const string &name, const st return _properties->getProperty(name,defaultValue); } +bool SystemConfigurationImpl::hasProperty(const string &key) +{ + return _properties->hasProperty(key); +} + ConfigurationProviderImpl::ConfigurationProviderImpl() { diff --git a/pvAccessApp/utils/configuration.h b/pvAccessApp/utils/configuration.h index 358f4ed..8ca29c5 100644 --- a/pvAccessApp/utils/configuration.h +++ b/pvAccessApp/utils/configuration.h @@ -34,6 +34,7 @@ public: void setProperty(const std::string &key,const std::string &value); std::string getProperty(const std::string &key); std::string getProperty(const std::string &key, const std::string &defaultValue); + bool hasProperty(const std::string &key); void store(); void store(const std::string &fileName); @@ -124,6 +125,8 @@ public: * @return environment variable value as std::string or default value if it does not exist. */ virtual std::string getPropertyAsString(const std::string &name, const std::string &defaultValue) = 0; + + virtual bool hasProperty(const std::string &name) = 0; }; class SystemConfigurationImpl: public Configuration @@ -136,7 +139,8 @@ public: float getPropertyAsFloat(const std::string &name, const float defaultValue); float getPropertyAsDouble(const std::string &name, const double defaultValue); std::string getPropertyAsString(const std::string &name, const std::string &defaultValue); - std::auto_ptr _properties; + bool hasProperty(const std::string &name); + std::auto_ptr _properties; private: ENV_PARAM _envParam; std::istringstream _ibuffer;