Rename pvAccessApp to src, adjust Makefiles

This commit is contained in:
Andrew Johnson
2014-03-28 11:53:02 -05:00
parent c6a99a64cd
commit a886984258
88 changed files with 43 additions and 43 deletions
+19
View File
@@ -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
+397
View File
@@ -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;
}
}}
+228
View File
@@ -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 */
+106
View File
@@ -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;
}
}
}
+58
View File
@@ -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_ */
+160
View File
@@ -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();
}
}
}
+123
View File
@@ -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_ */
+166
View File
@@ -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);
}
}}
+134
View File
@@ -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 */
+18
View File
@@ -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_ */
+116
View File
@@ -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);
}
}
}
}
+83
View File
@@ -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_ */
+161
View File
@@ -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 */
+99
View File
@@ -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;
}
}}
+87
View File
@@ -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 */