Rename pvAccessApp to src, adjust Makefiles
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
# This is a Makefile fragment, see ../Makefile
|
||||
|
||||
SRC_DIRS += $(PVACCESS_SRC)/utils
|
||||
|
||||
INC += hexDump.h
|
||||
INC += inetAddressUtil.h
|
||||
INC += logger.h
|
||||
INC += introspectionRegistry.h
|
||||
INC += namedLockPattern.h
|
||||
INC += referenceCountingLock.h
|
||||
INC += configuration.h
|
||||
INC += likely.h
|
||||
|
||||
LIBSRCS += hexDump.cpp
|
||||
LIBSRCS += inetAddressUtil.cpp
|
||||
LIBSRCS += logger.cpp
|
||||
LIBSRCS += introspectionRegistry.cpp
|
||||
LIBSRCS += configuration.cpp
|
||||
LIBSRCS += referenceCountingLock.cpp
|
||||
@@ -0,0 +1,397 @@
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* pvAccessCPP is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <pv/epicsException.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/configuration.h>
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ < 3
|
||||
#define OLDGCC
|
||||
#define NO_STREAM_EXCEPTIONS
|
||||
#endif
|
||||
|
||||
namespace epics {
|
||||
namespace pvAccess {
|
||||
|
||||
using namespace epics::pvData;
|
||||
using namespace std;
|
||||
|
||||
Properties::Properties()
|
||||
{
|
||||
_fileName = "";
|
||||
_infile.reset(new ifstream());
|
||||
_infile->exceptions (ifstream::failbit | ifstream::badbit );
|
||||
_outfile.reset(new ofstream());
|
||||
_outfile->exceptions (ofstream::failbit | ofstream::badbit );
|
||||
}
|
||||
|
||||
Properties::Properties(const string &fileName)
|
||||
{
|
||||
_fileName = fileName;
|
||||
_infile.reset(new ifstream());
|
||||
_infile->exceptions (ifstream::failbit | ifstream::badbit );
|
||||
_outfile.reset(new ofstream());
|
||||
_outfile->exceptions (ofstream::failbit | ofstream::badbit );
|
||||
}
|
||||
|
||||
Properties::~Properties()
|
||||
{
|
||||
}
|
||||
|
||||
void Properties::setProperty(const string &key, const string &value)
|
||||
{
|
||||
string oldValue;
|
||||
std::map<std::string,std::string>::iterator propertiesIterator = _properties.find(key);
|
||||
|
||||
if(propertiesIterator != _properties.end()) //found in map
|
||||
{
|
||||
_properties.erase(propertiesIterator);
|
||||
}
|
||||
_properties[key] = value;
|
||||
}
|
||||
|
||||
string Properties::getProperty(const string &key)
|
||||
{
|
||||
std::map<std::string,std::string>::iterator propertiesIterator = _properties.find(key);
|
||||
if(propertiesIterator != _properties.end()) //found in map
|
||||
{
|
||||
return string(propertiesIterator->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
string errMsg = "Property not found in the map: " + key;
|
||||
THROW_BASE_EXCEPTION(errMsg.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
string Properties::getProperty(const string &key, const string &defaultValue)
|
||||
{
|
||||
std::map<std::string,std::string>::iterator propertiesIterator = _properties.find(key);
|
||||
if(propertiesIterator != _properties.end()) //found in map
|
||||
{
|
||||
return string(propertiesIterator->second);
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
bool Properties::hasProperty(const string &key)
|
||||
{
|
||||
return (_properties.find(key) != _properties.end());
|
||||
}
|
||||
|
||||
void Properties::load()
|
||||
{
|
||||
_properties.clear();
|
||||
|
||||
#ifdef NO_STREAM_EXCEPTIONS
|
||||
_infile->open(_fileName.c_str(),ifstream::in);
|
||||
if (_infile->fail())
|
||||
#else
|
||||
try
|
||||
{
|
||||
_infile->open(_fileName.c_str(),ifstream::in);
|
||||
}
|
||||
catch (ifstream::failure& e)
|
||||
#endif
|
||||
{
|
||||
string errMsg = "Error opening file: " + string(_fileName.c_str());
|
||||
THROW_BASE_EXCEPTION(errMsg.c_str());
|
||||
}
|
||||
|
||||
string line;
|
||||
string property;
|
||||
string key;
|
||||
#ifndef NO_STREAM_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif
|
||||
while(!_infile->eof())
|
||||
{
|
||||
line.erase();
|
||||
std::getline(*_infile,line);
|
||||
|
||||
#ifdef NO_STREAM_EXCEPTIONS
|
||||
if (_infile->fail())
|
||||
{
|
||||
_infile->close();
|
||||
if(_infile->eof())
|
||||
{
|
||||
return; //end of file
|
||||
}
|
||||
string errMsg = "Error reading file: " + _fileName;
|
||||
THROW_BASE_EXCEPTION(errMsg.c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
//remove trailing spaces
|
||||
truncate(line);
|
||||
|
||||
//empty line
|
||||
if(line.length() == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// comment
|
||||
if(line[0] == '#')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//line is in format: propertyName=propertyValue
|
||||
size_t pos = line.find_first_of('=',0);
|
||||
if(pos == string::npos) //bad value (= not found)
|
||||
{
|
||||
string errMsg = "Bad property line found: " + line;
|
||||
THROW_BASE_EXCEPTION(errMsg.c_str());
|
||||
}
|
||||
|
||||
key = line.substr(0,pos);
|
||||
truncate(key);
|
||||
property = line.substr(pos + 1,line.length());
|
||||
truncate(property);
|
||||
_properties[key] = property;
|
||||
}
|
||||
#ifndef NO_STREAM_EXCEPTIONS
|
||||
}
|
||||
catch (ifstream::failure& e)
|
||||
{
|
||||
_infile->close();
|
||||
if(_infile->eof())
|
||||
{
|
||||
return; //end of file
|
||||
}
|
||||
string errMsg = "Error reading file: " + _fileName;
|
||||
THROW_BASE_EXCEPTION(errMsg.c_str());
|
||||
}
|
||||
#endif
|
||||
_infile->close();
|
||||
}
|
||||
|
||||
void Properties::load(const string &fileName)
|
||||
{
|
||||
_fileName = fileName;
|
||||
load();
|
||||
}
|
||||
|
||||
void Properties::store()
|
||||
{
|
||||
#ifdef NO_STREAM_EXCEPTIONS
|
||||
_outfile->open(_fileName.c_str(),ifstream::trunc);
|
||||
if (_outfile->fail())
|
||||
#else
|
||||
try
|
||||
{
|
||||
_outfile->open(_fileName.c_str(),ifstream::trunc);
|
||||
}
|
||||
catch (ofstream::failure& e)
|
||||
#endif
|
||||
{
|
||||
string errMsg = "Error opening file: " + string(_fileName.c_str());
|
||||
THROW_BASE_EXCEPTION(errMsg.c_str());
|
||||
}
|
||||
|
||||
|
||||
for (std::map<std::string,std::string>::iterator propertiesIterator = _properties.begin();
|
||||
propertiesIterator != _properties.end();
|
||||
propertiesIterator++ )
|
||||
{
|
||||
#ifndef NO_STREAM_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif
|
||||
string line = string(propertiesIterator->first) + string("=") + string(propertiesIterator->second) + string("\n");
|
||||
_outfile->write(line.c_str(),line.length());
|
||||
#ifdef NO_STREAM_EXCEPTIONS
|
||||
if(_outfile->fail())
|
||||
#else
|
||||
}
|
||||
catch (ofstream::failure& e)
|
||||
#endif
|
||||
{
|
||||
_outfile->close();
|
||||
string errMsg = "Error writing to file: " + string(_fileName.c_str());
|
||||
THROW_BASE_EXCEPTION(errMsg.c_str());
|
||||
}
|
||||
}
|
||||
_outfile->close();
|
||||
}
|
||||
|
||||
void Properties::store(const string &fileName)
|
||||
{
|
||||
_fileName = fileName;
|
||||
store();
|
||||
}
|
||||
|
||||
void Properties::list()
|
||||
{
|
||||
for (std::map<std::string,std::string>::iterator propertiesIterator = _properties.begin() ;
|
||||
propertiesIterator != _properties.end();
|
||||
propertiesIterator++ )
|
||||
{
|
||||
cout << "Key:" << propertiesIterator->first << ",Value: " << propertiesIterator->second << endl;
|
||||
}
|
||||
}
|
||||
|
||||
SystemConfigurationImpl::SystemConfigurationImpl() :
|
||||
_properties(new Properties())
|
||||
{
|
||||
_envParam.name = new char[256];
|
||||
_envParam.pdflt = NULL;
|
||||
// no exception, default value is taken
|
||||
//_ibuffer.exceptions ( ifstream::failbit | ifstream::badbit );
|
||||
//_obuffer.exceptions ( ifstream::failbit | ifstream::badbit );
|
||||
}
|
||||
|
||||
SystemConfigurationImpl::~SystemConfigurationImpl()
|
||||
{
|
||||
if(_envParam.name) delete[] _envParam.name;
|
||||
}
|
||||
|
||||
bool SystemConfigurationImpl::getPropertyAsBoolean(const string &name, const bool defaultValue)
|
||||
{
|
||||
/*
|
||||
bool retval;
|
||||
_ibuffer.clear();
|
||||
_obuffer.clear();
|
||||
_obuffer.str("");
|
||||
_obuffer << defaultValue;
|
||||
_ibuffer.str(getPropertyAsString(name,_obuffer.str()));
|
||||
_ibuffer >> retval;
|
||||
if (_ibuffer.fail() || _ibuffer.bad())
|
||||
return defaultValue;
|
||||
else
|
||||
return retval;
|
||||
*/
|
||||
|
||||
string value = getPropertyAsString(name, defaultValue ? "1" : "0");
|
||||
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
|
||||
|
||||
bool isTrue = (value == "1") || (value == "true") || (value == "yes");
|
||||
bool isFalse = (value == "0") || (value == "false") || (value == "no");
|
||||
|
||||
// invalid value
|
||||
if (!(isTrue || isFalse))
|
||||
return defaultValue;
|
||||
else
|
||||
return isTrue == true;
|
||||
}
|
||||
|
||||
int32 SystemConfigurationImpl::getPropertyAsInteger(const string &name, const int32 defaultValue)
|
||||
{
|
||||
int32 retval;
|
||||
_ibuffer.clear();
|
||||
_obuffer.clear();
|
||||
_obuffer.str("");
|
||||
_obuffer << defaultValue;
|
||||
_ibuffer.str(getPropertyAsString(name, _obuffer.str()));
|
||||
_ibuffer >> retval;
|
||||
if (_ibuffer.fail() || _ibuffer.bad())
|
||||
return defaultValue;
|
||||
else
|
||||
return retval;
|
||||
}
|
||||
|
||||
float SystemConfigurationImpl::getPropertyAsFloat(const string &name, const float defaultValue)
|
||||
{
|
||||
float retval;
|
||||
_ibuffer.clear();
|
||||
_obuffer.clear();
|
||||
_obuffer.str("");
|
||||
_obuffer << defaultValue;
|
||||
_ibuffer.str(getPropertyAsString(name, _obuffer.str()));
|
||||
_ibuffer >> retval;
|
||||
if (_ibuffer.fail() || _ibuffer.bad())
|
||||
return defaultValue;
|
||||
else
|
||||
return retval;
|
||||
}
|
||||
|
||||
float SystemConfigurationImpl::getPropertyAsDouble(const string &name, const double defaultValue)
|
||||
{
|
||||
float retval;
|
||||
_ibuffer.clear();
|
||||
_obuffer.clear();
|
||||
_obuffer.str("");
|
||||
_obuffer << defaultValue;
|
||||
_ibuffer.str(getPropertyAsString(name, _obuffer.str()));
|
||||
_ibuffer >> retval;
|
||||
if (_ibuffer.fail() || _ibuffer.bad())
|
||||
return defaultValue;
|
||||
else
|
||||
return retval;
|
||||
}
|
||||
|
||||
string SystemConfigurationImpl::getPropertyAsString(const string &name, const string &defaultValue)
|
||||
{
|
||||
strncpy(_envParam.name,name.c_str(),name.length() + 1);
|
||||
const char* val = envGetConfigParamPtr(&_envParam);
|
||||
if(val != NULL)
|
||||
{
|
||||
return _properties->getProperty(name, string(val));
|
||||
}
|
||||
return _properties->getProperty(name, defaultValue);
|
||||
}
|
||||
|
||||
bool SystemConfigurationImpl::hasProperty(const string &key)
|
||||
{
|
||||
strncpy(_envParam.name,key.c_str(),key.length() + 1);
|
||||
const char* val = envGetConfigParamPtr(&_envParam);
|
||||
return (val != NULL) || _properties->hasProperty(key);
|
||||
}
|
||||
|
||||
ConfigurationProviderImpl::ConfigurationProviderImpl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ConfigurationProviderImpl::~ConfigurationProviderImpl()
|
||||
{
|
||||
}
|
||||
|
||||
void ConfigurationProviderImpl::registerConfiguration(const string &name, Configuration::shared_pointer const & configuration)
|
||||
{
|
||||
Lock guard(_mutex);
|
||||
std::map<std::string,Configuration::shared_pointer>::iterator configsIter = _configs.find(name);
|
||||
if(configsIter != _configs.end())
|
||||
{
|
||||
string msg = "configuration with name " + name + " already registered";
|
||||
THROW_BASE_EXCEPTION(msg.c_str());
|
||||
}
|
||||
_configs[name] = configuration;
|
||||
}
|
||||
|
||||
Configuration::shared_pointer ConfigurationProviderImpl::getConfiguration(const string &name)
|
||||
{
|
||||
std::map<std::string,Configuration::shared_pointer>::iterator configsIter = _configs.find(name);
|
||||
if(configsIter != _configs.end())
|
||||
{
|
||||
return configsIter->second;
|
||||
}
|
||||
return Configuration::shared_pointer();
|
||||
}
|
||||
|
||||
ConfigurationProvider::shared_pointer configurationProvider;
|
||||
Mutex conf_factory_mutex;
|
||||
|
||||
ConfigurationProvider::shared_pointer ConfigurationFactory::getProvider()
|
||||
{
|
||||
Lock guard(conf_factory_mutex);
|
||||
if(configurationProvider.get() == NULL)
|
||||
{
|
||||
configurationProvider.reset(new ConfigurationProviderImpl());
|
||||
// default
|
||||
Configuration::shared_pointer systemConfig(new SystemConfigurationImpl());
|
||||
configurationProvider->registerConfiguration("system", systemConfig);
|
||||
}
|
||||
return configurationProvider;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* pvAccessCPP is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
|
||||
#ifndef CONFIGURATION_H
|
||||
#define CONFIGURATION_H
|
||||
|
||||
#include <string.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define configurationEpicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <pv/pvType.h>
|
||||
#include <pv/noDefaultMethods.h>
|
||||
#include <pv/lock.h>
|
||||
#include <pv/sharedPtr.h>
|
||||
|
||||
#include <envDefs.h>
|
||||
#ifdef configurationEpicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# undef configurationEpicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
namespace epics {
|
||||
namespace pvAccess {
|
||||
|
||||
class epicsShareClass Properties
|
||||
{
|
||||
public:
|
||||
Properties();
|
||||
Properties(const std::string &fileName);
|
||||
virtual ~Properties();
|
||||
|
||||
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);
|
||||
void load();
|
||||
void load(const std::string &fileName);
|
||||
void list();
|
||||
|
||||
private:
|
||||
std::map<std::string,std::string> _properties;
|
||||
std::auto_ptr<std::ifstream> _infile;
|
||||
std::auto_ptr<std::ofstream> _outfile;
|
||||
std::string _fileName;
|
||||
|
||||
inline void truncate(std::string& str)
|
||||
{
|
||||
while(str.length() != 0 && (str.at(0) == ' ' || str.at(0) == '\t'))
|
||||
{
|
||||
str.erase(0,1);
|
||||
}
|
||||
while(str.length() != 0 && (str.at(str.length()-1) == ' ' || str.at(str.length()-1) == '\t'))
|
||||
{
|
||||
str.erase(str.length()-1,1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Configuration
|
||||
*/
|
||||
class epicsShareClass Configuration : private epics::pvData::NoDefaultMethods
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(Configuration);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~Configuration() {};
|
||||
/**
|
||||
* Get the environment variable specified by name or return default value
|
||||
* if it does not exist.
|
||||
*
|
||||
* @param name name of the environment variable to return.
|
||||
* @param defualtValue default value to return if environment variable does not exists.
|
||||
*
|
||||
* @return environment variable value as bool or default value if it does not exist.
|
||||
*/
|
||||
virtual bool getPropertyAsBoolean(const std::string &name, const bool defaultValue) = 0;
|
||||
/**
|
||||
* Get the environment variable specified by name or return default value
|
||||
* if it does not exist.
|
||||
*
|
||||
* @param name name of the environment variable to return.
|
||||
* @param defualtValue default value to return if environment variable does not exists.
|
||||
*
|
||||
* @return environment variable value as int32 or default value if it does not exist.
|
||||
*/
|
||||
virtual epics::pvData::int32 getPropertyAsInteger(const std::string &name, const epics::pvData::int32 defaultValue) = 0;
|
||||
/**
|
||||
* Get the environment variable specified by name or return default value
|
||||
* if it does not exist.
|
||||
*
|
||||
* @param name name of the environment variable to return.
|
||||
* @param defualtValue default value to return if environment variable does not exists.
|
||||
*
|
||||
* @return environment variable value as float or default value if it does not exist.
|
||||
*/
|
||||
virtual float getPropertyAsFloat(const std::string &name, const float defaultValue) = 0;
|
||||
/**
|
||||
* Get the environment variable specified by name or return default value
|
||||
* if it does not exist.
|
||||
*
|
||||
* @param name name of the environment variable to return.
|
||||
* @param defualtValue default value to return if environment variable does not exists.
|
||||
*
|
||||
* @return environment variable value as double or default value if it does not exist.
|
||||
*/
|
||||
virtual float getPropertyAsDouble(const std::string &name, const double defaultValue) = 0;
|
||||
/**
|
||||
* Get the environment variable specified by name or return default value
|
||||
* if it does not exist.
|
||||
*
|
||||
* @param name name of the environment variable to return.
|
||||
* @param defualtValue default value to return if environment variable does not exists.
|
||||
*
|
||||
* @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 epicsShareClass SystemConfigurationImpl: public Configuration
|
||||
{
|
||||
public:
|
||||
SystemConfigurationImpl();
|
||||
~SystemConfigurationImpl();
|
||||
bool getPropertyAsBoolean(const std::string &name, const bool defaultValue);
|
||||
epics::pvData::int32 getPropertyAsInteger(const std::string &name, const epics::pvData::int32 defaultValue);
|
||||
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);
|
||||
bool hasProperty(const std::string &name);
|
||||
std::auto_ptr<Properties> _properties;
|
||||
private:
|
||||
ENV_PARAM _envParam;
|
||||
std::istringstream _ibuffer;
|
||||
std::ostringstream _obuffer;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Configuration provider.
|
||||
*/
|
||||
class epicsShareClass ConfigurationProvider : private epics::pvData::NoDefaultMethods
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ConfigurationProvider);
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~ConfigurationProvider() {};
|
||||
/**
|
||||
* Return configuration specified by name.
|
||||
*
|
||||
* @param name name of the configuration to return.
|
||||
*
|
||||
* @return configuration specified by name or NULL if it does not exists.
|
||||
*/
|
||||
virtual Configuration::shared_pointer getConfiguration(const std::string &name) = 0;
|
||||
/**
|
||||
* Register configuration.
|
||||
*
|
||||
* @param name name of the configuration to register.
|
||||
* @param configuration configuration to register.
|
||||
*/
|
||||
virtual void registerConfiguration(const std::string &name, Configuration::shared_pointer const & configuration) = 0;
|
||||
};
|
||||
|
||||
class ConfigurationProviderImpl: public ConfigurationProvider
|
||||
{
|
||||
public:
|
||||
ConfigurationProviderImpl();
|
||||
/**
|
||||
* Destructor. Note: Registered configurations will be deleted!!
|
||||
*/
|
||||
~ConfigurationProviderImpl();
|
||||
Configuration::shared_pointer getConfiguration(const std::string &name);
|
||||
void registerConfiguration(const std::string &name, Configuration::shared_pointer const & configuration);
|
||||
private:
|
||||
epics::pvData::Mutex _mutex;
|
||||
std::map<std::string,Configuration::shared_pointer> _configs;
|
||||
};
|
||||
|
||||
/**
|
||||
* Configuration factory.
|
||||
*/
|
||||
class epicsShareClass ConfigurationFactory : private epics::pvData::NoDefaultMethods
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ConfigurationFactory);
|
||||
|
||||
/**
|
||||
* Lazily creates configuration provider.
|
||||
*
|
||||
* @param name name of the configuration to register.
|
||||
* @param configuration configuration to register.
|
||||
*
|
||||
* @return configuration provider
|
||||
*/
|
||||
static ConfigurationProvider::shared_pointer getProvider();
|
||||
|
||||
private:
|
||||
ConfigurationFactory() {};
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* CONFIGURATION_H */
|
||||
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* pvAccessCPP is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/hexDump.h>
|
||||
|
||||
using namespace epics::pvData;
|
||||
using std::stringstream;
|
||||
using std::endl;
|
||||
using std::cout;
|
||||
|
||||
namespace epics {
|
||||
namespace pvAccess {
|
||||
|
||||
/// Byte to hexchar mapping.
|
||||
static const char lookup[] = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||
|
||||
/// Get hex representation of byte.
|
||||
String toHex(int8 b) {
|
||||
String sb;
|
||||
|
||||
int upper = (b>>4)&0x0F;
|
||||
sb += lookup[upper];
|
||||
|
||||
int lower = b&0x0F;
|
||||
sb += lookup[lower];
|
||||
|
||||
sb += ' ';
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
||||
/// Get ASCII representation of byte, dot if non-readable.
|
||||
char toAscii(int8 b) {
|
||||
if(b>(int8)31&&b<(int8)127)
|
||||
return (char)b;
|
||||
else
|
||||
return '.';
|
||||
}
|
||||
|
||||
void hexDump(String const & name, const int8 *bs, int len) {
|
||||
hexDump(name, bs, 0, len);
|
||||
}
|
||||
|
||||
void hexDump(String const & name, const int8 *bs, int start, int len) {
|
||||
hexDump("", name, bs, start, len);
|
||||
}
|
||||
|
||||
void hexDump(String const & prologue, String const & name, const int8 *bs,
|
||||
int start, int len) {
|
||||
|
||||
stringstream header;
|
||||
|
||||
header<<prologue<<endl<<"Hexdump ["<<name<<"] size = "<<len;
|
||||
|
||||
String out(header.str());
|
||||
|
||||
String chars;
|
||||
|
||||
for(int i = start; i<(start+len); i++) {
|
||||
if(((i-start)%16)==0) {
|
||||
out += chars;
|
||||
out += '\n';
|
||||
chars.erase();
|
||||
}
|
||||
|
||||
chars += toAscii(bs[i]);
|
||||
|
||||
out += toHex(bs[i]);
|
||||
|
||||
if(((i-start)%4)==3) {
|
||||
chars += ' ';
|
||||
out += ' ';
|
||||
}
|
||||
}
|
||||
|
||||
if(len%16!=0) {
|
||||
int pad = 0;
|
||||
int delta_bytes = 16-(len%16);
|
||||
|
||||
//rest of line (no of bytes)
|
||||
//each byte takes two chars plus one ws
|
||||
pad = delta_bytes*3;
|
||||
|
||||
//additional whitespaces after four bytes
|
||||
pad += (delta_bytes/4);
|
||||
pad++;
|
||||
|
||||
for(int i = 0; i<pad; i++)
|
||||
chars.insert(0, " ");
|
||||
}
|
||||
|
||||
out += chars;
|
||||
cout<<out<<endl;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* pvAccessCPP is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
|
||||
#ifndef HEXDUMP_H_
|
||||
#define HEXDUMP_H_
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define hexDumpEpicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <pv/pvType.h>
|
||||
|
||||
#ifdef hexDumpEpicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# undef hexDumpEpicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
namespace epics {
|
||||
namespace pvAccess {
|
||||
|
||||
/**
|
||||
* Output a buffer in hex format.
|
||||
* @param name name (description) of the message.
|
||||
* @param bs buffer to dump
|
||||
* @param len first bytes (length) to dump.
|
||||
*/
|
||||
epicsShareFunc void hexDump(epics::pvData::String const & name, const epics::pvData::int8 *bs, int len);
|
||||
|
||||
/**
|
||||
* Output a buffer in hex format.
|
||||
* @param[in] name name (description) of the message.
|
||||
* @param[in] bs buffer to dump
|
||||
* @param[in] start dump message using given offset.
|
||||
* @param[in] len first bytes (length) to dump.
|
||||
*/
|
||||
epicsShareFunc void hexDump(epics::pvData::String const & name, const epics::pvData::int8 *bs, int start, int len);
|
||||
|
||||
/**
|
||||
* Output a buffer in hex format.
|
||||
* @param[in] prologue string to prefixed to debug output, can be <code>null</code>
|
||||
* @param[in] name name (description) of the message.
|
||||
* @param[in] bs buffer to dump
|
||||
* @param[in] start dump message using given offset.
|
||||
* @param[in] len first bytes (length) to dump.
|
||||
*/
|
||||
epicsShareFunc void hexDump(epics::pvData::String const & prologue, epics::pvData::String const & name,
|
||||
const epics::pvData::int8 *bs, int start, int len);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HEXDUMP_H_ */
|
||||
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* pvAccessCPP is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
|
||||
#include <pv/byteBuffer.h>
|
||||
#include <pv/epicsException.h>
|
||||
#include <osiSock.h>
|
||||
#include <ellLib.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/inetAddressUtil.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace epics::pvData;
|
||||
|
||||
namespace epics {
|
||||
namespace pvAccess {
|
||||
|
||||
void addDefaultBroadcastAddress(InetAddrVector* v, unsigned short p) {
|
||||
osiSockAddr pNewNode;
|
||||
pNewNode.ia.sin_family = AF_INET;
|
||||
pNewNode.ia.sin_addr.s_addr = htonl(INADDR_BROADCAST);
|
||||
pNewNode.ia.sin_port = htons(p);
|
||||
v->push_back(pNewNode);
|
||||
}
|
||||
|
||||
InetAddrVector* getBroadcastAddresses(SOCKET sock,
|
||||
unsigned short defaultPort) {
|
||||
ELLLIST as;
|
||||
ellInit(&as);
|
||||
osiSockAddr serverAddr;
|
||||
memset(&serverAddr, 0, sizeof(osiSockAddr));
|
||||
InetAddrVector * v = new InetAddrVector;
|
||||
osiSockDiscoverBroadcastAddresses(&as, sock, &serverAddr);
|
||||
for(ELLNODE * n = ellFirst(&as); n != NULL; n = ellNext(n))
|
||||
{
|
||||
osiSockAddrNode * sn = (osiSockAddrNode *)n;
|
||||
sn->addr.ia.sin_port = htons(defaultPort);
|
||||
v->push_back(sn->addr);
|
||||
}
|
||||
ellFree(&as);
|
||||
return v;
|
||||
}
|
||||
|
||||
void encodeAsIPv6Address(ByteBuffer* buffer, const osiSockAddr* address) {
|
||||
// IPv4 compatible IPv6 address
|
||||
// first 80-bit are 0
|
||||
buffer->putLong(0);
|
||||
buffer->putShort(0);
|
||||
// next 16-bits are 1
|
||||
buffer->putShort(0xFFFF);
|
||||
// following IPv4 address in big-endian (network) byte order
|
||||
uint32_t ipv4Addr = ntohl(address->ia.sin_addr.s_addr);
|
||||
buffer->putByte((int8)((ipv4Addr>>24)&0xFF));
|
||||
buffer->putByte((int8)((ipv4Addr>>16)&0xFF));
|
||||
buffer->putByte((int8)((ipv4Addr>>8)&0xFF));
|
||||
buffer->putByte((int8)(ipv4Addr&0xFF));
|
||||
}
|
||||
|
||||
osiSockAddr* intToIPv4Address(int32 addr) {
|
||||
osiSockAddr* ret = new osiSockAddr;
|
||||
ret->ia.sin_family = AF_INET;
|
||||
ret->ia.sin_addr.s_addr = htonl(addr);
|
||||
ret->ia.sin_port = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32 ipv4AddressToInt(const osiSockAddr& addr) {
|
||||
return (int32)ntohl(addr.ia.sin_addr.s_addr);
|
||||
}
|
||||
|
||||
int32 parseInetAddress(const String addr) {
|
||||
int32 retAddr;
|
||||
|
||||
size_t dot = addr.find('.');
|
||||
if(dot==String::npos) THROW_BASE_EXCEPTION("Not an IPv4 address.");
|
||||
int byte = atoi(addr.substr(0, dot).c_str());
|
||||
if(byte<0||byte>255) THROW_BASE_EXCEPTION("Not an IPv4 address.");
|
||||
retAddr = byte;
|
||||
|
||||
int num = dot+1;
|
||||
dot = addr.find('.', num);
|
||||
if(dot==String::npos) THROW_BASE_EXCEPTION("Not an IPv4 address.");
|
||||
byte = atoi(addr.substr(num, dot-num).c_str());
|
||||
if(byte<0||byte>255) THROW_BASE_EXCEPTION("Not an IPv4 address.");
|
||||
retAddr <<= 8;
|
||||
retAddr |= byte;
|
||||
|
||||
num = dot+1;
|
||||
dot = addr.find('.', num);
|
||||
if(dot==String::npos) THROW_BASE_EXCEPTION("Not an IPv4 address.");
|
||||
byte = atoi(addr.substr(num, dot-num).c_str());
|
||||
if(byte<0||byte>255) THROW_BASE_EXCEPTION("Not an IPv4 address.");
|
||||
retAddr <<= 8;
|
||||
retAddr |= byte;
|
||||
|
||||
num = dot+1;
|
||||
byte = atoi(addr.substr(num).c_str());
|
||||
if(byte<0||byte>255) THROW_BASE_EXCEPTION("Not an IPv4 address.");
|
||||
retAddr <<= 8;
|
||||
retAddr |= byte;
|
||||
|
||||
return htonl(retAddr);
|
||||
}
|
||||
|
||||
InetAddrVector* getSocketAddressList(String list, int defaultPort,
|
||||
const InetAddrVector* appendList) {
|
||||
InetAddrVector* iav = new InetAddrVector();
|
||||
|
||||
// parse string
|
||||
size_t subStart = 0;
|
||||
size_t subEnd;
|
||||
while((subEnd = list.find(' ', subStart))!=String::npos) {
|
||||
String address = list.substr(subStart, (subEnd-subStart));
|
||||
osiSockAddr addr;
|
||||
aToIPAddr(address.c_str(), defaultPort, &addr.ia);
|
||||
iav->push_back(addr);
|
||||
subStart = list.find_first_not_of(" \t\r\n\v", subEnd);
|
||||
}
|
||||
|
||||
if(subStart!=String::npos&&list.length()>0) {
|
||||
osiSockAddr addr;
|
||||
aToIPAddr(list.substr(subStart).c_str(), defaultPort, &addr.ia);
|
||||
iav->push_back(addr);
|
||||
}
|
||||
|
||||
if(appendList!=NULL) {
|
||||
for(size_t i = 0; i<appendList->size(); i++)
|
||||
iav->push_back((*appendList)[i]);
|
||||
}
|
||||
return iav;
|
||||
}
|
||||
|
||||
const String inetAddressToString(const osiSockAddr &addr,
|
||||
bool displayPort, bool displayHex) {
|
||||
stringstream saddr;
|
||||
|
||||
int ipa = ntohl(addr.ia.sin_addr.s_addr);
|
||||
|
||||
saddr<<((int)(ipa>>24)&0xFF)<<'.';
|
||||
saddr<<((int)(ipa>>16)&0xFF)<<'.';
|
||||
saddr<<((int)(ipa>>8)&0xFF)<<'.';
|
||||
saddr<<((int)ipa&0xFF);
|
||||
if(displayPort) saddr<<":"<<ntohs(addr.ia.sin_port);
|
||||
if(displayHex) saddr<<" ("<<hex<<ntohl(addr.ia.sin_addr.s_addr)
|
||||
<<")";
|
||||
|
||||
return saddr.str();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* pvAccessCPP is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
|
||||
#ifndef INETADDRESSUTIL_H_
|
||||
#define INETADDRESSUTIL_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define inetAddressUtilExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <pv/pvType.h>
|
||||
#include <pv/byteBuffer.h>
|
||||
|
||||
#include <osiSock.h>
|
||||
|
||||
#ifdef inetAddressUtilExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# undef inetAddressUtilExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
|
||||
// TODO implement using smart pointers
|
||||
|
||||
namespace epics {
|
||||
namespace pvAccess {
|
||||
|
||||
typedef std::vector<osiSockAddr> InetAddrVector;
|
||||
|
||||
/**
|
||||
* Returns a vector containing all the IPv4 broadcast addresses on this machine.
|
||||
* IPv6 doesn't have a local broadcast address.
|
||||
* Conversion of the defaultPort to network byte order performed by
|
||||
* the function.
|
||||
*/
|
||||
epicsShareFunc InetAddrVector* getBroadcastAddresses(SOCKET sock, unsigned short defaultPort);
|
||||
|
||||
/**
|
||||
* Encode IPv4 address as IPv6 address.
|
||||
* @param buffer byte-buffer where to put encoded data.
|
||||
* @param address address to encode.
|
||||
*/
|
||||
epicsShareFunc void encodeAsIPv6Address(epics::pvData::ByteBuffer* buffer, const osiSockAddr* address);
|
||||
|
||||
/**
|
||||
* Convert an integer into an IPv4 INET address.
|
||||
* @param addr integer representation of a given address.
|
||||
* @return IPv4 INET address.
|
||||
*/
|
||||
epicsShareFunc osiSockAddr* intToIPv4Address(epics::pvData::int32 addr);
|
||||
|
||||
/**
|
||||
* Convert an IPv4 INET address to an integer.
|
||||
* @param addr IPv4 INET address.
|
||||
* @return integer representation of a given address.
|
||||
*/
|
||||
epicsShareFunc epics::pvData::int32 ipv4AddressToInt(const osiSockAddr& addr);
|
||||
|
||||
/**
|
||||
* Parse space delimited addresss[:port] string and return array of <code>InetSocketAddress</code>.
|
||||
* @param list space delimited addresss[:port] string.
|
||||
* @param defaultPort port take if not specified.
|
||||
* @param appendList list to be appended.
|
||||
* @return array of <code>InetSocketAddress</code>.
|
||||
*/
|
||||
epicsShareFunc InetAddrVector* getSocketAddressList(epics::pvData::String list, int defaultPort,
|
||||
const InetAddrVector* appendList = NULL);
|
||||
|
||||
epicsShareFunc const epics::pvData::String inetAddressToString(const osiSockAddr &addr,
|
||||
bool displayPort = true, bool displayHex = false);
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
// comparators for osiSockAddr
|
||||
|
||||
struct comp_osiSockAddrPtr {
|
||||
bool operator()(osiSockAddr const *a, osiSockAddr const *b) const {
|
||||
if(a->sa.sa_family<b->sa.sa_family) return true;
|
||||
if((a->sa.sa_family==b->sa.sa_family)&&(a->ia.sin_addr.s_addr
|
||||
<b->ia.sin_addr.s_addr)) return true;
|
||||
if((a->sa.sa_family==b->sa.sa_family)&&(a->ia.sin_addr.s_addr
|
||||
==b->ia.sin_addr.s_addr)&&(a->ia.sin_port
|
||||
<b->ia.sin_port)) return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct comp_osiSock_lt {
|
||||
bool operator()(const osiSockAddr& a, const osiSockAddr& b) const {
|
||||
if(a.sa.sa_family<b.sa.sa_family) return true;
|
||||
if((a.sa.sa_family==b.sa.sa_family)&&(a.ia.sin_addr.s_addr
|
||||
<b.ia.sin_addr.s_addr)) return true;
|
||||
if((a.sa.sa_family==b.sa.sa_family)&&(a.ia.sin_addr.s_addr
|
||||
==b.ia.sin_addr.s_addr)&&(a.ia.sin_port
|
||||
<b.ia.sin_port)) return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
//TODO if unordered map is used instead of map we can use sockAddrAreIdentical routine from osiSock.h
|
||||
struct comp_osiSockAddr {
|
||||
bool operator()(osiSockAddr const a, osiSockAddr const b) const {
|
||||
if(a.sa.sa_family<b.sa.sa_family) return true;
|
||||
if((a.sa.sa_family==b.sa.sa_family)&&(a.ia.sin_addr.s_addr
|
||||
<b.ia.sin_addr.s_addr)) return true;
|
||||
if((a.sa.sa_family==b.sa.sa_family)&&(a.ia.sin_addr.s_addr
|
||||
==b.ia.sin_addr.s_addr)&&(a.ia.sin_port
|
||||
<b.ia.sin_port)) return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* INETADDRESSUTIL_H_ */
|
||||
@@ -0,0 +1,166 @@
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* pvAccessCPP is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
|
||||
#include <pv/introspectionRegistry.h>
|
||||
#include <pv/convert.h>
|
||||
#include <pv/serializationHelper.h>
|
||||
|
||||
using namespace epics::pvData;
|
||||
using namespace std;
|
||||
using std::tr1::static_pointer_cast;
|
||||
|
||||
namespace epics {
|
||||
namespace pvAccess {
|
||||
|
||||
const int8 IntrospectionRegistry::NULL_TYPE_CODE = (int8)-1;
|
||||
const int8 IntrospectionRegistry::ONLY_ID_TYPE_CODE = (int8)-2;
|
||||
const int8 IntrospectionRegistry::FULL_WITH_ID_TYPE_CODE = (int8)-3;
|
||||
FieldCreatePtr IntrospectionRegistry::_fieldCreate(getFieldCreate());
|
||||
|
||||
IntrospectionRegistry::IntrospectionRegistry()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
IntrospectionRegistry::~IntrospectionRegistry()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void IntrospectionRegistry::reset()
|
||||
{
|
||||
_pointer = 1;
|
||||
_registry.clear();
|
||||
}
|
||||
|
||||
FieldConstPtr IntrospectionRegistry::getIntrospectionInterface(const int16 id)
|
||||
{
|
||||
registryMap_t::iterator registryIter = _registry.find(id);
|
||||
if(registryIter == _registry.end())
|
||||
{
|
||||
return FieldConstPtr();
|
||||
}
|
||||
return registryIter->second;
|
||||
}
|
||||
|
||||
void IntrospectionRegistry::registerIntrospectionInterface(const int16 id, FieldConstPtr const & field)
|
||||
{
|
||||
_registry[id] = field;
|
||||
}
|
||||
|
||||
int16 IntrospectionRegistry::registerIntrospectionInterface(FieldConstPtr const & field, bool& existing)
|
||||
{
|
||||
int16 key;
|
||||
// TODO this is slow
|
||||
if(registryContainsValue(field, key))
|
||||
{
|
||||
existing = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
existing = false;
|
||||
key = _pointer++;
|
||||
_registry[key] = field;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
void IntrospectionRegistry::printKeysAndValues(string name)
|
||||
{
|
||||
string buffer;
|
||||
cout << "############## print of all key/values of " << name.c_str() << " registry : ###################" << endl;
|
||||
for(registryMap_t::iterator registryIter = _registry.begin(); registryIter != _registry.end(); registryIter++)
|
||||
{
|
||||
buffer.erase();
|
||||
cout << "\t" << "Key: "<< registryIter->first << endl;
|
||||
cout << "\t" << "Value: " << registryIter->second << endl;
|
||||
|
||||
cout << "\t" << "References: " << buffer.c_str() << endl;
|
||||
buffer.erase();
|
||||
registryIter->second->toString(&buffer);
|
||||
cout << "\t" << "Value toString: " << buffer.c_str() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO slow !!!!
|
||||
bool IntrospectionRegistry::registryContainsValue(FieldConstPtr const & field, int16& key)
|
||||
{
|
||||
for(registryMap_t::reverse_iterator registryRIter = _registry.rbegin(); registryRIter != _registry.rend(); registryRIter++)
|
||||
{
|
||||
if(*(field.get()) == *(registryRIter->second))
|
||||
{
|
||||
key = registryRIter->first;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void IntrospectionRegistry::serialize(FieldConstPtr const & field, ByteBuffer* buffer, SerializableControl* control)
|
||||
{
|
||||
if (field.get() == NULL)
|
||||
{
|
||||
SerializationHelper::serializeNullField(buffer, control);
|
||||
}
|
||||
else
|
||||
{
|
||||
// do not cache scalars, scalarArrays
|
||||
// ... and (array of) variant unions - not worth the complex condition,
|
||||
// unless bool Field.cache() would exist
|
||||
if (field->getType() != scalar &&
|
||||
field->getType() != scalarArray)
|
||||
{
|
||||
bool existing;
|
||||
const int16 key = registerIntrospectionInterface(field, existing);
|
||||
if (existing) {
|
||||
control->ensureBuffer(3);
|
||||
buffer->putByte(ONLY_ID_TYPE_CODE);
|
||||
buffer->putShort(key);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
control->ensureBuffer(3);
|
||||
buffer->putByte(FULL_WITH_ID_TYPE_CODE); // could also be a mask
|
||||
buffer->putShort(key);
|
||||
}
|
||||
}
|
||||
|
||||
field->serialize(buffer, control);
|
||||
}
|
||||
}
|
||||
|
||||
FieldConstPtr IntrospectionRegistry::deserialize(ByteBuffer* buffer, DeserializableControl* control)
|
||||
{
|
||||
control->ensureData(1);
|
||||
size_t pos = buffer->getPosition();
|
||||
const int8 typeCode = buffer->getByte();
|
||||
|
||||
if (typeCode == NULL_TYPE_CODE)
|
||||
{
|
||||
return FieldConstPtr();
|
||||
}
|
||||
else if (typeCode == ONLY_ID_TYPE_CODE)
|
||||
{
|
||||
control->ensureData(sizeof(int16)/sizeof(int8));
|
||||
return getIntrospectionInterface(buffer->getShort());
|
||||
}
|
||||
// could also be a mask
|
||||
if(typeCode == IntrospectionRegistry::FULL_WITH_ID_TYPE_CODE)
|
||||
{
|
||||
control->ensureData(sizeof(int16)/sizeof(int8));
|
||||
const short key = buffer->getShort();
|
||||
FieldConstPtr field = _fieldCreate->deserialize(buffer, control);
|
||||
registerIntrospectionInterface(key, field);
|
||||
return field;
|
||||
}
|
||||
|
||||
// return typeCode back
|
||||
buffer->setPosition(pos);
|
||||
return _fieldCreate->deserialize(buffer, control);
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* pvAccessCPP is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
|
||||
#ifndef INTROSPECTIONREGISTRY_H
|
||||
#define INTROSPECTIONREGISTRY_H
|
||||
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define introspectionRegistryEpicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <pv/lock.h>
|
||||
#include <pv/pvIntrospect.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/byteBuffer.h>
|
||||
#include <pv/serialize.h>
|
||||
#include <pv/serializeHelper.h>
|
||||
#include <pv/status.h>
|
||||
#include <pv/standardField.h>
|
||||
|
||||
#ifdef introspectionRegistryEpicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# undef introspectionRegistryEpicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
// TODO check for memory leaks
|
||||
|
||||
namespace epics {
|
||||
namespace pvAccess {
|
||||
|
||||
typedef std::map<const short,epics::pvData::FieldConstPtr> registryMap_t;
|
||||
|
||||
|
||||
/**
|
||||
* PVData Structure registry.
|
||||
* Registry is used to cache introspection interfaces to minimize network traffic.
|
||||
* @author gjansa
|
||||
*/
|
||||
class IntrospectionRegistry : public epics::pvData::NoDefaultMethods {
|
||||
public:
|
||||
IntrospectionRegistry();
|
||||
virtual ~IntrospectionRegistry();
|
||||
|
||||
void printKeysAndValues(std::string name);
|
||||
/**
|
||||
* Resets registry, i.e. must be done when transport is changed (server restarted).
|
||||
*/
|
||||
void reset();
|
||||
/**
|
||||
* Get introspection interface for given ID.
|
||||
*
|
||||
* @param id id of the introspection interface to get
|
||||
*
|
||||
* @return <code>Field</code> instance for given ID.
|
||||
*/
|
||||
epics::pvData::FieldConstPtr getIntrospectionInterface(const epics::pvData::int16 id);
|
||||
|
||||
/**
|
||||
* Registers introspection interface with given ID. Always INCOMING.
|
||||
*
|
||||
* @param id id of the introspection interface to register
|
||||
* @param field introspection interface to register
|
||||
*/
|
||||
void registerIntrospectionInterface(const epics::pvData::int16 id, epics::pvData::FieldConstPtr const & field);
|
||||
|
||||
/**
|
||||
* Registers introspection interface and get it's ID. Always OUTGOING.
|
||||
* If it is already registered only preassigned ID is returned.
|
||||
*
|
||||
* TODO !!!!!!this can get very slow in large maps. We need to change this !!!!!!
|
||||
*
|
||||
* @param field introspection interface to register
|
||||
*
|
||||
* @return id of given introspection interface
|
||||
*/
|
||||
epics::pvData::int16 registerIntrospectionInterface(epics::pvData::FieldConstPtr const & field, bool& existing);
|
||||
|
||||
/**
|
||||
* Serializes introspection interface
|
||||
*
|
||||
* @param field
|
||||
* @param buffer
|
||||
* @param control
|
||||
*/
|
||||
void serialize(epics::pvData::FieldConstPtr const & field, epics::pvData::ByteBuffer* buffer, epics::pvData::SerializableControl* control);
|
||||
|
||||
/**
|
||||
* Deserializes introspection interface
|
||||
*
|
||||
* TODO
|
||||
*
|
||||
* @param buffer
|
||||
* @param control
|
||||
*
|
||||
* @return <code>Field</code> deserialized from the buffer.
|
||||
*/
|
||||
epics::pvData::FieldConstPtr deserialize(epics::pvData::ByteBuffer* buffer, epics::pvData::DeserializableControl* control);
|
||||
|
||||
/**
|
||||
* Null type.
|
||||
*/
|
||||
const static epics::pvData::int8 NULL_TYPE_CODE;
|
||||
|
||||
/**
|
||||
* Serialization contains only an ID (that was assigned by one of the previous <code>FULL_WITH_ID</code> descriptions).
|
||||
*/
|
||||
const static epics::pvData::int8 ONLY_ID_TYPE_CODE;
|
||||
|
||||
/**
|
||||
* Serialization contains an ID (that can be used later, if cached) and full interface description.
|
||||
*/
|
||||
const static epics::pvData::int8 FULL_WITH_ID_TYPE_CODE;
|
||||
|
||||
private:
|
||||
registryMap_t _registry;
|
||||
epics::pvData::int16 _pointer;
|
||||
|
||||
/**
|
||||
* Field factory.
|
||||
*/
|
||||
static epics::pvData::FieldCreatePtr _fieldCreate;
|
||||
|
||||
bool registryContainsValue(epics::pvData::FieldConstPtr const & field, epics::pvData::int16& key);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* INTROSPECTIONREGISTRY_H */
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* pvAccessCPP is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
|
||||
#ifndef LIKELY_H_
|
||||
#define LIKELY_H_
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ >= 3
|
||||
#define likely(x) __builtin_expect (x, 1)
|
||||
#define unlikely(x) __builtin_expect (x, 0)
|
||||
#else
|
||||
#define likely(x) (x)
|
||||
#define unlikely(x) (x)
|
||||
#endif
|
||||
|
||||
#endif /* LIKELY_H_ */
|
||||
@@ -0,0 +1,116 @@
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* pvAccessCPP is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <time.h>
|
||||
#include <cstring>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <pv/noDefaultMethods.h>
|
||||
#include <pv/lock.h>
|
||||
#include <pv/pvType.h>
|
||||
|
||||
#include <epicsExit.h>
|
||||
#include <errlog.h>
|
||||
|
||||
#include <epicsTime.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/logger.h>
|
||||
|
||||
using namespace epics::pvData;
|
||||
using std::ofstream;
|
||||
using std::ios;
|
||||
using std::endl;
|
||||
|
||||
namespace epics {
|
||||
namespace pvAccess {
|
||||
|
||||
#define TIMETEXTLEN 32
|
||||
|
||||
static pvAccessLogLevel g_pvAccessLogLevel = logLevelInfo;
|
||||
|
||||
void pvAccessLog(pvAccessLogLevel level, const char* format, ...)
|
||||
{
|
||||
// TODO lock
|
||||
if (level >= g_pvAccessLogLevel)
|
||||
{
|
||||
char timeText[TIMETEXTLEN];
|
||||
epicsTimeStamp tsNow;
|
||||
|
||||
epicsTimeGetCurrent(&tsNow);
|
||||
epicsTimeToStrftime(timeText, TIMETEXTLEN, "%Y-%m-%dT%H:%M:%S.%03f", &tsNow);
|
||||
|
||||
printf("%s ", timeText);
|
||||
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
vprintf(format, arg);
|
||||
va_end(arg);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void pvAccessSetLogLevel(pvAccessLogLevel level)
|
||||
{
|
||||
g_pvAccessLogLevel = level;
|
||||
}
|
||||
|
||||
bool pvAccessIsLoggable(pvAccessLogLevel level)
|
||||
{
|
||||
return level >= g_pvAccessLogLevel;
|
||||
}
|
||||
|
||||
class FileLogger : public NoDefaultMethods {
|
||||
public:
|
||||
FileLogger(String const & name) {
|
||||
logFile.open(name.data(), ios::app);
|
||||
}
|
||||
|
||||
~FileLogger() {
|
||||
logFile.close();
|
||||
}
|
||||
|
||||
void logMessage(const char* message) {
|
||||
time_t rawtime;
|
||||
time(&rawtime);
|
||||
char* timeStr = ctime(&rawtime);
|
||||
timeStr[strlen(timeStr)-1]='\0'; // remove newline
|
||||
|
||||
logFile<<timeStr<<"\t"<<message; // the newline is added by the caller
|
||||
}
|
||||
private:
|
||||
ofstream logFile;
|
||||
|
||||
};
|
||||
|
||||
static FileLogger* fileLogger = NULL;
|
||||
|
||||
static void errLogFileListener(void* /*pPrivate*/, const char *message) {
|
||||
fileLogger->logMessage(message);
|
||||
}
|
||||
|
||||
static void exitFileLoggerHandler(void* /*pPrivate*/) {
|
||||
errlogFlush();
|
||||
delete fileLogger;
|
||||
}
|
||||
|
||||
void createFileLogger(String const & fname) {
|
||||
static Mutex mutex;
|
||||
Lock xx(mutex);
|
||||
|
||||
if(fileLogger==NULL) {
|
||||
fileLogger = new FileLogger(fname);
|
||||
errlogInit(2048);
|
||||
errlogAddListener(errLogFileListener, NULL);
|
||||
epicsAtExit(exitFileLoggerHandler, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* pvAccessCPP is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
|
||||
#ifndef LOGGER_H_
|
||||
#define LOGGER_H_
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define loggerEpicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <pv/pvType.h>
|
||||
#include <errlog.h>
|
||||
|
||||
#ifdef loggerEpicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
#undef loggerEpicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
namespace epics {
|
||||
namespace pvAccess {
|
||||
|
||||
typedef enum { logLevelAll = 0, logLevelTrace, logLevelDebug, logLevelInfo,
|
||||
logLevelWarn, logLevelError, logLevelFatal, logLevelOff } pvAccessLogLevel;
|
||||
/*
|
||||
ALL
|
||||
The ALL has the lowest possible rank and is intended to turn on all logging.
|
||||
TRACE
|
||||
The TRACE Level designates finer-grained informational events than the DEBUG
|
||||
DEBUG
|
||||
The DEBUG Level designates fine-grained informational events that are most useful to debug an application.
|
||||
INFO
|
||||
The INFO level designates informational messages that highlight the progress of the application at coarse-grained level.
|
||||
WARN
|
||||
The WARN level designates potentially harmful situations.
|
||||
ERROR
|
||||
The ERROR level designates error events that might still allow the application to continue running.
|
||||
FATAL
|
||||
The FATAL level designates very severe error events that will presumably lead the application to abort.
|
||||
OFF
|
||||
The OFF has the highest possible rank and is intended to turn off logging.
|
||||
*/
|
||||
|
||||
|
||||
epicsShareExtern void pvAccessLog(pvAccessLogLevel level, const char* format, ...);
|
||||
epicsShareExtern void pvAccessSetLogLevel(pvAccessLogLevel level);
|
||||
epicsShareExtern bool pvAccessIsLoggable(pvAccessLogLevel level);
|
||||
|
||||
#if defined (__GNUC__) && __GNUC__ < 3
|
||||
#define LOG(level, format, ARGS...) pvAccessLog(level, format, ##ARGS)
|
||||
#else
|
||||
#define LOG(level, format, ...) pvAccessLog(level, format, ##__VA_ARGS__)
|
||||
#endif
|
||||
#define SET_LOG_LEVEL(level) pvAccessSetLogLevel(level)
|
||||
#define IS_LOGGABLE(level) pvAccessIsLoggable(level)
|
||||
|
||||
// EPICS errlog
|
||||
//#define LOG errlogSevPrintf
|
||||
//#define SET_LOG_LEVEL(level) errlogSetSevToLog(level)
|
||||
|
||||
// none
|
||||
//#define LOG(level, fmt, ...)
|
||||
//#define SET_LOG_LEVEL(level)
|
||||
|
||||
/**
|
||||
* Create a logger that will write to file indicated by the <tt>fname</tt>.
|
||||
* After creation you are free to use standard EPICSv3 functions from
|
||||
* <tt>errlog.h</tt>.
|
||||
*
|
||||
* @param[in] fname The file to write to. If the file exists, it
|
||||
* is opened for append.
|
||||
*/
|
||||
epicsShareExtern void createFileLogger( epics::pvData::String const & fname );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* LOGGER_H_ */
|
||||
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* pvAccessCPP is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
|
||||
#ifndef NAMEDLOCKPATTERN_H
|
||||
#define NAMEDLOCKPATTERN_H
|
||||
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define namedLockPatternEpicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <pv/lock.h>
|
||||
#include <pv/pvType.h>
|
||||
#include <pv/sharedPtr.h>
|
||||
|
||||
#ifdef namedLockPatternEpicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# undef namedLockPatternEpicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <pv/referenceCountingLock.h>
|
||||
|
||||
// TODO implement using smart pointers
|
||||
|
||||
namespace epics { namespace pvAccess {
|
||||
|
||||
/**
|
||||
* NamedLockPattern
|
||||
*/
|
||||
template <class Key, class Compare = std::less<Key> >
|
||||
class NamedLockPattern
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
NamedLockPattern() {};
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~NamedLockPattern() {};
|
||||
/**
|
||||
* Acquire synchronization lock for named object.
|
||||
*
|
||||
* NOTE: Argument msecs is currently not supported due to
|
||||
* Darwin OS not supporting pthread_mutex_timedlock. May be changed in the future.
|
||||
*
|
||||
* @param name name of the object whose lock to acquire.
|
||||
* @param msec the number of milleseconds to wait.
|
||||
* An argument less than or equal to zero means not to wait at all.
|
||||
* @return <code>true</code> if acquired, <code>false</code> othwerwise.
|
||||
* NOTE: currently this routine always returns true. Look above for explanation.
|
||||
*/
|
||||
bool acquireSynchronizationObject(const Key& name, const epics::pvData::int64 msec);
|
||||
/**
|
||||
* Release synchronization lock for named object.
|
||||
* @param name name of the object whose lock to release.
|
||||
*/
|
||||
void releaseSynchronizationObject(const Key& name);
|
||||
private:
|
||||
epics::pvData::Mutex _mutex;
|
||||
std::map<const Key,ReferenceCountingLock::shared_pointer,Compare> _namedLocks;
|
||||
typename std::map<const Key,ReferenceCountingLock::shared_pointer,Compare>::iterator _namedLocksIter;
|
||||
|
||||
/**
|
||||
* Release synchronization lock for named object.
|
||||
* @param name name of the object whose lock to release.
|
||||
* @param release set to <code>false</code> if there is no need to call release
|
||||
* on synchronization lock.
|
||||
*/
|
||||
void releaseSynchronizationObject(const Key& name,const bool release);
|
||||
};
|
||||
|
||||
template <class Key, class Compare>
|
||||
bool NamedLockPattern<Key,Compare>::acquireSynchronizationObject(const Key& name, const epics::pvData::int64 msec)
|
||||
{
|
||||
ReferenceCountingLock::shared_pointer lock;
|
||||
{ //due to guard
|
||||
epics::pvData::Lock guard(_mutex);
|
||||
|
||||
_namedLocksIter = _namedLocks.find(name);
|
||||
// get synchronization object
|
||||
|
||||
// none is found, create and return new one
|
||||
// increment references
|
||||
if(_namedLocksIter == _namedLocks.end())
|
||||
{
|
||||
lock.reset(new ReferenceCountingLock());
|
||||
_namedLocks[name] = lock;
|
||||
}
|
||||
else
|
||||
{
|
||||
lock = _namedLocksIter->second;
|
||||
lock->increment();
|
||||
}
|
||||
} // end of guarded area
|
||||
|
||||
bool success = lock->acquire(msec);
|
||||
|
||||
if(!success)
|
||||
{
|
||||
releaseSynchronizationObject(name, false);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
template <class Key, class Compare>
|
||||
void NamedLockPattern<Key,Compare>::releaseSynchronizationObject(const Key& name)
|
||||
{
|
||||
releaseSynchronizationObject(name, true);
|
||||
}
|
||||
|
||||
template <class Key, class Compare>
|
||||
void NamedLockPattern<Key,Compare>::releaseSynchronizationObject(const Key& name,const bool release)
|
||||
{
|
||||
epics::pvData::Lock guard(_mutex);
|
||||
ReferenceCountingLock::shared_pointer lock;
|
||||
_namedLocksIter = _namedLocks.find(name);
|
||||
|
||||
// release lock
|
||||
if (_namedLocksIter != _namedLocks.end())
|
||||
{
|
||||
lock = _namedLocksIter->second;
|
||||
|
||||
// release the lock
|
||||
if (release)
|
||||
{
|
||||
lock->release();
|
||||
}
|
||||
|
||||
// if there only one current lock exists
|
||||
// remove it from the map
|
||||
if (lock->decrement() <= 0)
|
||||
{
|
||||
_namedLocks.erase(_namedLocksIter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class Key, class Compare>
|
||||
class NamedLock : private epics::pvData::NoDefaultMethods
|
||||
{
|
||||
public:
|
||||
NamedLock(NamedLockPattern<Key,Compare>* namedLockPattern): _namedLockPattern(namedLockPattern) {}
|
||||
bool acquireSynchronizationObject(const Key& name, const epics::pvData::int64 msec) {_name = name; return _namedLockPattern->acquireSynchronizationObject(name,msec);}
|
||||
~NamedLock(){_namedLockPattern->releaseSynchronizationObject(_name);}
|
||||
private:
|
||||
Key _name;
|
||||
NamedLockPattern<Key,Compare>* _namedLockPattern;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* NAMEDLOCKPATTERN_H */
|
||||
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* pvAccessCPP is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
|
||||
#include <pv/referenceCountingLock.h>
|
||||
|
||||
namespace epics {
|
||||
namespace pvAccess {
|
||||
|
||||
using namespace epics::pvData;
|
||||
|
||||
ReferenceCountingLock::ReferenceCountingLock(): _references(1)
|
||||
{
|
||||
/* pthread_mutexattr_t mutexAttribute;
|
||||
int32 retval = pthread_mutexattr_init(&mutexAttribute);
|
||||
if(retval != 0)
|
||||
{
|
||||
//string errMsg = "Error: pthread_mutexattr_init failed: " + string(strerror(retval));
|
||||
assert(false);
|
||||
}
|
||||
retval = pthread_mutexattr_settype(&mutexAttribute, PTHREAD_MUTEX_RECURSIVE);
|
||||
if(retval == 0)
|
||||
{
|
||||
retval = pthread_mutex_init(_mutex, &mutexAttribute);
|
||||
if(retval != 0)
|
||||
{
|
||||
//string errMsg = "Error: pthread_mutex_init failed: " + string(strerror(retval));
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//string errMsg = "Error: pthread_mutexattr_settype failed: " + string(strerror(retval));
|
||||
assert(false);
|
||||
}
|
||||
|
||||
pthread_mutexattr_destroy(&mutexAttribute);*/
|
||||
}
|
||||
|
||||
ReferenceCountingLock::~ReferenceCountingLock()
|
||||
{
|
||||
// pthread_mutex_destroy(_mutex);
|
||||
}
|
||||
|
||||
bool ReferenceCountingLock::acquire(int64 /*msecs*/)
|
||||
{
|
||||
_mutex.lock();
|
||||
return true;
|
||||
/* struct timespec deltatime;
|
||||
if(msecs > 0)
|
||||
{
|
||||
deltatime.tv_sec = msecs / 1000;
|
||||
deltatime.tv_nsec = (msecs % 1000) * 1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
deltatime.tv_sec = 0;
|
||||
deltatime.tv_nsec = 0;
|
||||
}
|
||||
|
||||
int32 retval = pthread_mutex_timedlock(_mutex, &deltatime);
|
||||
if(retval == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
*/
|
||||
}
|
||||
|
||||
void ReferenceCountingLock::release()
|
||||
{
|
||||
_mutex.unlock();
|
||||
/* int retval = pthread_mutex_unlock(_mutex);
|
||||
if(retval != 0)
|
||||
{
|
||||
//string errMsg = "Error: pthread_mutex_unlock failed: " + string(strerror(retval));
|
||||
//TODO do something?
|
||||
}*/
|
||||
}
|
||||
|
||||
// TODO use atomic primitive impl.
|
||||
int ReferenceCountingLock::increment()
|
||||
{
|
||||
Lock guard(_countMutex);
|
||||
++_references;
|
||||
return _references;
|
||||
}
|
||||
|
||||
int ReferenceCountingLock::decrement()
|
||||
{
|
||||
Lock guard(_countMutex);
|
||||
--_references;
|
||||
return _references;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* pvAccessCPP is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
|
||||
#ifndef REFERENCECOUNTINGLOCK_H
|
||||
#define REFERENCECOUNTINGLOCK_H
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define referenceCountingLockEpicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <pv/lock.h>
|
||||
#include <pv/pvType.h>
|
||||
#include <pv/sharedPtr.h>
|
||||
|
||||
#ifdef referenceCountingLockEpicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# undef referenceCountingLockEpicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
namespace epics {
|
||||
namespace pvAccess {
|
||||
|
||||
/**
|
||||
* Reference counting mutex implementation w/ deadlock detection.
|
||||
* Synchronization helper class used (intended for use) for activation/deactivation synchronization.
|
||||
* This class enforces <code>attempt</code> method of acquiring the locks to prevent deadlocks.
|
||||
* Class also offers reference counting.
|
||||
* (NOTE: automatic lock counting was not implemented due to imperfect usage.)
|
||||
*
|
||||
*/
|
||||
class ReferenceCountingLock
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ReferenceCountingLock);
|
||||
|
||||
/**
|
||||
* Constructor of <code>ReferenceCountingLock</code>.
|
||||
* After construction lock is free and reference count equals <code>1</code>.
|
||||
*/
|
||||
ReferenceCountingLock();
|
||||
/**
|
||||
* Destructor of <code>ReferenceCountingLock</code>.
|
||||
*/
|
||||
virtual ~ReferenceCountingLock();
|
||||
/**
|
||||
* Attempt to acquire lock.
|
||||
*
|
||||
* NOTE: Argument msecs is currently not supported due to
|
||||
* Darwin OS not supporting pthread_mutex_timedlock. May be changed in the future.
|
||||
*
|
||||
* @param msecs the number of milleseconds to wait.
|
||||
* An argument less than or equal to zero means not to wait at all.
|
||||
*
|
||||
* @return <code>true</code> if acquired, <code>false</code> otherwise.
|
||||
* NOTE: currently this routine always returns true. Look above for explanation.
|
||||
*
|
||||
*/
|
||||
bool acquire(epics::pvData::int64 msecs);
|
||||
/**
|
||||
* Release previously acquired lock.
|
||||
*/
|
||||
void release();
|
||||
/**
|
||||
* Increment number of references.
|
||||
*
|
||||
* @return number of references.
|
||||
*/
|
||||
int increment();
|
||||
/**
|
||||
* Decrement number of references.
|
||||
*
|
||||
* @return number of references.
|
||||
*/
|
||||
int decrement();
|
||||
private:
|
||||
int _references;
|
||||
epics::pvData::Mutex _mutex;
|
||||
epics::pvData::Mutex _countMutex;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* REFERENCECOUNTINGLOCK_H */
|
||||
Reference in New Issue
Block a user