Merge with additions from Gasper Jansa
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
QtC-pvAccess.creator.user
|
||||
|
||||
syntax: glob
|
||||
O.Common
|
||||
O.linux-x86
|
||||
O.*
|
||||
.DS_Store
|
||||
|
||||
syntax: regexp
|
||||
^bin
|
||||
^include
|
||||
|
||||
^lib
|
||||
|
||||
@@ -19,12 +19,16 @@ INC += inetAddressUtil.h
|
||||
INC += logger.h
|
||||
INC += introspectionRegistry.h
|
||||
INC += transportRegistry.h
|
||||
INC += namedLockPattern.h
|
||||
INC += referenceCountingLock.h
|
||||
LIBSRCS += hexDump.cpp
|
||||
LIBSRCS += wildcharMatcher.cpp
|
||||
LIBSRCS += inetAddressUtil.cpp
|
||||
LIBSRCS += logger.cpp
|
||||
LIBSRCS += introspectionRegistry.cpp
|
||||
LIBSRCS += transportRegistry.cpp
|
||||
LIBSRCS += namedLockPattern.cpp
|
||||
LIBSRCS += referenceCountingLock.cpp
|
||||
|
||||
|
||||
SRC_DIRS += $(PVACCESS)/client
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace epics {
|
||||
const int16 CA_DEFAULT_PRIORITY = 0;
|
||||
|
||||
/** Unreasonable channel name length. */
|
||||
const int32 UNREASONABLE_CHANNEL_NAME_LENGTH = 500;
|
||||
const uint32 UNREASONABLE_CHANNEL_NAME_LENGTH = 500;
|
||||
|
||||
/** Invalid data type. */
|
||||
const int16 INVALID_DATA_TYPE = (int16)0xFFFF;
|
||||
|
||||
@@ -583,6 +583,17 @@ namespace epics { namespace pvAccess {
|
||||
virtual ChannelArray* createChannelArray(
|
||||
ChannelArrayRequester *channelArrayRequester,
|
||||
epics::pvData::PVStructure *pvRequest) = 0;
|
||||
|
||||
/**
|
||||
* Prints detailed information about the context to the standard output stream.
|
||||
*/
|
||||
virtual void printInfo() = 0;
|
||||
|
||||
/**
|
||||
* Prints detailed information about the context to the specified output stream.
|
||||
* @param out the output stream.
|
||||
*/
|
||||
virtual void printInfo(epics::pvData::StringBuilder out) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ bool BeaconHandler::updateBeacon(int8 remoteTransportRevision, int64 timestamp,
|
||||
|
||||
void BeaconHandler::beaconArrivalNotify()
|
||||
{
|
||||
int32 size;
|
||||
int32 size = 0;
|
||||
//TODO TCP name must be get from somewhere not hardcoded
|
||||
//TODO
|
||||
Transport** transports = NULL;//_context->getTransportRegistry().get("TCP", _responseFrom, size);
|
||||
@@ -83,12 +83,12 @@ void BeaconHandler::beaconArrivalNotify()
|
||||
{
|
||||
transports[i]->aliveNotification();
|
||||
}
|
||||
delete transports;
|
||||
delete[] transports;
|
||||
}
|
||||
|
||||
void BeaconHandler::changedTransport()
|
||||
{
|
||||
int32 size;
|
||||
int32 size = 0;
|
||||
//TODO TCP name must be get from somewhere not hardcoded
|
||||
//TODO
|
||||
Transport** transports = NULL;//_context->getTransportRegistry().get("TCP", _responseFrom, size);
|
||||
@@ -102,7 +102,7 @@ void BeaconHandler::changedTransport()
|
||||
{
|
||||
transports[i]->changedTransport();
|
||||
}
|
||||
delete transports;
|
||||
delete[] transports;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -67,7 +67,6 @@ namespace epics { namespace pvAccess {
|
||||
* Mutex
|
||||
*/
|
||||
Mutex _mutex;
|
||||
|
||||
/**
|
||||
* Update beacon.
|
||||
* @param remoteTransportRevision encoded (major, minor) revision.
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace epics { namespace pvAccess {
|
||||
*/
|
||||
BeaconServerStatusProvider(ServerContext* context);
|
||||
/**
|
||||
* Test Constructor (ohne context)
|
||||
* Test Constructor (without context)
|
||||
*/
|
||||
BeaconServerStatusProvider();
|
||||
/**
|
||||
|
||||
7
pvAccessApp/utils/namedLockPattern.cpp
Normal file
7
pvAccessApp/utils/namedLockPattern.cpp
Normal file
@@ -0,0 +1,7 @@
|
||||
/*
|
||||
* namedLockPattern.cpp
|
||||
*/
|
||||
|
||||
#include "namedLockPattern.h"
|
||||
|
||||
//NOTE NamedLockPattern is template so implementation is in header file
|
||||
144
pvAccessApp/utils/namedLockPattern.h
Normal file
144
pvAccessApp/utils/namedLockPattern.h
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* namedLockPattern.h
|
||||
*/
|
||||
|
||||
#ifndef NAMEDLOCKPATTERN_H
|
||||
#define NAMEDLOCKPATTERN_H
|
||||
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
|
||||
#include <lock.h>
|
||||
#include <pvType.h>
|
||||
|
||||
#include "referenceCountingLock.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace epics::pvData;
|
||||
|
||||
namespace epics { namespace pvAccess {
|
||||
/**
|
||||
* NamedLockPattern
|
||||
*/
|
||||
template <class Key, class Compare = less<Key> >
|
||||
class NamedLockPattern
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
NamedLockPattern() {};
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~NamedLockPattern() {};
|
||||
/**
|
||||
* Acquire synchronization lock for named object.
|
||||
* @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.
|
||||
*/
|
||||
bool acquireSynchronizationObject(const Key name, const int64 msec);
|
||||
/**
|
||||
* Release synchronization lock for named object.
|
||||
* @param name name of the object whose lock to release.
|
||||
*/
|
||||
void releaseSynchronizationObject(const Key name);
|
||||
private:
|
||||
Mutex _mutex;
|
||||
std::map<const Key,ReferenceCountingLock*,Compare> _namedLocks;
|
||||
typename std::map<const Key,ReferenceCountingLock*,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 int64 msec)
|
||||
{
|
||||
ReferenceCountingLock* lock;
|
||||
{ //due to guard
|
||||
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 = 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)
|
||||
{
|
||||
Lock guard(&_mutex);
|
||||
ReferenceCountingLock* 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);
|
||||
delete lock;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class Key, class Compare>
|
||||
class NamedLock : private NoDefaultMethods
|
||||
{
|
||||
public:
|
||||
NamedLock(NamedLockPattern<Key,Compare>* namedLockPattern): _namedLockPattern(namedLockPattern) {}
|
||||
bool acquireSynchronizationObject(const Key name, const int64 msec) {_name = name; return _namedLockPattern->acquireSynchronizationObject(name,msec);}
|
||||
~NamedLock(){_namedLockPattern->releaseSynchronizationObject(_name);}
|
||||
private:
|
||||
Key _name;
|
||||
NamedLockPattern<Key,Compare>* _namedLockPattern;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* NAMEDLOCKPATTERN_H */
|
||||
81
pvAccessApp/utils/referenceCountingLock.cpp
Normal file
81
pvAccessApp/utils/referenceCountingLock.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* namedLockPattern.cpp
|
||||
*/
|
||||
|
||||
#include "referenceCountingLock.h"
|
||||
|
||||
namespace epics { namespace pvAccess {
|
||||
|
||||
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(true);
|
||||
}
|
||||
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(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//string errMsg = "Error: pthread_mutexattr_settype failed: " + string(strerror(retval));
|
||||
assert(true);
|
||||
}
|
||||
|
||||
pthread_mutexattr_destroy(&mutexAttribute);
|
||||
}
|
||||
|
||||
ReferenceCountingLock::~ReferenceCountingLock()
|
||||
{
|
||||
pthread_mutex_destroy(&_mutex);
|
||||
}
|
||||
|
||||
bool ReferenceCountingLock::acquire(int64 msecs)
|
||||
{
|
||||
struct timespec deltatime;
|
||||
deltatime.tv_sec = msecs / 1000;
|
||||
deltatime.tv_nsec = (msecs % 1000) * 1000;
|
||||
|
||||
int32 retval = pthread_mutex_timedlock(&_mutex, &deltatime);
|
||||
if(retval == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ReferenceCountingLock::release()
|
||||
{
|
||||
int retval = pthread_mutex_unlock(&_mutex);
|
||||
if(retval != 0)
|
||||
{
|
||||
string errMsg = "Error: pthread_mutex_unlock failed: " + string(strerror(retval));
|
||||
//TODO do something?
|
||||
}
|
||||
}
|
||||
|
||||
int ReferenceCountingLock::increment()
|
||||
{
|
||||
//TODO does it really has to be atomic?
|
||||
//return ++_references;
|
||||
return __sync_add_and_fetch(&_references,1);
|
||||
}
|
||||
|
||||
int ReferenceCountingLock::decrement()
|
||||
{
|
||||
//TODO does it really has to be atomic?
|
||||
//return --_references;
|
||||
return __sync_sub_and_fetch(&_references,1);
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
74
pvAccessApp/utils/referenceCountingLock.h
Normal file
74
pvAccessApp/utils/referenceCountingLock.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* referenceCountingLock.h
|
||||
*/
|
||||
|
||||
#ifndef REFERENCECOUNTINGLOCK_H
|
||||
#define REFERENCECOUNTINGLOCK_H
|
||||
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <pvType.h>
|
||||
#include <epicsAssert.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace epics::pvData;
|
||||
|
||||
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:
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
bool acquire(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;
|
||||
pthread_mutex_t _mutex;
|
||||
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* NAMEDLOCKPATTERN_H */
|
||||
@@ -520,6 +520,26 @@ class MockChannel : public Channel {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void printInfo() {
|
||||
String info;
|
||||
printInfo(&info);
|
||||
std::cout << info.c_str() << std::endl;
|
||||
}
|
||||
|
||||
virtual void printInfo(epics::pvData::StringBuilder out) {
|
||||
//std::ostringstream ostr;
|
||||
//static String emptyString;
|
||||
|
||||
out->append( "CHANNEL : "); out->append(m_name);
|
||||
out->append("\nSTATE : "); out->append(ConnectionStateNames[getConnectionState()]);
|
||||
if (isConnected())
|
||||
{
|
||||
out->append("\nADDRESS : "); out->append(getRemoteAddress());
|
||||
//out->append("\nRIGHTS : "); out->append(getAccessRights());
|
||||
}
|
||||
out->append("\n");
|
||||
}
|
||||
};
|
||||
|
||||
class MockChannelProvider;
|
||||
@@ -905,7 +925,7 @@ int main(int argc,char *argv[])
|
||||
context->getProvider()->createChannel("test", &channelRequester, ChannelProvider::PRIORITY_DEFAULT, "over the rainbow");
|
||||
|
||||
Channel* channel = context->getProvider()->createChannel("test", &channelRequester);
|
||||
std::cout << channel->getChannelName() << std::endl;
|
||||
channel->printInfo();
|
||||
|
||||
GetFieldRequesterImpl getFieldRequesterImpl;
|
||||
channel->getField(&getFieldRequesterImpl, "timeStamp.secondsPastEpoch");
|
||||
|
||||
@@ -18,6 +18,9 @@ PROD_HOST += testBeaconEmitter
|
||||
testBeaconEmitter_SRCS += testBeaconEmitter.cpp
|
||||
testBeaconEmitter_LIBS += pvData pvAccess Com
|
||||
|
||||
PROD_HOST += testBeaconHandler
|
||||
testBeaconHandler_SRCS += testBeaconHandler.cpp
|
||||
testBeaconHandler_LIBS += pvData pvAccess Com
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
|
||||
@@ -42,9 +42,9 @@ void testBeaconEmitter()
|
||||
osiSockAddr* addr = new osiSockAddr;
|
||||
addr->ia.sin_family = AF_INET;
|
||||
addr->ia.sin_port = htons(5067);
|
||||
if(inet_aton("92.50.75.255",&addr->ia.sin_addr)==0) {
|
||||
cout<<"error in inet_aton()"<<endl;
|
||||
return;
|
||||
if(inet_aton("255.255.255.255",&addr->ia.sin_addr)==0)
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
broadcastAddresses->push_back(addr);
|
||||
BlockingUDPConnector connector(true, broadcastAddresses, true);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "blockingUDP.h"
|
||||
#include "beaconHandler.h"
|
||||
#include "inetAddressUtil.h"
|
||||
#include "introspectionRegistry.h"
|
||||
|
||||
#include <osiSock.h>
|
||||
|
||||
@@ -14,32 +15,105 @@
|
||||
|
||||
using namespace epics::pvAccess;
|
||||
using namespace epics::pvData;
|
||||
using namespace std;
|
||||
|
||||
void decodeFromIPv6Address(ByteBuffer* buffer, osiSockAddr* address)
|
||||
{
|
||||
// IPv4 compatible IPv6 address
|
||||
// first 80-bit are 0
|
||||
buffer->getLong();
|
||||
buffer->getShort();
|
||||
// next 16-bits are 1
|
||||
buffer->getShort();
|
||||
// following IPv4 address in big-endian (network) byte order
|
||||
in_addr_t ipv4Addr = 0;
|
||||
ipv4Addr |= (uint32)buffer->getByte() << 24;
|
||||
ipv4Addr |= (uint32)buffer->getByte() << 16;
|
||||
ipv4Addr |= (uint32)buffer->getByte() << 8;
|
||||
ipv4Addr |= (uint32)buffer->getByte() << 0;
|
||||
address->ia.sin_addr.s_addr = ipv4Addr;
|
||||
}
|
||||
|
||||
class BeaconResponseHandler : public ResponseHandler
|
||||
{
|
||||
public:
|
||||
BeaconResponseHandler()
|
||||
{
|
||||
_pvDataCreate = getPVDataCreate();
|
||||
}
|
||||
|
||||
virtual void handleResponse(osiSockAddr* responseFrom,
|
||||
Transport* transport, int8 version, int8 command, int payloadSize,
|
||||
ByteBuffer* payloadBuffer)
|
||||
{
|
||||
cout << "DummyResponseHandler::handleResponse" << endl;
|
||||
cout << "BeaconResponseHandler::handleResponse" << endl;
|
||||
|
||||
// reception timestamp
|
||||
TimeStamp timestamp;
|
||||
timestamp.getCurrent();
|
||||
|
||||
//TODO
|
||||
//super.handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer);
|
||||
|
||||
transport->ensureData((2*sizeof(int16)+2*sizeof(int32)+128)/sizeof(int8));
|
||||
|
||||
const int32 sequentalID = payloadBuffer->getShort() & 0x0000FFFF;
|
||||
const TimeStamp startupTimestamp(payloadBuffer->getInt() & 0x00000000FFFFFFFFL,(int32)(payloadBuffer->getInt() & 0x00000000FFFFFFFFL));
|
||||
|
||||
// 128-bit IPv6 address
|
||||
osiSockAddr address;
|
||||
decodeFromIPv6Address(payloadBuffer, &address);
|
||||
|
||||
// get port
|
||||
const int32 port = payloadBuffer->getShort() & 0xFFFF;
|
||||
address.ia.sin_port = ntohs(port);
|
||||
|
||||
// accept given address if explicitly specified by sender
|
||||
if (!ipv4AddressToInt(address))
|
||||
{
|
||||
responseFrom->ia.sin_port = port;
|
||||
}
|
||||
else
|
||||
{
|
||||
responseFrom->ia.sin_port = port;
|
||||
responseFrom->ia.sin_addr.s_addr = address.ia.sin_addr.s_addr;
|
||||
}
|
||||
|
||||
//org.epics.ca.client.impl.remote.BeaconHandler beaconHandler = context.getBeaconHandler(responseFrom);
|
||||
// currently we care only for servers used by this context
|
||||
//if (beaconHandler == null)
|
||||
// return;
|
||||
|
||||
// extra data
|
||||
PVFieldPtr data = NULL;
|
||||
const FieldConstPtr field = IntrospectionRegistry::deserializeFull(payloadBuffer, transport);
|
||||
if (field != NULL)
|
||||
{
|
||||
data = _pvDataCreate->createPVField(NULL, field);
|
||||
data->deserialize(payloadBuffer, transport);
|
||||
}
|
||||
|
||||
// notify beacon handler
|
||||
//beaconHandler.beaconNotify(responseFrom, version, timestamp, startupTimestamp, sequentalID, data);
|
||||
}
|
||||
|
||||
private:
|
||||
PVDataCreate* _pvDataCreate;
|
||||
BeaconHandler* _beaconHandler;
|
||||
};
|
||||
|
||||
|
||||
void testBeaconHandler()
|
||||
{
|
||||
BeacondResponseHandler brh;
|
||||
BeaconResponseHandler brh;
|
||||
BlockingUDPConnector connector(false, NULL, true);
|
||||
DummyClientContext context;
|
||||
|
||||
osiSockAddr bindAddr;
|
||||
bindAddr.ia.sin_family = AF_INET;
|
||||
bindAddr.ia.sin_port = htons(5067);
|
||||
bindAddr.ia.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
Transport* transport = connector.connect(NULL, &brh, &bindAddr, 1, 50);
|
||||
|
||||
((BlockingUDPTransport*)transport)->start();
|
||||
(static_cast<BlockingUDPTransport*>(transport))->start();
|
||||
|
||||
while(1) sleep(1);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -34,6 +34,10 @@ PROD_HOST += transportRegisterTest
|
||||
transportRegisterTest_SRCS += transportRegistryTest.cpp
|
||||
transportRegisterTest_LIBS += pvAccess Com pvData
|
||||
|
||||
PROD_HOST += namedLockPatternTest
|
||||
namedLockPatternTest_SRCS += namedLockPatternTest.cpp
|
||||
namedLockPatternTest_LIBS += pvAccess Com pvData
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
# ADD RULES AFTER THIS LINE
|
||||
|
||||
216
testApp/utils/namedLockPatternTest.cpp
Normal file
216
testApp/utils/namedLockPatternTest.cpp
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* namedLockPatternTest.cpp
|
||||
*
|
||||
*/
|
||||
|
||||
#include "namedLockPattern.h"
|
||||
#include "showConstructDestruct.h"
|
||||
|
||||
#include <epicsAssert.h>
|
||||
#include <iostream>
|
||||
|
||||
#include <osiSock.h>
|
||||
|
||||
using namespace epics::pvAccess;
|
||||
using namespace std;
|
||||
|
||||
void testIntLockPattern()
|
||||
{
|
||||
int64 timeout = 100;
|
||||
NamedLockPattern<int> namedLockPattern;
|
||||
int name1 = 1;
|
||||
assert(namedLockPattern.acquireSynchronizationObject(name1,timeout));
|
||||
assert(namedLockPattern.acquireSynchronizationObject(name1,timeout));
|
||||
namedLockPattern.releaseSynchronizationObject(name1);
|
||||
namedLockPattern.releaseSynchronizationObject(name1);
|
||||
int name2 = 2;
|
||||
assert(namedLockPattern.acquireSynchronizationObject(name2,timeout));
|
||||
namedLockPattern.releaseSynchronizationObject(name2);
|
||||
}
|
||||
|
||||
void testIntPtrLockPattern()
|
||||
{
|
||||
int64 timeout = 100;
|
||||
NamedLockPattern<int*> namedLockPattern;
|
||||
int name1 = 1;
|
||||
assert(namedLockPattern.acquireSynchronizationObject(&name1,timeout));
|
||||
assert(namedLockPattern.acquireSynchronizationObject(&name1,timeout));
|
||||
namedLockPattern.releaseSynchronizationObject(&name1);
|
||||
namedLockPattern.releaseSynchronizationObject(&name1);
|
||||
int name2 = 2;
|
||||
assert(namedLockPattern.acquireSynchronizationObject(&name2,timeout));
|
||||
namedLockPattern.releaseSynchronizationObject(&name2);
|
||||
}
|
||||
|
||||
struct cmp_str
|
||||
{
|
||||
bool operator()(char const *a, char const *b)
|
||||
{
|
||||
return strcmp(a, b) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
void testCharPtrLockPattern()
|
||||
{
|
||||
int64 timeout = 100;
|
||||
NamedLockPattern<const char*,cmp_str> namedLockPattern;
|
||||
string name1 = "lojze";
|
||||
assert(namedLockPattern.acquireSynchronizationObject(name1.c_str(),timeout));
|
||||
assert(namedLockPattern.acquireSynchronizationObject(name1.c_str(),timeout));
|
||||
namedLockPattern.releaseSynchronizationObject(name1.c_str());
|
||||
namedLockPattern.releaseSynchronizationObject(name1.c_str());
|
||||
string name2 = "francka";
|
||||
assert(namedLockPattern.acquireSynchronizationObject(name2.c_str(),timeout));
|
||||
namedLockPattern.releaseSynchronizationObject(name2.c_str());
|
||||
}
|
||||
|
||||
struct comp_osiSockAddrPtr
|
||||
{
|
||||
bool operator()(osiSockAddr const *a, osiSockAddr const *b)
|
||||
{
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
void testOsiSockAddrLockPattern()
|
||||
{
|
||||
int64 timeout = 10000;
|
||||
NamedLockPattern<const osiSockAddr*,comp_osiSockAddrPtr> namedLockPattern;
|
||||
osiSockAddr name1;
|
||||
name1.ia.sin_addr.s_addr = 1;
|
||||
name1.ia.sin_port = 1;
|
||||
name1.ia.sin_family = AF_INET;
|
||||
|
||||
assert(namedLockPattern.acquireSynchronizationObject(&name1,timeout));
|
||||
assert(namedLockPattern.acquireSynchronizationObject(&name1,timeout));
|
||||
namedLockPattern.releaseSynchronizationObject(&name1);
|
||||
namedLockPattern.releaseSynchronizationObject(&name1);
|
||||
|
||||
osiSockAddr name2;
|
||||
name2.ia.sin_addr.s_addr = 1;
|
||||
name2.ia.sin_port = 1;
|
||||
name2.ia.sin_family = AF_INET;
|
||||
NamedLock<const osiSockAddr*,comp_osiSockAddrPtr> namedGuard(&namedLockPattern);
|
||||
assert(namedGuard.acquireSynchronizationObject(&name1,timeout));
|
||||
}
|
||||
|
||||
struct comp_osiSockAddr
|
||||
{
|
||||
bool operator()(osiSockAddr const a, osiSockAddr const b)
|
||||
{
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
void* testWorker1(void* p)
|
||||
{
|
||||
int32 timeout = 1000;
|
||||
const int32 max = 1000;
|
||||
NamedLockPattern<osiSockAddr,comp_osiSockAddr>* namedLockPattern = (NamedLockPattern<osiSockAddr,comp_osiSockAddr>*)p;
|
||||
|
||||
for(int32 i = 0 ; i < max; i = i +2)
|
||||
{
|
||||
osiSockAddr addr;
|
||||
addr.ia.sin_addr.s_addr = i;
|
||||
addr.ia.sin_port = i;
|
||||
addr.ia.sin_family = AF_INET;
|
||||
NamedLock<osiSockAddr,comp_osiSockAddr> namedGuard(namedLockPattern);
|
||||
assert(namedGuard.acquireSynchronizationObject(addr,timeout));
|
||||
usleep(1);
|
||||
}
|
||||
|
||||
//this one takes a lock, thread 2 will be slower and will get timeout
|
||||
{ //due to namedGuard
|
||||
osiSockAddr addr;
|
||||
addr.ia.sin_addr.s_addr = 1;
|
||||
addr.ia.sin_port = 1;
|
||||
addr.ia.sin_family = AF_INET;
|
||||
NamedLock<osiSockAddr,comp_osiSockAddr> namedGuard(namedLockPattern);
|
||||
assert(namedGuard.acquireSynchronizationObject(addr,timeout));
|
||||
sleep(5);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void* testWorker2(void* p)
|
||||
{
|
||||
int32 timeout = 1000;
|
||||
const int32 max = 1000;
|
||||
NamedLockPattern<osiSockAddr,comp_osiSockAddr>* namedLockPattern = (NamedLockPattern<osiSockAddr,comp_osiSockAddr>*)p;
|
||||
|
||||
for(int32 i = 1 ; i < max; i = i + 2)
|
||||
{
|
||||
osiSockAddr addr;
|
||||
addr.ia.sin_addr.s_addr = i;
|
||||
addr.ia.sin_port = i;
|
||||
addr.ia.sin_family = AF_INET;
|
||||
NamedLock<osiSockAddr,comp_osiSockAddr> namedGuard(namedLockPattern);
|
||||
assert(namedGuard.acquireSynchronizationObject(addr,timeout));
|
||||
usleep(1);
|
||||
}
|
||||
|
||||
//this thread sleeps a while and gets timeout on lock
|
||||
{
|
||||
sleep(1);
|
||||
osiSockAddr addr;
|
||||
addr.ia.sin_addr.s_addr = 1;
|
||||
addr.ia.sin_port = 1;
|
||||
addr.ia.sin_family = AF_INET;
|
||||
NamedLock<osiSockAddr,comp_osiSockAddr> namedGuard(namedLockPattern);
|
||||
assert(!namedGuard.acquireSynchronizationObject(addr,timeout));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
testIntLockPattern();
|
||||
testIntPtrLockPattern();
|
||||
testCharPtrLockPattern();
|
||||
testOsiSockAddrLockPattern();
|
||||
|
||||
pthread_t _worker1Id;
|
||||
pthread_t _worker2Id;
|
||||
|
||||
NamedLockPattern<osiSockAddr,comp_osiSockAddr> namedLockPattern;
|
||||
|
||||
//create two threads
|
||||
int32 retval = pthread_create(&_worker1Id, NULL, testWorker1, &namedLockPattern);
|
||||
if(retval != 0)
|
||||
{
|
||||
assert(true);
|
||||
}
|
||||
|
||||
retval = pthread_create(&_worker2Id, NULL, testWorker2, &namedLockPattern);
|
||||
if(retval != 0)
|
||||
{
|
||||
assert(true);
|
||||
}
|
||||
|
||||
//wait for threads
|
||||
retval = pthread_join(_worker1Id, NULL);
|
||||
if(retval != 0)
|
||||
{
|
||||
assert(true);
|
||||
}
|
||||
|
||||
retval = pthread_join(_worker2Id, NULL);
|
||||
if(retval != 0)
|
||||
{
|
||||
assert(true);
|
||||
}
|
||||
|
||||
getShowConstructDestruct()->constuctDestructTotals(stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user