continuation of last commit

This commit is contained in:
Marty Kraimer
2010-12-08 07:10:01 -05:00
parent 381c6de7e9
commit 3c060afedb
35 changed files with 4353 additions and 0 deletions

386
pvDataApp/misc/bitSet.cpp Normal file
View File

@@ -0,0 +1,386 @@
/* bitSet.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include "string.h"
#include "stdio.h"
#include "bitSet.h"
namespace epics { namespace pvData {
BitSet::BitSet() : words(0), wordsLength(0), wordsInUse(0) {
initWords(BITS_PER_WORD);
}
BitSet::BitSet(uint32 nbits) : words(0), wordsLength(0), wordsInUse(0) {
initWords(nbits);
}
BitSet::~BitSet() {
delete words;
}
void BitSet::initWords(uint32 nbits) {
uint32 length = (nbits <= 0) ? 1 : wordIndex(nbits-1) + 1;
if (words) delete words;
words = new uint64[length];
bzero(words, sizeof(uint64)*length);
wordsLength = length;
}
void BitSet::recalculateWordsInUse() {
// wordsInUse is unsigned
if (wordsInUse == 0)
return;
// Traverse the bitset until a used word is found
uint32 i;
for (i = wordsInUse-1; i >= 0; i--)
if (words[i] != 0)
break;
wordsInUse = i+1; // The new logical size
}
void BitSet::ensureCapacity(uint32 wordsRequired) {
if (wordsLength < wordsRequired) {
// create and copy
uint64* newwords = new uint64[wordsRequired];
bzero(newwords, sizeof(uint64)*wordsRequired);
memcpy(newwords, words, sizeof(uint64)*wordsLength);
if (words) delete words;
words = newwords;
wordsLength = wordsRequired;
}
}
void BitSet::expandTo(uint32 wordIndex) {
uint32 wordsRequired = wordIndex+1;
if (wordsInUse < wordsRequired) {
ensureCapacity(wordsRequired);
wordsInUse = wordsRequired;
}
}
void BitSet::flip(uint32 bitIndex) {
uint32 wordIdx = wordIndex(bitIndex);
expandTo(wordIdx);
words[wordIdx] ^= (((uint64)1) << (bitIndex % BITS_PER_WORD));
recalculateWordsInUse();
}
void BitSet::set(uint32 bitIndex) {
uint32 wordIdx = wordIndex(bitIndex);
expandTo(wordIdx);
words[wordIdx] |= (((uint64)1) << (bitIndex % BITS_PER_WORD));
}
void BitSet::clear(uint32 bitIndex) {
uint32 wordIdx = wordIndex(bitIndex);
if (wordIdx >= wordsInUse)
return;
words[wordIdx] &= ~(((uint64)1) << (bitIndex % BITS_PER_WORD));
recalculateWordsInUse();
}
void BitSet::set(uint32 bitIndex, bool value) {
if (value)
set(bitIndex);
else
clear(bitIndex);
}
bool BitSet::get(uint32 bitIndex) const {
uint32 wordIdx = wordIndex(bitIndex);
return ((wordIdx < wordsInUse)
&& ((words[wordIdx] & (((uint64)1) << (bitIndex % BITS_PER_WORD))) != 0));
}
void BitSet::clear() {
while (wordsInUse > 0)
words[--wordsInUse] = 0;
}
uint32 BitSet::numberOfTrailingZeros(uint64 i) {
// HD, Figure 5-14
uint32 x, y;
if (i == 0) return 64;
uint32 n = 63;
y = (uint32)i; if (y != 0) { n = n -32; x = y; } else x = (uint32)(i>>32);
y = x <<16; if (y != 0) { n = n -16; x = y; }
y = x << 8; if (y != 0) { n = n - 8; x = y; }
y = x << 4; if (y != 0) { n = n - 4; x = y; }
y = x << 2; if (y != 0) { n = n - 2; x = y; }
return n - ((x << 1) >> 31);
}
uint32 BitSet::bitCount(uint64 i) {
// HD, Figure 5-14
i = i - ((i >> 1) & 0x5555555555555555LL);
i = (i & 0x3333333333333333LL) + ((i >> 2) & 0x3333333333333333LL);
i = (i + (i >> 4)) & 0x0f0f0f0f0f0f0f0fLL;
i = i + (i >> 8);
i = i + (i >> 16);
i = i + (i >> 32);
return (uint32)(i & 0x7f);
}
int32 BitSet::nextSetBit(uint32 fromIndex) const {
uint32 u = wordIndex(fromIndex);
if (u >= wordsInUse)
return -1;
uint64 word = words[u] & (WORD_MASK << (fromIndex % BITS_PER_WORD));
while (true) {
if (word != 0)
return (u * BITS_PER_WORD) + numberOfTrailingZeros(word);
if (++u == wordsInUse)
return -1;
word = words[u];
}
}
int32 BitSet::nextClearBit(uint32 fromIndex) const {
// Neither spec nor implementation handle bitsets of maximal length.
uint32 u = wordIndex(fromIndex);
if (u >= wordsInUse)
return fromIndex;
uint64 word = ~words[u] & (WORD_MASK << (fromIndex % BITS_PER_WORD));
while (true) {
if (word != 0)
return (u * BITS_PER_WORD) + numberOfTrailingZeros(word);
if (++u == wordsInUse)
return wordsInUse * BITS_PER_WORD;
word = ~words[u];
}
}
bool BitSet::isEmpty() const {
return (wordsInUse == 0);
}
uint32 BitSet::cardinality() const {
uint32 sum = 0;
for (uint32 i = 0; i < wordsInUse; i++)
sum += bitCount(words[i]);
return sum;
}
BitSet& BitSet::operator&=(const BitSet& set) {
while (wordsInUse > set.wordsInUse)
words[--wordsInUse] = 0;
// Perform logical AND on words in common
for (uint32 i = 0; i < wordsInUse; i++)
words[i] &= set.words[i];
recalculateWordsInUse();
return *this;
}
BitSet& BitSet::operator|=(const BitSet& set) {
uint32 wordsInCommon;
if (wordsInUse < set.wordsInUse) {
wordsInCommon = wordsInUse;
//ensureCapacity(set.wordsInUse);
//wordsInUse = set.wordsInUse;
}
else
wordsInCommon = set.wordsInUse;
// Perform logical OR on words in common
uint32 i = 0;
for (; i < wordsInCommon; i++)
words[i] |= set.words[i];
// TODO what to do if BitSets are not the same size !!!
// recalculateWordsInUse() is not needed
return *this;
}
BitSet& BitSet::operator^=(const BitSet& set) {
uint32 wordsInCommon;
if (wordsInUse < set.wordsInUse) {
wordsInCommon = wordsInUse;
//ensureCapacity(set.wordsInUse);
//wordsInUse = set.wordsInUse;
}
else
wordsInCommon = set.wordsInUse;
// Perform logical XOR on words in common
uint32 i = 0;
for (; i < wordsInCommon; i++)
words[i] ^= set.words[i];
// TODO what to do if BitSets are not the same size !!!
recalculateWordsInUse();
return *this;
}
BitSet& BitSet::operator-=(const BitSet& set) {
uint32 wordsInCommon;
if (wordsInUse < set.wordsInUse) {
wordsInCommon = wordsInUse;
//ensureCapacity(set.wordsInUse);
//wordsInUse = set.wordsInUse;
}
else
wordsInCommon = set.wordsInUse;
// Perform logical (a & !b) on words in common
uint32 i = 0;
for (; i < wordsInCommon; i++)
words[i] &= ~set.words[i];
recalculateWordsInUse();
return *this;
}
BitSet& BitSet::operator=(const BitSet &set) {
// Check for self-assignment!
if (this == &set)
return *this;
// we ensure that words array size is adequate (and not wordsInUse to ensure capacity to the future)
if (wordsLength < set.wordsLength)
{
if (words) delete words;
words = new uint64[set.wordsLength];
wordsLength = set.wordsLength;
}
memcpy(words, set.words, sizeof(uint64)*set.wordsInUse);
wordsInUse = set.wordsInUse;
return *this;
}
void BitSet::or_and(const BitSet& set1, const BitSet& set2) {
uint32 inUse = (set1.wordsInUse < set2.wordsInUse) ? set1.wordsInUse : set2.wordsInUse;
ensureCapacity(inUse);
wordsInUse = inUse;
// Perform logical AND on words in common
for (uint32 i = 0; i < inUse; i++)
words[i] |= (set1.words[i] & set2.words[i]);
// recalculateWordsInUse()...
}
bool BitSet::operator==(const BitSet &set) const
{
if (this == &set)
return true;
if (wordsInUse != set.wordsInUse)
return false;
// Check words in use by both BitSets
for (uint32 i = 0; i < wordsInUse; i++)
if (words[i] != set.words[i])
return false;
return true;
}
bool BitSet::operator!=(const BitSet &set) const
{
return !(*this == set);
}
void BitSet::toString(StringBuilder buffer) { toString(buffer, 0); }
void BitSet::toString(StringBuilder buffer, int indentLevel) const
{
*buffer += '{';
int32 i = nextSetBit(0);
char tmp[30];
if (i != -1) {
sprintf(tmp,"%d",i); *buffer += tmp;
for (i = nextSetBit(i+1); i >= 0; i = nextSetBit(i+1)) {
int32 endOfRun = nextClearBit(i);
do { *buffer += ", "; sprintf(tmp,"%d",i); *buffer += tmp; } while (++i < endOfRun);
}
}
*buffer += '}';
}
/*
void serialize(ByteBuffer buffer, SerializableControl flusher) {
final int n = wordsInUse;
if (n == 0) {
SerializeHelper.writeSize(0, buffer, flusher);
return;
}
int len = 8 * (n-1);
for (long x = words[n - 1]; x != 0; x >>>= 8)
len++;
SerializeHelper.writeSize(len, buffer, flusher);
flusher.ensureBuffer(len);
for (int i = 0; i < n - 1; i++)
buffer.putLong(words[i]);
for (long x = words[n - 1]; x != 0; x >>>= 8)
buffer.put((byte) (x & 0xff));
}
public void deserialize(ByteBuffer buffer, DeserializableControl control) {
final int bytes = SerializeHelper.readSize(buffer, control); // in bytes
wordsInUse = (bytes + 7) / 8;
if (wordsInUse > words.length)
words = new long[wordsInUse];
if (wordsInUse == 0)
return;
control.ensureData(bytes);
int i = 0;
final int longs = bytes / 8;
while (i < longs)
words[i++] = buffer.getLong();
for (int j = i; j < wordsInUse; j++)
words[j] = 0;
for (int remaining = (bytes - longs * 8), j = 0; j < remaining; j++)
words[i] |= (buffer.get() & 0xffL) << (8 * j);
}
*/
}};

310
pvDataApp/misc/bitSet.h Normal file
View File

@@ -0,0 +1,310 @@
/* bitSet.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#ifndef BITSET_H
#define BITSET_H
#include <stdexcept>
#include <pvType.h>
//#include "byteBuffer.h"
//#include "serialize.h"
namespace epics { namespace pvData {
/**
* This class implements a vector of bits that grows as needed. Each
* component of the bit set has a {@code bool} value. The
* bits of a {@code BitSet} are indexed by nonnegative integers.
* Individual indexed bits can be examined, set, or cleared. One
* {@code BitSet} may be used to modify the contents of another
* {@code BitSet} through logical AND, logical inclusive OR, and
* logical exclusive OR operations.
*
* <p>By default, all bits in the set initially have the value
* {@code false}.
*
* <p>Every bit set has a current size, which is the number of bits
* of space currently in use by the bit set. Note that the size is
* related to the implementation of a bit set, so it may change with
* implementation. The length of a bit set relates to logical length
* of a bit set and is defined independently of implementation.
*
* <p>A {@code BitSet} is not safe for multithreaded use without
* external synchronization.
*
* Based on Java implementation.
*/
class BitSet /*: public Serializable*/ {
public:
/**
* Creates a new bit set. All bits are initially {@code false}.
*/
BitSet();
/**
* Creates a bit set whose initial size is large enough to explicitly
* represent bits with indices in the range {@code 0} through
* {@code nbits-1}. All bits are initially {@code false}.
*
* @param nbits the initial size of the bit set
*/
BitSet(uint32 nbits);
/**
* Destructor.
*/
virtual ~BitSet();
/**
* Sets the bit at the specified index to the complement of its
* current value.
*
* @param bitIndex the index of the bit to flip
*/
void flip(uint32 bitIndex);
/**
* Sets the bit at the specified index to {@code true}.
*
* @param bitIndex a bit index
*/
void set(uint32 bitIndex);
/**
* Sets the bit specified by the index to {@code false}.
*
* @param bitIndex the index of the bit to be cleared
*/
void clear(uint32 bitIndex);
/**
* Sets the bit at the specified index to the specified value.
*
* @param bitIndex a bit index
* @param value a boolean value to set
*/
void set(uint32 bitIndex, bool value);
/**
* Returns the value of the bit with the specified index. The value
* is {@code true} if the bit with the index {@code bitIndex}
* is currently set in this {@code BitSet}; otherwise, the result
* is {@code false}.
*
* @param bitIndex the bit index
* @return the value of the bit with the specified index
*/
bool get(uint32 bitIndex) const;
/**
* Sets all of the bits in this BitSet to {@code false}.
*/
void clear();
/**
* Returns the index of the first bit that is set to {@code true}
* that occurs on or after the specified starting index. If no such
* bit exists then {@code -1} is returned.
*
* <p>To iterate over the {@code true} bits in a {@code BitSet},
* use the following loop:
*
* <pre> {@code
* for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
* // operate on index i here
* }}</pre>
*
* @param fromIndex the index to start checking from (inclusive)
* @return the index of the next set bit, or {@code -1} if there
* is no such bit
*/
int32 nextSetBit(uint32 fromIndex) const;
/**
* Returns the index of the first bit that is set to {@code false}
* that occurs on or after the specified starting index.
*
* @param fromIndex the index to start checking from (inclusive)
* @return the index of the next clear bit
*/
int32 nextClearBit(uint32 fromIndex) const;
/**
* Returns true if this {@code BitSet} contains no bits that are set
* to {@code true}.
*
* @return indicating whether this {@code BitSet} is empty
*/
bool isEmpty() const;
/**
* Returns the number of bits set to {@code true} in this {@code BitSet}.
*
* @return the number of bits set to {@code true} in this {@code BitSet}
*/
uint32 cardinality() const;
/**
* Performs a logical <b>AND</b> of this target bit set with the
* argument bit set. This bit set is modified so that each bit in it
* has the value {@code true} if and only if it both initially
* had the value {@code true} and the corresponding bit in the
* bit set argument also had the value {@code true}.
*
* @param set a bit set
*/
BitSet& operator&=(const BitSet& set);
/**
* Performs a logical <b>OR</b> of this bit set with the bit set
* argument. This bit set is modified so that a bit in it has the
* value {@code true} if and only if it either already had the
* value {@code true} or the corresponding bit in the bit set
* argument has the value {@code true}.
*
* @param set a bit set
*/
BitSet& operator|=(const BitSet& set);
/**
* Performs a logical <b>XOR</b> of this bit set with the bit set
* argument. This bit set is modified so that a bit in it has the
* value {@code true} if and only if one of the following
* statements holds:
* <ul>
* <li>The bit initially has the value {@code true}, and the
* corresponding bit in the argument has the value {@code false}.
* <li>The bit initially has the value {@code false}, and the
* corresponding bit in the argument has the value {@code true}.
* </ul>
*
* @param set a bit set
*/
BitSet& operator^=(const BitSet& set);
/**
* Clears all of the bits in this {@code BitSet} whose corresponding
* bit is set in the specified {@code BitSet}.
*
* @param set the {@code BitSet} with which to mask this
* {@code BitSet}
*/
BitSet& operator-=(const BitSet& set);
/**
* Assigment operator.
*/
BitSet& operator=(const BitSet &set);
/**
* Perform AND operation on <code>set1</code> and <code>set2</code>,
* and OR on result and this instance.
* @param set1
* @param set2
*/
void or_and(const BitSet& set1, const BitSet& set2);
/**
* Comparison operator.
*/
bool operator==(const BitSet &set) const;
bool operator!=(const BitSet &set) const;
void toString(StringBuilder buffer);
void toString(StringBuilder buffer, int indentLevel) const;
private:
/*
* BitSets are packed into arrays of "words." Currently a word is
* a long, which consists of 64 bits, requiring 6 address bits.
* The choice of word size is determined purely by performance concerns.
*/
static const uint32 ADDRESS_BITS_PER_WORD = 6;
static const uint32 BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD;
static const uint32 BIT_INDEX_MASK = BITS_PER_WORD - 1;
/** Used to shift left or right for a partial word mask */
static const uint64 WORD_MASK = ~((uint64)0);
/** The internal field corresponding to the serialField "bits". */
uint64* words;
/** The internal field corresponding to the size of words[] array. */
uint32 wordsLength;
/** The number of words in the logical size of this BitSet. */
uint32 wordsInUse;
private:
/**
* Given a bit index, return word index containing it.
*/
static inline uint32 wordIndex(uint32 bitIndex) {
return bitIndex >> ADDRESS_BITS_PER_WORD;
}
/**
* Creates a new word array.
*/
void initWords(uint32 nbits);
/**
* Sets the field wordsInUse to the logical size in words of the bit set.
* WARNING: This method assumes that the number of words actually in use is
* less than or equal to the current value of wordsInUse!
*/
void recalculateWordsInUse();
/**
* Ensures that the BitSet can hold enough words.
* @param wordsRequired the minimum acceptable number of words.
*/
void ensureCapacity(uint32 wordsRequired);
/**
* Ensures that the BitSet can accommodate a given wordIndex,
* temporarily violating the invariants. The caller must
* restore the invariants before returning to the user,
* possibly using recalculateWordsInUse().
* @param wordIndex the index to be accommodated.
*/
void expandTo(uint32 wordIndex);
/**
* Returns the number of zero bits following the lowest-order ("rightmost")
* one-bit in the two's complement binary representation of the specified
* <tt>long</tt> value. Returns 64 if the specified value has no
* one-bits in its two's complement representation, in other words if it is
* equal to zero.
*
* @return the number of zero bits following the lowest-order ("rightmost")
* one-bit in the two's complement binary representation of the
* specified <tt>long</tt> value, or 64 if the value is equal
* to zero.
*/
static uint32 numberOfTrailingZeros(uint64 i);
/**
* Returns the number of one-bits in the two's complement binary
* representation of the specified <tt>long</tt> value. This function is
* sometimes referred to as the <i>population count</i>.
*
* @return the number of one-bits in the two's complement binary
* representation of the specified <tt>long</tt> value.
*/
static uint32 bitCount(uint64 i);
};
}}
#endif /* BITSET_H */

View File

@@ -0,0 +1,198 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/*
* byteBuffer.cpp
*
* Created on: Oct 18, 2010
* Author: Miha Vitorovic
*/
#include <cstring>
#include "byteBuffer.h"
#include "epicsException.h"
namespace epics {
namespace pvData {
using std::stringstream;
ByteBuffer::ByteBuffer(int size, int byteOrder) :
_bufferByteOrder(byteOrder), _size(size), _position(0),
_limit(size), _buffer(0) {
if (size < 0)
throw EpicsException("negative size");
if (byteOrder!=EPICS_ENDIAN_BIG && byteOrder!=EPICS_ENDIAN_LITTLE)
throw EpicsException("invalid endian");
_buffer = new char[_size];
}
ByteBuffer::~ByteBuffer() {
if (_buffer) delete _buffer;
}
ByteBuffer* ByteBuffer::clear() {
_position = 0;
_limit = _size;
return this;
}
ByteBuffer* ByteBuffer::flip() {
_limit = _position;
_position = 0;
return this;
}
ByteBuffer* ByteBuffer::rewind() {
_position = 0;
return this;
}
bool ByteBuffer::getBoolean() {
if(_position<_limit)
return _buffer[_position++]==0 ? false : true;
else
throw EpicsException("buffer underflow");
}
int8 ByteBuffer::getByte() {
if(_position<_limit)
return (int8)_buffer[_position++];
else
throw EpicsException("buffer underflow");
}
int16 ByteBuffer::getShort() {
if(_limit-_position<(int)sizeof(int16))
throw EpicsException("buffer underflow");
int16 val;
getWithEndianness((char*)&val, sizeof(int16)); // store short into val
return val;
}
int32 ByteBuffer::getInt() {
if(_limit-_position<(int)sizeof(int32))
throw EpicsException("buffer underflow");
int32 val;
getWithEndianness((char*)&val, sizeof(int32)); // store int into val
return val;
}
int64 ByteBuffer::getLong() {
if(_limit-_position<(int)sizeof(int64))
throw EpicsException("buffer underflow");
int64 val;
getWithEndianness((char*)&val, sizeof(int64)); // store long into val
return val;
}
float ByteBuffer::getFloat() {
if(_limit-_position<(int)sizeof(float))
throw EpicsException("buffer underflow");
float val;
getWithEndianness((char*)&val, sizeof(float)); // store float into val
return val;
}
double ByteBuffer::getDouble() {
if(_limit-_position<(int)sizeof(double))
throw EpicsException("buffer underflow");
double val;
getWithEndianness((char*)&val, sizeof(double)); // store double into val
return val;
}
void ByteBuffer::get(char* dst, int offset, int count) {
if(count>getRemaining()) throw EpicsException("buffer underflow");
for(int i = 0; i<count; i++)
dst[offset+i] = _buffer[_position++];
}
ByteBuffer* ByteBuffer::put(const char* src, int offset, int count) {
if(count>getRemaining()) throw EpicsException("buffer overflow");
for(int i = 0; i<count; i++)
_buffer[_position++] = src[offset+i];
return this;
}
ByteBuffer* ByteBuffer::putBoolean(bool value) {
if(_position<_limit)
_buffer[_position++] = value ? 1 : 0;
else
throw EpicsException("buffer overflow");
return this;
}
ByteBuffer* ByteBuffer::putByte(int8 value) {
if(_position<_limit)
_buffer[_position++] = (char)value;
else
throw EpicsException("buffer overflow");
return this;
}
ByteBuffer* ByteBuffer::putShort(int16 value) {
if(_limit-_position<(int)sizeof(int16))
throw EpicsException("buffer overflow");
putWithEndianness((char*)&value, sizeof(int16)); // store short into buffer
return this;
}
ByteBuffer* ByteBuffer::putInt(int32 value) {
if(_limit-_position<(int)sizeof(int32))
throw EpicsException("buffer overflow");
putWithEndianness((char*)&value, sizeof(int32)); // store int into buffer
return this;
}
ByteBuffer* ByteBuffer::putLong(int64 value) {
if(_limit-_position<(int)sizeof(int64))
throw EpicsException("buffer overflow");
putWithEndianness((char*)&value, sizeof(int64)); // store long into buffer
return this;
}
ByteBuffer* ByteBuffer::putFloat(float value) {
if(_limit-_position<(int)sizeof(float))
throw EpicsException("buffer overflow");
putWithEndianness((char*)&value, sizeof(float)); // store float into buffer
return this;
}
ByteBuffer* ByteBuffer::putDouble(double value) {
if(_limit-_position<(int)sizeof(double))
throw EpicsException("buffer overflow");
putWithEndianness((char*)&value, sizeof(double)); // store double into buffer
return this;
}
/**
* Buffer underflow or overflow checks are performed in the caller.
*/
void ByteBuffer::getWithEndianness(char* dest, size_t size) {
if(_bufferByteOrder==EPICS_BYTE_ORDER)
for(size_t i = 0; i<size; i++)
dest[i] = _buffer[_position++];
else
for(int i = (int)size-1; i>=0; i--)
dest[i] = _buffer[_position++];
}
/**
* Buffer underflow or overflow checks are performed in the caller.
*/
void ByteBuffer::putWithEndianness(char* src, size_t size) {
if(_bufferByteOrder==EPICS_BYTE_ORDER)
for(size_t i = 0; i<size; i++)
_buffer[_position++] = src[i];
else
for(int i = (int)size-1; i>=0; i--)
_buffer[_position++] = src[i];
}
}
}

330
pvDataApp/misc/byteBuffer.h Normal file
View File

@@ -0,0 +1,330 @@
/* byteBuffer.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#ifndef BYTEBUFFER_H
#define BYTEBUFFER_H
#include <string>
#include <pvType.h>
#include <epicsEndian.h>
namespace epics {
namespace pvData {
/** @brief A buffer of bytes.
*
* A buffer of bytes, which has
* - capacity (size)
* - limit
* - position
* The capacity is the maximum capacity of the buffer, the buffer's
* limit is the index of the first element that should not be read or
* written, and its position is the index of the next element to be
* written.
*
* The buffer also ha a byte order specified which can be little or
* big endian.
*/
class ByteBuffer {
public:
/** @brief ByteBuffer constructor.
*
* Creates a buffer of a given size, and with a specified byteOrder.
*
* @param size Specify the capacity of the buffer. Default is 32.
* @param byteOrder the byte order of the buffer. Can be either
* EPICS_ENDIAN_LITTLE or EPICS_ENDIAN_BIG.
*/
ByteBuffer(int size = 32, int byteOrder = EPICS_BYTE_ORDER);
/**
* @brief ByteBuffer destructor.
*/
~ByteBuffer();
/**
* Clears the buffer. Sets the {@code position} to 0 and {@code limit}
* to {@code capacity}.
*/
ByteBuffer* clear();
/**
* Flips the buffer. The {@code limit} is set to the current {@code position}
* and the {@code position} is set to {@code 0}. This prepares the
* buffer for a series of relative @em get operations after a series
* of relative @em put operations.
*/
ByteBuffer* flip();
/**
* Rewinds the buffer. This sets {@code position} to {@code 0}
* without affecting the {@code limit}.
*/
ByteBuffer* rewind();
/**
* Relative boolean read, {@code position} is incremented by
* {@code 1}.
*
* @returns The next byte in the buffer as a boolean.
* @throws EpicsException - Buffer underflow if there are no bytes
* remaining in the buffer.
*/
bool getBoolean();
/**
* Relative Int8 read, {@code position} is incremented by
* {@code 1}.
*
* @returns The next byte in the buffer as a signed Int8.
* @throws EpicsException - Buffer underflow if there are no bytes
* remaining in the buffer.
*/
int8 getByte();
/**
* Relative Int16 read, {@code position} is incremented by
* {@code 2}.
*
* @returns The next Int16 value in the buffer.
* @throws EpicsException - Buffer underflow if there are less than
* 2 bytes remaining in the buffer.
*/
int16 getShort();
/**
* Relative Int32 read, {@code position} is incremented by
* {@code 4}.
*
* @returns The next Int32 value in the buffer.
* @throws EpicsException - Buffer underflow if there are less than
* 4 bytes remaining in the buffer.
*/
int32 getInt();
/**
* Relative Int64 read, {@code position} is incremented by
* {@code 8}.
*
* @returns The next Int64 value in the buffer.
* @throws EpicsException - Buffer underflow if there are less than
* 8 bytes remaining in the buffer.
*/
int64 getLong();
/**
* Relative float read, {@code position} is incremented by
* {@code 4}.
*
* @returns The next float value in the buffer.
* @throws EpicsException - Buffer underflow if there are less than
* 4 bytes remaining in the buffer.
*/
float getFloat();
/**
* Relative double read, {@code position} is incremented by
* {@code 8}.
*
* @returns The next double value in the buffer.
* @throws EpicsException - Buffer underflow if there are less than
* 8 bytes remaining in the buffer.
*/
double getDouble();
/**
* Relative bulk @em get method. It transfers {@code count} bytes
* from the buffer into the {@code dst}.
*
* @param[out] dst Destination buffer
* @param[in] offset Offset in the destination buffer
* @param[in] count The number of bytes to copy
* @throws EpicsException - Buffer underflow if there are fewer
* than count bytes remaining in the buffer.
*/
void get(char* dst, int offset, int count);
//virtual String getString() = 0; // TODO
/**
* Relative bulk @em put method. It transfers {@code count} bytes
* from the {@code src} into the the buffer.
*
* @param[in] src Source buffer
* @param[in] offset Offset in the source buffer
* @param[in] count The number of bytes to copy
* @returns Pointer to this ByteBuffer instance.
* @throws EpicsException - Buffer overflow if there are not
* enough bytes remaining in the buffer.
*/
ByteBuffer* put(const char* src, int offset, int count);
/**
* Relative boolean write, {@code position} is incremented by
* {@code 1}.
*
* @param[in] value The boolean value to write.
* @throws EpicsException - Buffer overflow if there are no
* bytes remaining in the buffer.
*/
ByteBuffer* putBoolean(bool value);
/**
* Relative Int8 write, {@code position} is incremented by
* {@code 1}.
*
* @param[in] value The Int8 value to write.
* @throws EpicsException - Buffer overflow if there are no
* bytes remaining in the buffer.
*/
ByteBuffer* putByte(int8 value);
/**
* Relative Int16 write, {@code position} is incremented by
* {@code 2}.
*
* @param[in] value The Int16 value to write.
* @throws EpicsException - Buffer overflow if there are less than
* 2 bytes remaining in the buffer.
*/
ByteBuffer* putShort(int16 value);
/**
* Relative Int32 write, {@code position} is incremented by
* {@code 4}.
*
* @param[in] value The Int32 value to write.
* @throws EpicsException - Buffer overflow if there are less than
* 4 bytes remaining in the buffer.
*/
ByteBuffer* putInt(int32 value);
/**
* Relative Int64 write, {@code position} is incremented by
* {@code 8}.
*
* @param[in] value The Int64 value to write.
* @throws EpicsException - Buffer overflow if there are less than
* 8 bytes remaining in the buffer.
*/
ByteBuffer* putLong(int64 value);
/**
* Relative float write, {@code position} is incremented by
* {@code 4}.
*
* @param[in] value The float value to write.
* @throws EpicsException - Buffer overflow if there are less than
* 4 bytes remaining in the buffer.
*/
ByteBuffer* putFloat(float value);
/**
* Relative float write, {@code position} is incremented by
* {@code 8}.
*
* @param[in] value The double value to write.
* @throws EpicsException - Buffer overflow if there are less than
* 8 bytes remaining in the buffer.
*/
ByteBuffer* putDouble(double value);
//virtual ByteBuffer *putString(String value) = 0; // TODO
/**
* The capacity (size) of the buffer in bytes.
*
* @returns The capacity of the buffer in bytes.
*/
inline int getSize() const {
return _size;
}
/**
* The offset from the start of the buffer in bytes. Currently this
* method always returns {@code 0}.
*
* @returns The offset from the start of the buffer in bytes
*/
inline int getArrayOffset() const {
return 0;
}
/**
* The byte index of the next element to @em get or @em put.
*
* @returns The byte index of the next element.
*/
inline int getPosition() const {
return _position;
}
/**
* The byte index of the {@code limit}. {@code limit} is always less
* or equal to the buffer capacity. No @em put or @em get operation
* can be performed pass the {@code limit}.
*
* @returns The byte index of the {@code limit}.
*/
inline int getLimit() const {
return _limit;
}
/**
* The number of the bytes that can be successfully read or written.
*
* @returns The number of the bytes that can be successfully read or
* written.
*/
inline int getRemaining() const {
return _limit-_position;
}
/**
* The byte order of the buffer.
*
* @returns Either {@code EPICS_ENDIAN_LITTLE} or
* {@code EPICS_ENDIAN_BIG}.
*/
inline int getByteOrder() const {
return _bufferByteOrder;
}
/**
* Gives a read-only access to the buffer.
*
* @returns A const (read-only) pointer to the actual buffer.
*/
inline const char* getArray() const {
return _buffer;
}
// TODO must define arrays
private:
int _bufferByteOrder, _size, _position, _limit;
char* _buffer;
/**
* Reads the next <pre>size</pre> bytes from the buffer and stores them
* into the destination taking into account endianness of the buffer
* and the current hardware.
*/
void getWithEndianness(char* dest, size_t size);
/**
* Puts the next <pre>size</pre> bytes into the buffer reading them
* from source taking into account endianness of the buffer
* and the current hardware.
*/
void putWithEndianness(char* src, size_t size);
};
}
}
#endif /* BYTEBUFFER_H */

View File

@@ -0,0 +1,231 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/*
* epicsException.hpp
*
* Created on: Oct 20, 2010
* Author: Matej Sekoranja
*/
#include <cstdio>
#ifndef EPICSEXCEPTION_H_
#define EPICSEXCEPTION_H_
// TODO to be redefined!!!!!!
#include <stdexcept>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#include <cxxabi.h>
namespace epics { namespace pvData {
class BaseException :
public std::exception {
public:
BaseException(const char* message, const char* file, int line, std::exception* cause = 0)
: m_msg(message), m_file(file), m_line(line), m_cause(cause)
{
getStackTrace(&m_stackTrace);
}
virtual ~BaseException() throw()
{
if (m_cause) delete m_cause;
}
virtual const char* what() const throw() { return m_msg.c_str(); }
const char* getFile() const { return m_file.c_str(); }
int getLine() const { return m_line; }
void toString(std::string& str, unsigned int depth = 0) {
str.append("BaseException: ");
str.append(m_msg);
str.append("\n\tat ");
str.append(m_file);
str.append(":");
char sline[10];
snprintf(sline, 10, "%d", m_line);
str.append(sline);
str.append("\n");
str.append(m_stackTrace);
if (m_cause)
{
str.append("caused by: ");
BaseException *be = dynamic_cast<BaseException*>(m_cause);
if (be)
be->toString(str, depth+1);
else
str.append(m_cause->what());
}
}
/** Get stack trace, i.e. demangled backtrace of the caller. */
static inline void getStackTrace(std::string* trace, unsigned int skip_frames = 0, unsigned int max_frames = 63)
{
#ifdef DISABLE_STACK_TRACE
trace += "(stack trace disabled)";
#else
// storage array for stack trace address data
void* addrlist[max_frames+1];
// retrieve current stack addresses
int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*));
if (addrlen == 0) {
trace->append("(stack trace not available)");
return;
}
// resolve addresses into strings containing "filename(function+address)",
// this array must be free()-ed
char** symbollist = backtrace_symbols(addrlist, addrlen);
// allocate string which will be filled with the demangled function name
size_t funcnamesize = 256;
char* funcname = (char*)malloc(funcnamesize);
// iterate over the returned symbol lines. skip the first, it is the
// address of this function.
for (int i = (1 + skip_frames); i < addrlen; i++)
{
char *module = 0, *fname = 0, *offset = 0;
#ifdef __APPLE__
int stage = 0;
for (char *p = symbollist[i]; *p; ++p)
{
// find spaces and separate
// 0 a.out 0x0000000100000bbc _Z11print_tracev + 22
switch (stage)
{
case 0: // skip frame index
if (*p == ' ') stage++;
break;
case 1: // skip spaces
if (*p != ' ') { module = p; stage++; }
break;
case 2: // module name
if (*p == ' ') { *p = '\0'; stage++; }
break;
case 3: // skip spaces
if (*p != ' ') stage++;
break;
case 4: // address
if (*p == ' ') { fname = p+1; stage++; }
break;
case 5: // function
if (*p == ' ') { *p = '\0'; stage++; }
break;
case 6: // "+ "
if (*p == '+') { p++; offset = p+1; };
break;
}
}
#else
// find parentheses and +address offset surrounding the mangled name:
// ./module(function+0x15c) [0x8048a6d]
module = symbollist[i];
for (char *p = symbollist[i]; *p; ++p)
{
if (*p == '(') {
// terminate module
*p = '\0';
fname = p+1;
}
else if (*p == '+') {
// terminate fname
*p = '\0';
offset = p+1;
}
else if (*p == ')' && offset) {
// terminate offset
*p = '\0';
break;
}
}
#endif
if (fname && offset && offset && fname < offset)
{
// mangled name is now in [begin_name, begin_offset) and caller
// offset in [begin_offset, end_offset). now apply
// __cxa_demangle():
int status;
char* ret = abi::__cxa_demangle(fname,
funcname, &funcnamesize, &status);
if (status == 0) {
trace->append("\t ");
*trace += module;
trace->append(": ");
*trace += ret; // use possibly realloc()-ed string
trace->append("+");
*trace += offset;
trace->append("\n");
}
else {
// demangling failed. Output function name as a C function with
// no arguments.
trace->append("\t ");
*trace += module;
trace->append(": ");
*trace += fname;
*trace += "()+";
*trace += offset;
trace->append("\n");
}
}
else
{
// couldn't parse the line? print the whole line.
trace->append("\t ");
*trace += symbollist[i];
trace->append("\n");
}
}
free(funcname);
free(symbollist);
#endif
}
private:
std::string m_msg;
std::string m_file;
int m_line;
std::exception* m_cause;
std::string m_stackTrace;
};
#define THROW_BASE_EXCEPTION(msg) throw new BaseException(msg, __FILE__, __LINE__)
#define THROW_BASE_EXCEPTION_CAUSE(msg, cause) throw new BaseException(msg, __FILE__, __LINE__, cause)
/*
/// Construct with file, line info and printf-type arguments.
GenericException(const char *sourcefile, size_t line, const char *format, ...)
__attribute__ ((format (printf, 4, 5)));
*/
/** Base Epics Exception */
class EpicsException : public std::logic_error {
public:
explicit EpicsException(const std::string& arg) :
std::logic_error(arg) {
}
};
}
}
#endif /* EPICSEXCEPTION_H_ */

107
pvDataApp/misc/event.cpp Normal file
View File

@@ -0,0 +1,107 @@
/* event.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <stdexcept>
#include <memory>
#include <vector>
#include <epicsThread.h>
#include <epicsMutex.h>
#include <epicsEvent.h>
#include "noDefaultMethods.h"
#include "pvType.h"
#include "lock.h"
#include "event.h"
namespace epics { namespace pvData {
static volatile int64 totalConstruct = 0;
static volatile int64 totalDestruct = 0;
static Mutex *globalMutex = 0;
static String alreadyOn("already on list");
static int64 getTotalConstruct()
{
Lock xx(globalMutex);
return totalConstruct;
}
static int64 getTotalDestruct()
{
Lock xx(globalMutex);
return totalDestruct;
}
static ConstructDestructCallback *pConstructDestructCallback;
static void init()
{
static Mutex mutex = Mutex();
Lock xx(&mutex);
if(globalMutex==0) {
globalMutex = new Mutex();
pConstructDestructCallback = new ConstructDestructCallback(
String("event"),
getTotalConstruct,getTotalDestruct,0);
}
}
Event::~Event() {
epicsEventDestroy(id);
id = 0;
Lock xx(globalMutex);
totalDestruct++;
}
Event::Event(bool full)
: id(epicsEventCreate(full?epicsEventFull : epicsEventEmpty))
{
init();
Lock xx(globalMutex);
totalConstruct++;
}
ConstructDestructCallback *Event::getConstructDestructCallback()
{
init();
return pConstructDestructCallback;
}
void Event::signal()
{
if(id==0) throw std::logic_error(String("event was deleted"));
epicsEventSignal(id);
}
bool Event::wait ()
{
if(id==0) throw std::logic_error(String("event was deleted"));
epicsEventWaitStatus status = epicsEventWait(id);
return status==epicsEventWaitOK ? true : false;
}
bool Event::wait ( double timeOut )
{
if(id==0) throw std::logic_error(String("event was deleted"));
epicsEventWaitStatus status = epicsEventWaitWithTimeout(id,timeOut);
return status==epicsEventWaitOK ? true : false;
}
bool Event::tryWait ()
{
if(id==0) throw std::logic_error(String("event was deleted"));
epicsEventWaitStatus status = epicsEventTryWait(id);
return status==epicsEventWaitOK ? true : false;
}
}}

33
pvDataApp/misc/event.h Normal file
View File

@@ -0,0 +1,33 @@
/* event.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#ifndef EVENT_H
#define EVENT_H
#include <memory>
#include <vector>
#include <epicsMutex.h>
#include <epicsEvent.h>
#include "noDefaultMethods.h"
#include "pvType.h"
#include "showConstructDestruct.h"
namespace epics { namespace pvData {
class Event : private NoDefaultMethods {
public:
explicit Event(bool = false);
~Event();
static ConstructDestructCallback *getConstructDestructCallback();
void signal();
bool wait (); /* blocks until full */
bool wait ( double timeOut ); /* false if empty at time out */
bool tryWait (); /* false if empty */
private:
epicsEventId id;
};
}}
#endif /* EVENT_H */

187
pvDataApp/misc/executor.cpp Normal file
View File

@@ -0,0 +1,187 @@
/* executor.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <memory>
#include <vector>
#include "linkedList.h"
#include "lock.h"
#include "thread.h"
#include "event.h"
#include "executor.h"
namespace epics { namespace pvData {
static volatile int64 totalConstruct = 0;
static volatile int64 totalDestruct = 0;
static Mutex *globalMutex = 0;
static int64 getTotalConstruct()
{
Lock xx(globalMutex);
return totalConstruct;
}
static int64 getTotalDestruct()
{
Lock xx(globalMutex);
return totalDestruct;
}
static ConstructDestructCallback *pConstructDestructCallback;
static void init() {
static Mutex mutex = Mutex();
Lock xx(&mutex);
if(globalMutex==0) {
globalMutex = new Mutex();
pConstructDestructCallback = new ConstructDestructCallback(
String("executor"),
getTotalConstruct,getTotalDestruct,0);
}
}
typedef LinkedListNode<ExecutorNode> ExecutorListNode;
typedef LinkedList<ExecutorNode> ExecutorList;
class ExecutorNode {
public:
ExecutorNode(Command *command);
~ExecutorNode();
Command *command;
ExecutorListNode *node;
ExecutorListNode *runNode;
};
ExecutorNode::ExecutorNode(Command *command)
: command(command),
node(new ExecutorListNode(this)),
runNode(new ExecutorListNode(this))
{}
ExecutorNode::~ExecutorNode()
{
delete node;
delete runNode;
}
ConstructDestructCallback *Executor::getConstructDestructCallback()
{
init();
return pConstructDestructCallback;
}
class ExecutorPvt : public Runnable{
public:
ExecutorPvt(String threadName,ThreadPriority priority);
~ExecutorPvt();
ExecutorNode * createNode(Command *command);
void execute(ExecutorNode *node);
virtual void run();
private:
ExecutorList *executorList;
ExecutorList *runList;
Event *moreWork;
Event *stopped;
Mutex mutex;
volatile bool alive;
Thread *thread;
};
ExecutorPvt::ExecutorPvt(String threadName,ThreadPriority priority)
: executorList(new ExecutorList()),
runList(new ExecutorList()),
moreWork(new Event(false)),
stopped(new Event(false)),
mutex(Mutex()),
alive(true),
thread(new Thread(threadName,priority,this))
{}
ExecutorPvt::~ExecutorPvt()
{
{
Lock xx(&mutex);
alive = false;
}
moreWork->signal();
{
Lock xx(&mutex);
stopped->wait();
}
ExecutorListNode *node;
while((node=executorList->removeHead())!=0) {
delete node->getObject();
}
delete thread;
delete stopped;
delete moreWork;
delete runList;
delete executorList;
}
void ExecutorPvt::run()
{
while(alive) {
ExecutorListNode * executorListNode = 0;
while(alive && runList->isEmpty()) {
moreWork->wait();
}
if(alive) {
Lock xx(&mutex);
executorListNode = runList->removeHead();
}
if(alive && executorListNode!=0) {
executorListNode->getObject()->command->command();
}
}
stopped->signal();
}
ExecutorNode * ExecutorPvt::createNode(Command *command)
{
Lock xx(&mutex);
ExecutorNode *executorNode = new ExecutorNode(command);
executorList->addTail(executorNode->node);
return executorNode;
}
void ExecutorPvt::execute(ExecutorNode *node)
{
Lock xx(&mutex);
if(!alive || node->runNode->isOnList()) return;
bool isEmpty = runList->isEmpty();
runList->addTail(node->runNode);
if(isEmpty) moreWork->signal();
}
Executor::Executor(String threadName,ThreadPriority priority)
: pImpl(new ExecutorPvt(threadName,priority))
{
init();
Lock xx(globalMutex);
totalConstruct++;
}
Executor::~Executor() {
delete pImpl;
Lock xx(globalMutex);
totalDestruct++;
}
ExecutorNode * Executor::createNode(Command*command)
{return pImpl->createNode(command);}
void Executor::execute(ExecutorNode *node) {pImpl->execute(node);}
}}

37
pvDataApp/misc/executor.h Normal file
View File

@@ -0,0 +1,37 @@
/* executor.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#ifndef EXECUTOR_H
#define EXECUTOR_H
#include <memory>
#include <vector>
#include "noDefaultMethods.h"
#include "pvType.h"
#include "thread.h"
namespace epics { namespace pvData {
// This is created by Executor.createNode and passed to Executor.execute
class ExecutorNode;
class Command {
public:
virtual void command() = 0;
};
class Executor : private NoDefaultMethods {
public:
Executor(String threadName,ThreadPriority priority);
~Executor();
static ConstructDestructCallback *getConstructDestructCallback();
ExecutorNode * createNode(Command *command);
void execute(ExecutorNode *node);
private:
class ExecutorPvt *pImpl;
};
}}
#endif /* EXECUTOR_H */

View File

@@ -0,0 +1,88 @@
/* linkedList.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include "linkedListVoid.h"
namespace epics { namespace pvData {
template <typename T>
class LinkedList;
template <typename T>
class LinkedListNode : private LinkedListVoidNode {
public:
LinkedListNode(T *object) : LinkedListVoidNode(object){}
~LinkedListNode() {}
T *getObject() { return static_cast<T *>(LinkedListVoidNode::getObject());}
bool isOnList() {return LinkedListVoidNode::isOnList();}
friend class LinkedList<T>;
};
template <typename T>
class LinkedList : private LinkedListVoid {
public:
LinkedList() : LinkedListVoid() {}
~LinkedList() {}
int getLength() {return LinkedListVoid::getLength();}
void addTail(LinkedListNode<T> *listNode)
{
LinkedListVoid::addTail(static_cast<LinkedListVoidNode *>(listNode));
}
void addHead(LinkedListNode<T> *listNode)
{
LinkedListVoid::addHead(static_cast<LinkedListVoidNode *>(listNode));
}
void insertAfter(LinkedListNode<T> *listNode,
LinkedListNode<T> *addNode)
{
LinkedListVoid::insertAfter(
static_cast<LinkedListVoidNode *>(listNode),
static_cast<LinkedListVoidNode *>(addNode));
}
void insertBefore(LinkedListNode<T> *listNode,
LinkedListNode<T> *addNode)
{
LinkedListVoid::insertBefore(
static_cast<LinkedListVoidNode *>(listNode),
static_cast<LinkedListVoidNode *>(addNode));
}
LinkedListNode<T> *removeTail(){
return static_cast<LinkedListNode<T> *>(LinkedListVoid::removeTail());
}
LinkedListNode<T> *removeHead(){
return static_cast<LinkedListNode<T> *>(LinkedListVoid::removeHead());
}
void remove(LinkedListNode<T> *listNode){
LinkedListVoid::remove(static_cast<LinkedListVoidNode *>(listNode));
}
void remove(T *object){
LinkedListVoid::remove(object);
}
LinkedListNode<T> *getHead(){
return static_cast<LinkedListNode<T> *>(LinkedListVoid::getHead());
}
LinkedListNode<T> *getTail(){
return static_cast<LinkedListNode<T> *>(LinkedListVoid::getTail());
}
LinkedListNode<T> *getNext(LinkedListNode<T> *listNode){
return static_cast<LinkedListNode<T> *>(LinkedListVoid::getNext(
static_cast<LinkedListVoidNode *>(listNode)));
}
LinkedListNode<T> *getPrev(LinkedListNode<T> *listNode){
return static_cast<LinkedListNode<T> *>(LinkedListVoid::getPrev(
static_cast<LinkedListVoidNode *>(listNode)));
}
bool isEmpty() { return LinkedListVoid::isEmpty();}
bool contains(T *object) { return LinkedListVoid::contains(object);}
};
}}
#endif /* LINKEDLIST_H */

View File

@@ -0,0 +1,300 @@
/* linkedListVoid.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <stdexcept>
#include "lock.h"
#include "pvType.h"
#include "linkedListVoid.h"
namespace epics { namespace pvData {
static volatile int64 totalNodeConstruct = 0;
static volatile int64 totalNodeDestruct = 0;
static volatile int64 totalListConstruct = 0;
static volatile int64 totalListDestruct = 0;
static Mutex *globalMutex = 0;
static String alreadyOnList("already on list");
static int64 getTotalNodeConstruct()
{
Lock xx(globalMutex);
return totalNodeConstruct;
}
static int64 getTotalNodeDestruct()
{
Lock xx(globalMutex);
return totalNodeDestruct;
}
static int64 getTotalListConstruct()
{
Lock xx(globalMutex);
return totalListConstruct;
}
static int64 getTotalListDestruct()
{
Lock xx(globalMutex);
return totalListDestruct;
}
static ConstructDestructCallback *pCDCallbackLinkedListNode;
static ConstructDestructCallback *pCDCallbackLinkedList;
static void initPvt()
{
static Mutex mutex = Mutex();
Lock xx(&mutex);
if(globalMutex==0) {
globalMutex = new Mutex();
pCDCallbackLinkedListNode = new ConstructDestructCallback(
"linkedListNode",
getTotalNodeConstruct,getTotalNodeDestruct,0);
pCDCallbackLinkedList = new ConstructDestructCallback(
"linkedList",
getTotalListConstruct,getTotalListDestruct,0);
}
}
LinkedListVoidNode::LinkedListVoidNode(void *object)
: object(object),before(0),after(0),linkedListVoid(0)
{
initPvt();
Lock xx(globalMutex);
totalNodeConstruct++;
}
LinkedListVoidNode::LinkedListVoidNode(bool isHead)
: object(this),before(this),after(this)
{
initPvt();
Lock xx(globalMutex);
totalNodeConstruct++;
}
LinkedListVoidNode::~LinkedListVoidNode()
{
Lock xx(globalMutex);
totalNodeDestruct++;
}
ConstructDestructCallback *LinkedListVoidNode::getConstructDestructCallback()
{
initPvt();
return pCDCallbackLinkedListNode;
}
void *LinkedListVoidNode::getObject() {
return object;
}
bool LinkedListVoidNode::isOnList()
{
if(before==0 && after==0) return false;
return true;
}
LinkedListVoid::LinkedListVoid()
: head(new LinkedListVoidNode(true)),length(0)
{
initPvt();
Lock xx(globalMutex);
totalListConstruct++;
}
LinkedListVoid::~LinkedListVoid()
{
Lock xx(globalMutex);
delete head;
totalListDestruct++;
}
ConstructDestructCallback *LinkedListVoid::getConstructDestructCallback()
{
initPvt();
return pCDCallbackLinkedList;
}
int LinkedListVoid::getLength()
{
return length;
}
void LinkedListVoid::addTail(LinkedListVoidNode *node)
{
if(node->before!=0 || node->after!=0) {
throw std::logic_error(alreadyOnList);
}
node->linkedListVoid = this;
node->before = head->before;
node->after = head;
head->before->after = node;
head->before = node;
++length;
}
void LinkedListVoid::addHead(LinkedListVoidNode *node)
{
if(node->before!=0 || node->after!=0) {
throw std::logic_error(alreadyOnList);
}
node->linkedListVoid = this;
node->after = head->after;
node->before = head;
head->after->before = node;
head->after = node;
++length;
}
void LinkedListVoid::insertAfter(LinkedListVoidNode *node,
LinkedListVoidNode *addNode)
{
LinkedListVoidNode *existingNode = node;
LinkedListVoidNode *newNode = addNode;
if(existingNode->after==0 || existingNode->before==0) {
throw std::logic_error(String("listNode not on list"));
}
if(newNode->before!=0 || newNode->after!=0) {
throw std::logic_error(alreadyOnList);
}
if(node->linkedListVoid!=this) {
throw std::logic_error(String("node not on this list"));
}
newNode->linkedListVoid = this;
newNode->after = existingNode->after;
newNode->before = existingNode;
existingNode->after->before = newNode;
existingNode->after = newNode;
++length;
}
void LinkedListVoid::insertBefore(LinkedListVoidNode *node,
LinkedListVoidNode *addNode)
{
LinkedListVoidNode *existingNode = node;
LinkedListVoidNode *newNode = addNode;
if(existingNode->after==0 || existingNode->before==0) {
throw std::logic_error(String("listNode not on list"));
}
if(newNode->before!=0 || newNode->after!=0) {
throw std::logic_error(alreadyOnList);
}
if(node->linkedListVoid!=this) {
throw std::logic_error(String("node not on this list"));
}
newNode->linkedListVoid = this;
newNode->after = existingNode;
newNode->before = existingNode->before;
existingNode->before->after = newNode;
existingNode->before = newNode;
++length;
}
LinkedListVoidNode *LinkedListVoid::removeTail()
{
if(head->after==head) return 0;
LinkedListVoidNode *node = head->before;
remove(head->before);
return node;
}
LinkedListVoidNode *LinkedListVoid::removeHead()
{
if(head->after==head) return 0;
LinkedListVoidNode *node = head->after;
remove(head->after);
return node;
}
void LinkedListVoid::remove(LinkedListVoidNode *node)
{
if(node->before==0 || node->after==0) {
throw std::logic_error(String("node not on list"));
}
if(node->linkedListVoid!=this) {
throw std::logic_error(String("node not on this list"));
}
node->linkedListVoid = 0;
LinkedListVoidNode *prev = node->before;
LinkedListVoidNode *next = node->after;
node->after = node->before = 0;
prev->after = next;
next->before = prev;
length--;
}
void LinkedListVoid::remove(void * object)
{
LinkedListVoidNode *node = getHead();
while(node!=0) {
if(node->getObject()==object) {
remove(node);
return;
}
node = getNext(node);
}
throw std::logic_error(String("object not on this list"));
}
LinkedListVoidNode *LinkedListVoid::getHead()
{
if(head->after==head) return 0;
return head->after;
}
LinkedListVoidNode *LinkedListVoid::getTail()
{
if(head->after==head) return 0;
return head->before;
}
LinkedListVoidNode *LinkedListVoid::getNext(LinkedListVoidNode *listNode)
{
if(listNode->linkedListVoid!=this) {
throw std::logic_error(String("node not on this list"));
}
if(listNode->after==head) return 0;
return listNode->after;
}
LinkedListVoidNode *LinkedListVoid::getPrev(LinkedListVoidNode *listNode)
{
if(listNode->linkedListVoid!=this) {
throw std::logic_error(String("node not on this list"));
}
if(listNode->before==head) return 0;
return listNode->before;
}
bool LinkedListVoid::isEmpty()
{
if(head->after==head) return true;
return false;
}
bool LinkedListVoid::contains(void * object)
{
LinkedListVoidNode *node = getHead();
while(node!=0) {
if(node->getObject()==object) {
return true;
}
node = getNext(node);
}
return false;
}
}}

View File

@@ -0,0 +1,73 @@
/* linkedListVoid.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include "pvType.h"
#include "showConstructDestruct.h"
#ifndef LINKEDLISTVOID_H
#define LINKEDLISTVOID_H
namespace epics { namespace pvData {
class LinkedListVoid;
class LinkedListVoidNode;
class LinkedListVoidNode {
public:
~LinkedListVoidNode();
static ConstructDestructCallback *getConstructDestructCallback();
void *getObject();
bool isOnList();
protected:
LinkedListVoidNode(void *object);
private:
LinkedListVoidNode(bool isHead);
friend class LinkedListVoid;
void *object;
LinkedListVoidNode *before;
LinkedListVoidNode *after;
LinkedListVoid *linkedListVoid;
// do not implement the following
LinkedListVoidNode(const LinkedListVoidNode&);
LinkedListVoidNode & operator=(const LinkedListVoidNode&);
};
class LinkedListVoid {
public:
~LinkedListVoid();
static ConstructDestructCallback *getConstructDestructCallback();
int getLength();
void addTail(LinkedListVoidNode *listNode);
void addHead(LinkedListVoidNode *listNode);
void insertAfter(LinkedListVoidNode *listNode,
LinkedListVoidNode *addNode);
void insertBefore(LinkedListVoidNode *listNode,
LinkedListVoidNode *addNode);
LinkedListVoidNode *removeTail();
LinkedListVoidNode *removeHead();
void remove(LinkedListVoidNode *listNode);
void remove(void * object);
LinkedListVoidNode *getHead();
LinkedListVoidNode *getTail();
LinkedListVoidNode *getNext(LinkedListVoidNode *listNode);
LinkedListVoidNode *getPrev(LinkedListVoidNode *listNode);
bool isEmpty();
bool contains(void * object);
protected:
LinkedListVoid();
private:
friend class LinkedListVoidNode;
LinkedListVoidNode *head;
int length;
// do not implement the following
LinkedListVoid(const LinkedListVoid&);
LinkedListVoid & operator=(const LinkedListVoid&);
};
}}
#endif /* LINKEDLISTVOID_H */

38
pvDataApp/misc/lock.h Normal file
View File

@@ -0,0 +1,38 @@
/* lock.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#ifndef LOCK_H
#define LOCK_H
#include <epicsMutex.h>
#include "noDefaultMethods.h"
/* This is based on item 14 of
* Effective C++, Third Edition, Scott Meyers
*/
namespace epics { namespace pvData {
class Mutex {
public:
Mutex() : id(epicsMutexMustCreate()){}
~Mutex() { epicsMutexDestroy(id) ;}
void lock(){epicsMutexMustLock(id);}
void unlock(){epicsMutexUnlock(id);}
private:
epicsMutexId id;
};
class Lock : private NoDefaultMethods {
public:
explicit Lock(Mutex *pm)
: mutexPtr(pm)
{mutexPtr->lock();}
~Lock(){mutexPtr->unlock();}
private:
Mutex *mutexPtr;
};
}}
#endif /* LOCK_H */

View File

@@ -0,0 +1,166 @@
/* messageQueue.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <stdexcept>
#include "pvType.h"
#include "lock.h"
#include "requester.h"
#include "noDefaultMethods.h"
#include "showConstructDestruct.h"
#include "queue.h"
#include "messageQueue.h"
namespace epics { namespace pvData {
static volatile int64 totalQueueConstruct = 0;
static volatile int64 totalQueueDestruct = 0;
static Mutex *globalMutex = 0;
static int64 getTotalQueueConstruct()
{
Lock xx(globalMutex);
return totalQueueConstruct;
}
static int64 getTotalQueueDestruct()
{
Lock xx(globalMutex);
return totalQueueDestruct;
}
static ConstructDestructCallback *pCDCallbackQueue;
static void initPvt()
{
static Mutex mutex = Mutex();
Lock xx(&mutex);
if(globalMutex==0) {
globalMutex = new Mutex();
pCDCallbackQueue = new ConstructDestructCallback(
"messageQueue",
getTotalQueueConstruct,getTotalQueueDestruct,0);
}
}
typedef MessageNode * MessageNodePtr;
typedef QueueElement<MessageNode> MessageElement;
typedef MessageElement *MessageElementPtr;
typedef Queue<MessageNode> MessageNodeQueue;
MessageNode::MessageNode()
: message(String("")),messageType(infoMessage){}
MessageNode::~MessageNode() {}
String MessageNode::getMessage() const { return message;};
MessageType MessageNode::getMessageType() const { return messageType;}
class MessageQueuePvt {
public:
MessageNodePtr *messageNodeArray;
MessageNodeQueue *queue;
MessageNodePtr lastPut;
MessageElementPtr lastGet;
int size;
int overrun;
};
MessageQueue::MessageQueue(int size)
: pImpl(new MessageQueuePvt)
{
initPvt();
Lock xx(globalMutex);
totalQueueConstruct++;
pImpl->size = size;
pImpl->overrun = 0;
pImpl->lastPut = 0;
pImpl->lastGet = 0;
pImpl->messageNodeArray = new MessageNodePtr[size];
for(int i=0; i<size; i++) {
pImpl->messageNodeArray[i] = new MessageNode();
}
pImpl->queue = new MessageNodeQueue(pImpl->messageNodeArray,size);
}
MessageQueue::~MessageQueue()
{
delete pImpl->queue;
for(int i=0; i< pImpl->size; i++) {
delete pImpl->messageNodeArray[i];
}
delete[] pImpl->messageNodeArray;
initPvt();
Lock xx(globalMutex);
totalQueueDestruct++;
}
MessageNode *MessageQueue::get() {
if(pImpl->lastGet!=0) {
throw std::logic_error(
String("MessageQueue::get() but did not release last"));
}
MessageElementPtr element = pImpl->queue->getUsed();
if(element==0) return 0;
pImpl->lastGet = element;
return element->getObject();
}
void MessageQueue::release() {
if(pImpl->lastGet==0) return;
pImpl->queue->releaseUsed(pImpl->lastGet);
pImpl->lastGet = 0;
}
bool MessageQueue::put(String message,MessageType messageType,bool replaceLast)
{
MessageElementPtr element = pImpl->queue->getFree();
if(element!=0) {
MessageNodePtr node = element->getObject();
node->message = message;
node->messageType = messageType;
pImpl->lastPut = node;
pImpl->queue->setUsed(element);
return true;
}
pImpl->overrun++;
if(replaceLast) {
MessageNodePtr node = pImpl->lastPut;
node->message = message;
node->messageType = messageType;
}
return false;
}
bool MessageQueue::isEmpty() const
{
int free = pImpl->queue->getNumberFree();
if(free==pImpl->size) return true;
return false;
}
bool MessageQueue::isFull() const
{
if(pImpl->queue->getNumberFree()==0) return true;
return false;
}
int MessageQueue::getClearOverrun()
{
int num = pImpl->overrun;
pImpl->overrun = 0;
return num;
}
}}

View File

@@ -0,0 +1,49 @@
/* messageQueue.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#ifndef MESSAGEQUEUE_H
#define MESSAGEQUEUE_H
#include "pvType.h"
#include "requester.h"
#include "noDefaultMethods.h"
#include "showConstructDestruct.h"
namespace epics { namespace pvData {
class MessageNode {
public:
String getMessage() const;
MessageType getMessageType() const;
private:
MessageNode();
~MessageNode();
friend class MessageQueue;
String message;
MessageType messageType;
};
class MessageQueue : private NoDefaultMethods {
public:
MessageQueue(int size);
~MessageQueue();
static ConstructDestructCallback *getConstructDestructCallback();
MessageNode *get();
// must call release before next get
void release();
// return (false,true) if message (was not, was) put into queue
bool put(String message,MessageType messageType,bool replaceLast);
bool isEmpty() const;
bool isFull() const;
int getClearOverrun();
private:
class MessageQueuePvt *pImpl;
};
}}
#endif /* MESSAGEQUEUE_H */

View File

@@ -0,0 +1,27 @@
/* noDefaultMethods.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#ifndef NO_DEFAULT_METHODS_H
#define NO_DEFAULT_METHODS_H
namespace epics { namespace pvData {
/* This is based on Item 6 of
* Effective C++, Third Edition, Scott Meyers
*/
class NoDefaultMethods {
protected:
// allow by derived objects
NoDefaultMethods(){};
~NoDefaultMethods(){}
private:
// do not implment
NoDefaultMethods(const NoDefaultMethods&);
NoDefaultMethods & operator=(const NoDefaultMethods &);
};
}}
#endif /* NO_DEFAULT_METHODS_H */

28
pvDataApp/misc/pvType.h Normal file
View File

@@ -0,0 +1,28 @@
/* pvType.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include <string>
#ifndef PVTYPE_H
#define PVTYPE_H
namespace epics { namespace pvData {
typedef signed char int8;
typedef short int16;
typedef int int32;
typedef long long int64;
typedef unsigned int uint32;
typedef unsigned long long uint64;
typedef std::string String;
typedef std::string * StringBuilder;
typedef String* StringArray;
}}
#endif /* PVTYPE_H */

54
pvDataApp/misc/queue.h Normal file
View File

@@ -0,0 +1,54 @@
/* queue.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#ifndef QUEUE_H
#define QUEUE_H
#include "queueVoid.h"
namespace epics { namespace pvData {
template <typename T>
class Queue;
template <typename T>
class QueueElement;
template <typename T>
class QueueElement : private QueueElementVoid {
public:
T *getObject() { return static_cast<T *>(QueueElementVoid::getObject());}
protected:
QueueElement(T *object) : QueueElementVoid(static_cast<void *>(object)){}
~QueueElement() {}
friend class Queue<T>;
};
template <typename T>
class Queue : private QueueVoid {
public:
Queue(T *array[],int number)
: QueueVoid((ObjectPtr*)array,number)
//: QueueVoid(static_cast<ObjectPtr*>(array),number)
{}
~Queue() {}
void clear() {QueueVoid::clear();}
int getNumberFree() {return QueueVoid::getNumberFree();}
int capacity() {return QueueVoid::capacity();}
QueueElement<T> *getFree() {
return static_cast<QueueElement<T> *>(QueueVoid::getFree());}
void setUsed(QueueElement<T> *queueElement) {
QueueVoid::setUsed(static_cast<QueueElementVoid *>(queueElement));}
QueueElement<T> *getUsed() {
return static_cast<QueueElement<T> *>(QueueVoid::getUsed());}
void releaseUsed(QueueElement<T> *queueElement) {
QueueVoid::releaseUsed(static_cast<QueueElementVoid *>(queueElement));}
};
}}
#endif /* QUEUE_H */

View File

@@ -0,0 +1,184 @@
/* queueVoid.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <stdexcept>
#include "lock.h"
#include "pvType.h"
#include "queueVoid.h"
namespace epics { namespace pvData {
static volatile int64 totalElementConstruct = 0;
static volatile int64 totalElementDestruct = 0;
static volatile int64 totalQueueConstruct = 0;
static volatile int64 totalQueueDestruct = 0;
static Mutex *globalMutex = 0;
static int64 getTotalNodeConstruct()
{
Lock xx(globalMutex);
return totalElementConstruct;
}
static int64 getTotalNodeDestruct()
{
Lock xx(globalMutex);
return totalElementDestruct;
}
static int64 getTotalListConstruct()
{
Lock xx(globalMutex);
return totalQueueConstruct;
}
static int64 getTotalListDestruct()
{
Lock xx(globalMutex);
return totalQueueDestruct;
}
static ConstructDestructCallback *pCDCallbackQueueNode;
static ConstructDestructCallback *pCDCallbackQueue;
static void initPvt()
{
static Mutex mutex = Mutex();
Lock xx(&mutex);
if(globalMutex==0) {
globalMutex = new Mutex();
pCDCallbackQueueNode = new ConstructDestructCallback(
"queueElement",
getTotalNodeConstruct,getTotalNodeDestruct,0);
pCDCallbackQueue = new ConstructDestructCallback(
"queue",
getTotalListConstruct,getTotalListDestruct,0);
}
}
QueueElementVoid::QueueElementVoid(ObjectPtr object)
: object(object)
{
initPvt();
Lock xx(globalMutex);
totalElementConstruct++;
}
QueueElementVoid::~QueueElementVoid()
{
Lock xx(globalMutex);
totalElementDestruct++;
}
ConstructDestructCallback *QueueElementVoid::getConstructDestructCallback()
{
initPvt();
return pCDCallbackQueueNode;
}
ObjectPtr QueueElementVoid::getObject() {
return object;
}
QueueVoid::QueueVoid(ObjectPtr object[],int number)
: array(new QueueElementVoidPtr[number]),number(number),
numberFree(number),numberUsed(0),
nextGetFree(0),nextSetUsed(),
nextGetUsed(0),nextReleaseUsed(0)
{
for(int i=0; i<number; i++) {
array[i] = new QueueElementVoid(object[i]);
}
initPvt();
Lock xx(globalMutex);
totalQueueConstruct++;
}
QueueVoid::~QueueVoid()
{
for(int i=0; i<number; i++) {
delete array[i];
}
delete[]array;
Lock xx(globalMutex);
totalQueueDestruct++;
}
ConstructDestructCallback *QueueVoid::getConstructDestructCallback()
{
initPvt();
return pCDCallbackQueue;
}
void QueueVoid::clear()
{
numberFree = number;
numberUsed = 0;
nextGetFree = 0;
nextSetUsed = 0;
nextGetUsed = 0;
nextReleaseUsed = 0;
}
int QueueVoid::getNumberFree()
{
return numberFree;
}
int QueueVoid::capacity()
{
return number;
}
QueueElementVoid * QueueVoid::getFree()
{
if(numberFree==0) return 0;
numberFree--;
QueueElementVoid *queueElement = array[nextGetFree++];
if(nextGetFree>=number) nextGetFree = 0;
return queueElement;
}
void QueueVoid::setUsed(QueueElementVoid *queueElement)
{
if(queueElement!=array[nextSetUsed++]) {
throw std::logic_error(String("not correcect queueElement"));
}
numberUsed++;
if(nextSetUsed>=number) nextSetUsed = 0;
}
QueueElementVoid * QueueVoid::getUsed()
{
if(numberUsed==0) return 0;
QueueElementVoid *queueElement = array[nextGetUsed++];
if(nextGetUsed>=number) nextGetUsed = 0;
return queueElement;
}
void QueueVoid::releaseUsed(QueueElementVoid *queueElement)
{
if(queueElement!=array[nextReleaseUsed++]) {
throw std::logic_error(String(
"not queueElement returned by last call to getUsed"));
}
if(nextReleaseUsed>=number) nextReleaseUsed = 0;
numberUsed--;
numberFree++;
}
}}

View File

@@ -0,0 +1,61 @@
/* queueVoid.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include "showConstructDestruct.h"
#ifndef QUEUEVOID_H
#define QUEUEVOID_H
namespace epics { namespace pvData {
class QueueVoid;
class QueueElementVoid;
typedef void * ObjectPtr;
typedef QueueElementVoid * QueueElementVoidPtr;
typedef QueueElementVoidPtr * QueueElementVoidPtrArray;
class QueueElementVoid {
public:
static ConstructDestructCallback *getConstructDestructCallback();
protected:
ObjectPtr getObject();
QueueElementVoid(ObjectPtr object);
~QueueElementVoid();
ObjectPtr object;
friend class QueueVoid;
};
class QueueVoid {
public:
static ConstructDestructCallback *getConstructDestructCallback();
protected:
QueueVoid(ObjectPtr array[],int number);
~QueueVoid();
void clear();
int getNumberFree();
int capacity();
QueueElementVoidPtr getFree();
void setUsed(QueueElementVoid *queueElement);
QueueElementVoid *getUsed();
void releaseUsed(QueueElementVoid *queueElement);
private:
friend class QueueElementVoid;
QueueElementVoidPtrArray array;
int number;
int numberFree;
int numberUsed;
int nextGetFree;
int nextSetUsed;
int nextGetUsed;
int nextReleaseUsed;
};
}}
#endif /* QUEUEVOID_H */

View File

@@ -0,0 +1,20 @@
/* requester.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include <string>
#include "requester.h"
namespace epics { namespace pvData {
static std::string typeName[] = {
String("info"),
String("warning"),
String("error"),
String("fatalError")
};
StringArray messageTypeName = typeName;
}}

View File

@@ -0,0 +1,28 @@
/* requester.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include <string>
#ifndef REQUESTER_H
#define REQUESTER_H
#include "pvType.h"
namespace epics { namespace pvData {
class Requester;
enum MessageType {
infoMessage,warningMessage,errorMessage,fatalErrorMessage
};
extern StringArray messageTypeName;
class Requester {
public:
virtual String getRequesterName() = 0;
virtual void message(String message,MessageType messageType) = 0;
};
}}
#endif /* REQUESTER_H */

View File

@@ -0,0 +1,54 @@
/* serialize.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#ifndef SERIALIZE_H
#define SERIALIZE_H
#include "bitSet.h"
#include "byteBuffer.h"
namespace epics { namespace pvData {
class SerializableControl;
class DeserializableControl;
class Serializable;
class BitSetSerializable;
class SerializableArray;
class SerializableControl {
public:
virtual void flushSerializeBuffer() =0;
virtual void ensureBuffer(int size) =0;
};
class DeserializableControl {
public:
virtual void ensureData(int size) =0;
};
class Serializable {
public:
virtual void serialize(ByteBuffer *buffer,
SerializableControl *flusher) = 0;
virtual void deserialize(ByteBuffer *buffer,
DeserializableControl *flusher) = 0;
};
class BitSetSerializable {
public:
virtual void serialize(ByteBuffer *buffer,
SerializableControl *flusher,BitSet *bitSet) = 0;
virtual void deserialize(ByteBuffer *buffer,
DeserializableControl *flusher,BitSet *bitSet) = 0;
};
class SerializableArray : public Serializable {
public:
virtual void serialize(ByteBuffer *buffer,
SerializableControl *flusher, int offset, int count) = 0;
};
}}
#endif /* SERIALIZE_H */

View File

@@ -0,0 +1,125 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/*
* serializeHelper.cpp
*
* Created on: Oct 22, 2010
* Author: Miha vitorovic
*/
#include <algorithm>
#include <pvType.h>
#include "epicsException.h"
#include "byteBuffer.h"
#include "serializeHelper.h"
using namespace std;
namespace epics {
namespace pvData {
void SerializeHelper::writeSize(int s, ByteBuffer* buffer,
SerializableControl* flusher) {
flusher->ensureBuffer(sizeof(int64)+1);
SerializeHelper::writeSize(s, buffer);
}
void SerializeHelper::writeSize(int s, ByteBuffer* buffer) {
if(s==-1) // null
buffer->putByte(-1);
else if(s<254)
buffer->putByte(s);
else
buffer->putByte(-2)->putInt(s); // (byte)-2 + size
}
int SerializeHelper::readSize(ByteBuffer* buffer,
DeserializableControl* control) {
control->ensureData(1);
int8 b = buffer->getByte();
if(b==-1)
return -1;
else if(b==-2) {
control->ensureData(sizeof(int32));
int32 s = buffer->getInt();
if(s<0) throw EpicsException("negative array size");
return s;
}
else
return (int)(b<0 ? b+256 : b);
}
void SerializeHelper::serializeString(const String& value,
ByteBuffer* buffer, SerializableControl* flusher) {
int len = value.length();
SerializeHelper::writeSize(len, buffer, flusher);
int i = 0;
while(true) {
int maxToWrite = min(len-i, buffer->getRemaining());
buffer->put(value.data(), i, maxToWrite); // UTF-8
i += maxToWrite;
if(i<len)
flusher->flushSerializeBuffer();
else
break;
}
}
void SerializeHelper::serializeSubstring(const String& value,
int offset, int count, ByteBuffer* buffer,
SerializableControl* flusher) {
if(offset<0)
offset = 0;
else if(offset>(int)value.length()) offset = value.length();
if(offset+count>(int)value.length()) count = value.length()-offset;
SerializeHelper::writeSize(count, buffer, flusher);
int i = 0;
while(true) {
int maxToWrite = min(count-i, buffer->getRemaining());
buffer->put(value.data(), offset+i, maxToWrite); // UTF-8
i += maxToWrite;
if(i<count)
flusher->flushSerializeBuffer();
else
break;
}
}
String SerializeHelper::deserializeString(ByteBuffer* buffer,
DeserializableControl* control) {
int size = SerializeHelper::readSize(buffer, control);
if(size>=0) {
char* retBuffer = new char[size]; // get the return buffer
try {
int i = 0;
while(true) {
int toRead = min(size-i, buffer->getRemaining());
buffer->get(retBuffer, i, toRead);
i += toRead;
if(i<size)
control->ensureData(1);
else
break;
}
String s = String(retBuffer, size);
delete retBuffer;
return s;
} catch(...) {
delete retBuffer; // remove the buffer
throw;
}
}
else
return String("");
}
}
}

View File

@@ -0,0 +1,103 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/*
* serializeHelper.h
*
* Created on: Oct 21, 2010
* Author: Miha Vitorovic
*/
#ifndef SERIALIZEHELPER_H_
#define SERIALIZEHELPER_H_
#include "serialize.h"
#include "byteBuffer.h"
#include "noDefaultMethods.h"
#include "../pv/pvIntrospect.h"
namespace epics {
namespace pvData {
class SerializeHelper : public NoDefaultMethods {
public:
/**
* Serialize array size.
*
* @param[in] s size to encode
* @param[in] buffer serialization buffer
* @param[in] flusher flusher
*/
static void writeSize(int s, ByteBuffer* buffer,
SerializableControl* flusher);
/**
* Deserialize array size.
*
* @param[in] buffer deserialization buffer.
* @returns array size.
*/
static int readSize(ByteBuffer* buffer,
DeserializableControl* control);
/**
* String serialization helper method.
*
* @param[in] value String to serialize
* @param[in] buffer serialization buffer
* @param[in] flusher flusher
*/
static void serializeString(const String& value, ByteBuffer* buffer,
SerializableControl* flusher);
/**
* String serialization helper method.
*
* @param[in] value String to serialize
* @param[in] offset start of the substring in {@code value}
* @param[in] count the number of characters to write
* @param[in] buffer serialization buffer
* @param[in] flusher flusher
*/
static void serializeSubstring(const String& value, int offset,
int count, ByteBuffer* buffer,
SerializableControl* flusher);
/**
* String deserialization helper method.
* TODO This method cannot return "null", but Java implementation
* could have serialized "null" value as well. We need to decide
* how to deserialize "null".
*
* @param[in] buffer deserialization buffer
* @param[in] control control
* @returns deserialized string
*
* @todo This method cannot return "null", but Java implementation
* could have serialized "null" value as well. We need to decide
* how to deserialize "null".
*/
static String deserializeString(ByteBuffer* buffer,
DeserializableControl* control);
private:
SerializeHelper() {};
~SerializeHelper() {};
/**
* Serialize array size.
*
* @param[in] s size to encode
* @param[in] buffer serialization buffer
*/
static void writeSize(int s, ByteBuffer* buffer);
};
}
}
#endif /* SERIALIZEHELPER_H_ */

View File

@@ -0,0 +1,127 @@
/* showConstructDestruct.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <stdexcept>
#include "noDefaultMethods.h"
#include "lock.h"
#include "pvType.h"
#include "linkedList.h"
#include "showConstructDestruct.h"
namespace epics { namespace pvData {
static ShowConstructDestruct *pShowConstructDestruct = 0;
static Mutex *globalMutex = 0;
typedef LinkedListNode<ConstructDestructCallback> ListNode;
typedef LinkedList<ConstructDestructCallback> List;
static List *list;
ConstructDestructCallback::ConstructDestructCallback(
String name,
getTotal construct,
getTotal destruct,
getTotal reference)
: name(name), construct(construct), destruct(destruct) ,reference(reference)
{
getShowConstructDestruct()->registerCallback(this);
}
ConstructDestructCallback::~ConstructDestructCallback() {}
String ConstructDestructCallback::getConstructName()
{
return name;
}
int64 ConstructDestructCallback::getTotalConstruct()
{
return construct();
}
int64 ConstructDestructCallback:: getTotalDestruct()
{
return destruct();
}
int64 ConstructDestructCallback::getTotalReferenceCount()
{
if(reference==0) return 0;
return reference();
}
ShowConstructDestruct::ShowConstructDestruct() {}
void ShowConstructDestruct::constuctDestructTotals(FILE *fd)
{
getShowConstructDestruct(); // make it initialize
Lock xx(globalMutex);
ListNode *node = list->getHead();
while(node!=0) {
ConstructDestructCallback *callback = node->getObject();
String name = callback->getConstructName();
int64 reference = callback->getTotalReferenceCount();
int64 construct = callback->getTotalConstruct();
int64 destruct = callback->getTotalDestruct();
fprintf(fd,"%s: totalConstruct %lli totalDestruct %lli",
name.c_str(),construct,destruct);
if(reference>0) fprintf(fd," totalReference %lli",reference);
fprintf(fd,"\n");
node = list->getNext(node);
}
}
void ShowConstructDestruct::registerCallback(ConstructDestructCallback *callback)
{
static ConstructDestructCallback *listCallback = 0;
static ConstructDestructCallback *listNodeCallback = 0;
Lock xx(globalMutex);
ListNode *listNode = 0;
if(list==0) {
if(callback->getConstructName().compare("linkedListNode")==0) {
listNodeCallback = callback;
} else if(callback->getConstructName().compare("linkedList")==0) {
listCallback = callback;
} else {
throw std::logic_error(String("ShowConstructDestruct::registerCallback"));
}
return;
}
if(listCallback!=0) {
if(listNodeCallback==0) {
throw std::logic_error(String(
"ShowConstructDestruct::registerCallback expected listNodeCallback!=0"));
}
listNode = new ListNode(listNodeCallback);
list->addTail(listNode);
listNode = new ListNode(listCallback);
list->addTail(listNode);
listCallback = 0;
listNodeCallback = 0;
}
listNode = new ListNode(callback);
list->addTail(listNode);
}
ShowConstructDestruct * getShowConstructDestruct()
{
static Mutex mutex = Mutex();
Lock xx(&mutex);
if(pShowConstructDestruct==0) {
globalMutex = new Mutex();
pShowConstructDestruct = new ShowConstructDestruct();
list = new List();
}
return pShowConstructDestruct;
}
}}

View File

@@ -0,0 +1,53 @@
/* showConstructDestruct.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#ifndef SHOWCONSTRUCTDESTRUCT_H
#define SHOWCONSTRUCTDESTRUCT_H
#include <stddef.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include "noDefaultMethods.h"
#include "pvType.h"
namespace epics { namespace pvData {
typedef int64 (*getTotal)();
class ConstructDestructCallback : private NoDefaultMethods {
public:
ConstructDestructCallback(
String name,
getTotal construct,
getTotal destruct,
getTotal reference);
String getConstructName();
int64 getTotalConstruct();
int64 getTotalDestruct();
int64 getTotalReferenceCount();
private:
~ConstructDestructCallback();
String name;
getTotal construct;
getTotal destruct;
getTotal reference;
};
class ShowConstructDestruct : private NoDefaultMethods {
public:
void constuctDestructTotals(FILE *fd);
void registerCallback(ConstructDestructCallback *callback);
private:
ShowConstructDestruct();
friend ShowConstructDestruct* getShowConstructDestruct();
};
extern ShowConstructDestruct* getShowConstructDestruct();
}}
#endif /* SHOWCONSTRUCTDESTRUCT_H */

210
pvDataApp/misc/thread.cpp Normal file
View File

@@ -0,0 +1,210 @@
/* thread.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <stdexcept>
#include <epicsThread.h>
#include <epicsEvent.h>
#include "lock.h"
#include "event.h"
#include "thread.h"
#include "linkedList.h"
namespace epics { namespace pvData {
static unsigned int epicsPriority[] = {
epicsThreadPriorityLow,
epicsThreadPriorityLow + 15,
epicsThreadPriorityMedium - 15,
epicsThreadPriorityMedium,
epicsThreadPriorityMedium + 15,
epicsThreadPriorityHigh - 15,
epicsThreadPriorityHigh
};
unsigned int const * const ThreadPriorityFunc::getEpicsPriorities()
{
return epicsPriority;
}
static String threadPriorityNames[] = {
String("lowest"),String("lower"),String("low"),
String("middle"),
String("high"),String("higher"),String("highest")
};
class ThreadListElement;
typedef LinkedListNode<ThreadListElement> ThreadListNode;
typedef LinkedList<ThreadListElement> ThreadList;
static volatile int64 totalConstruct = 0;
static volatile int64 totalDestruct = 0;
static Mutex *globalMutex = 0;
static ThreadList *threadList;
static int64 getTotalConstruct()
{
Lock xx(globalMutex);
return totalConstruct;
}
static int64 getTotalDestruct()
{
Lock xx(globalMutex);
return totalDestruct;
}
static ConstructDestructCallback *pConstructDestructCallback;
static void init()
{
static Mutex mutex = Mutex();
Lock xx(&mutex);
if(globalMutex==0) {
globalMutex = new Mutex();
threadList = new ThreadList();
pConstructDestructCallback = new ConstructDestructCallback(
String("thread"),
getTotalConstruct,getTotalDestruct,0);
}
}
class ThreadListElement {
public:
ThreadListElement(Thread *thread) : thread(thread),node(new ThreadListNode(this)){}
~ThreadListElement(){delete node;}
Thread *thread;
ThreadListNode *node;
};
int ThreadPriorityFunc::getEpicsPriority(ThreadPriority threadPriority) {
return epicsPriority[threadPriority];
}
extern "C" void myFunc ( void * pPvt );
class ThreadPvt {
public:
ThreadPvt(Thread *thread,String name,
ThreadPriority priority, Runnable*runnable);
virtual ~ThreadPvt();
void ready();
public: // only used within this source module
Thread *thread;
String name;
ThreadPriority priority;
Runnable *runnable;
bool isReady;
ThreadListElement *threadListElement;
Event *waitDone;
epicsThreadId id;
};
extern "C" void myFunc ( void * pPvt )
{
ThreadPvt *threadPvt = (ThreadPvt *)pPvt;
threadPvt->runnable->run();
threadPvt->waitDone->signal();
}
ThreadPvt::ThreadPvt(Thread *thread,String name,
ThreadPriority priority, Runnable *runnable)
: thread(thread),name(name),priority(priority),
runnable(runnable),
isReady(false),
threadListElement(new ThreadListElement(thread)),
waitDone(new Event()),
id(epicsThreadCreate(
name.c_str(),
epicsPriority[priority],
epicsThreadGetStackSize(epicsThreadStackSmall),
myFunc,this))
{
init();
Lock xx(globalMutex);
threadList->addTail(threadListElement->node);
totalConstruct++;
}
ThreadPvt::~ThreadPvt()
{
bool result = waitDone->wait(2.0);
if(!result) {
throw std::logic_error(String("delete thread but run did not return"));
String message("destroy thread ");
message += thread->getName();
message += " but run did not return";
throw std::logic_error(message);
}
if(!threadListElement->node->isOnList()) {
String message("destroy thread ");
message += thread->getName();
message += " is not on threadlist";
throw std::logic_error(message);
}
threadList->remove(threadListElement->node);
delete waitDone;
delete threadListElement;
Lock xx(globalMutex);
totalDestruct++;
}
Thread::Thread(String name,ThreadPriority priority,Runnable *runnable)
: pImpl(new ThreadPvt(this,name,priority,runnable))
{
}
Thread::~Thread()
{
delete pImpl;
}
ConstructDestructCallback *Thread::getConstructDestructCallback()
{
init();
return pConstructDestructCallback;
}
void Thread::sleep(double seconds)
{
epicsThreadSleep(seconds);;
}
String Thread::getName()
{
return pImpl->name;
}
ThreadPriority Thread::getPriority()
{
return pImpl->priority;
}
void Thread::showThreads(StringBuilder buf)
{
init();
Lock xx(globalMutex);
ThreadListNode *node = threadList->getHead();
while(node!=0) {
Thread *thread = node->getObject()->thread;
*buf += thread->getName();
*buf += " ";
*buf += threadPriorityNames[thread->getPriority()];
*buf += "\n";
node = threadList->getNext(node);
}
}
}}

53
pvDataApp/misc/thread.h Normal file
View File

@@ -0,0 +1,53 @@
/* thread.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#ifndef THREAD_H
#define THREAD_H
#include "noDefaultMethods.h"
#include "pvType.h"
#include "showConstructDestruct.h"
namespace epics { namespace pvData {
enum ThreadPriority {
lowestPriority,
lowerPriority,
lowPriority,
middlePriority,
highPriority,
higherPriority,
highestPriority
};
class ThreadPriorityFunc {
public:
static unsigned int const * const getEpicsPriorities();
static int getEpicsPriority(ThreadPriority threadPriority);
};
class Runnable{
public:
virtual void run() = 0;
};
class Thread;
class Thread : private NoDefaultMethods {
public:
Thread(String name,ThreadPriority priority,Runnable *runnable);
~Thread();
static ConstructDestructCallback *getConstructDestructCallback();
String getName();
ThreadPriority getPriority();
static void showThreads(StringBuilder buf);
static void sleep(double seconds);
private:
class ThreadPvt *pImpl;
friend class ThreadPvt;
};
}}
#endif /* THREAD_H */

View File

@@ -0,0 +1,54 @@
/* timeFunction.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include "noDefaultMethods.h"
#include "pvType.h"
#include "timeStamp.h"
namespace epics { namespace pvData {
class TimeFunctionRequester {
public:
virtual void function() = 0;
};
class TimeFunction : private NoDefaultMethods {
public:
TimeFunction(TimeFunctionRequester *requester);
~TimeFunction();
double timeCall();
private:
TimeFunctionRequester *requester;
};
TimeFunction::TimeFunction(TimeFunctionRequester *requester)
: requester(requester) {}
TimeFunction::~TimeFunction() {}
double TimeFunction::timeCall()
{
TimeStamp startTime;
TimeStamp endTime;
double perCall = 0.0;
long ntimes = 1;
while(true) {
startTime.getCurrent();
for(long i=0; i<ntimes; i++) requester->function();
endTime.getCurrent();
double diff = TimeStamp::diff(endTime,startTime);
if(diff>=1.0) {
perCall = diff/(double)ntimes;
break;
}
ntimes *= 2;
}
return perCall;
}
}}

View File

@@ -0,0 +1,30 @@
/* timeFunction.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#ifndef TIMEFUNCTION_H
#define TIMEFUNCTION_H
#include "noDefaultMethods.h"
#include "pvType.h"
namespace epics { namespace pvData {
class TimeFunctionRequester {
public:
virtual void function() = 0;
};
class TimeFunction : private NoDefaultMethods {
public:
TimeFunction(TimeFunctionRequester *requester);
~TimeFunction();
double timeCall();
private:
TimeFunctionRequester *requester;
};
}}
#endif /* TIMEFUNCTION_H */

View File

@@ -0,0 +1,183 @@
/* timeStamp.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <epicsTime.h>
#include "noDefaultMethods.h"
#include "pvType.h"
#include "timeStamp.h"
namespace epics { namespace pvData {
int32 milliSecPerSec = 1000;
int32 microSecPerSec = milliSecPerSec*milliSecPerSec;
int32 nanoSecPerSec = milliSecPerSec*microSecPerSec;
int64 posixEpochAtEpicsEpoch = POSIX_TIME_AT_EPICS_EPOCH;
TimeStamp::TimeStamp(int64 secondsPastEpoch,int32 nanoSeconds)
: secondsPastEpoch(secondsPastEpoch),nanoSeconds(nanoSeconds)
{
normalize();
}
void TimeStamp::normalize()
{
if(nanoSeconds>=0 && nanoSeconds<nanoSecPerSec) return;
while(nanoSeconds>=nanoSecPerSec) {
nanoSeconds -= nanoSecPerSec;
secondsPastEpoch++;
}
while(nanoSeconds<0) {
nanoSeconds += nanoSecPerSec;
secondsPastEpoch--;
}
}
void TimeStamp::fromTime_t(const time_t & tt)
{
epicsTimeStamp epicsTime;
epicsTimeFromTime_t(&epicsTime,tt);
secondsPastEpoch = epicsTime.secPastEpoch + posixEpochAtEpicsEpoch;
nanoSeconds = epicsTime.nsec;
}
void TimeStamp::toTime_t(time_t &tt) const
{
epicsTimeStamp epicsTime;
epicsTime.secPastEpoch = secondsPastEpoch-posixEpochAtEpicsEpoch;
epicsTime.nsec = nanoSeconds;
epicsTimeToTime_t(&tt,&epicsTime);
}
void TimeStamp::put(int64 milliseconds)
{
secondsPastEpoch = milliseconds/1000;
nanoSeconds = (milliseconds%1000)*1000000;
}
void TimeStamp::getCurrent()
{
epicsTimeStamp epicsTime;
epicsTimeGetCurrent(&epicsTime);
secondsPastEpoch = epicsTime.secPastEpoch;
secondsPastEpoch += posixEpochAtEpicsEpoch;
nanoSeconds = epicsTime.nsec;
}
double TimeStamp::toSeconds() const
{
double value = secondsPastEpoch;
double nano = nanoSeconds;
value += nano/1e9;
return value;
}
int64 TimeStamp::diffInt(TimeStamp const & left,TimeStamp const&right )
{
int64 sl = left.secondsPastEpoch;
int32 nl = left.nanoSeconds;
int64 sr = right.secondsPastEpoch;
int32 nr = right.nanoSeconds;
int64 sdiff = sl - sr;
sdiff *= nanoSecPerSec;
sdiff += nl - nr;
return sdiff;
}
bool TimeStamp::operator==(TimeStamp const &right) const
{
int64 sdiff = diffInt(*this,right);
if(sdiff==0) return true;
return false;
}
bool TimeStamp::operator!=(TimeStamp const &right) const
{
int64 sdiff = diffInt(*this,right);
if(sdiff!=0) return true;
return false;
}
bool TimeStamp::operator<=(TimeStamp const &right) const
{
int64 sdiff = diffInt(*this,right);
if(sdiff<=0) return true;
return false;
}
bool TimeStamp::operator< (TimeStamp const &right) const
{
int64 sdiff = diffInt(*this,right);
if(sdiff<0) return true;
return false;
}
bool TimeStamp::operator>=(TimeStamp const &right) const
{
int64 sdiff = diffInt(*this,right);
if(sdiff>=0) return true;
return false;
}
bool TimeStamp::operator>(TimeStamp const &right) const
{
int64 sdiff = diffInt(*this,right);
if(sdiff>0) return true;
return false;
}
double TimeStamp::diff(TimeStamp const & a,TimeStamp const & b)
{
double result = a.secondsPastEpoch - b.secondsPastEpoch;
result += (a.nanoSeconds - b.nanoSeconds)/1e9;
return result;
}
TimeStamp & TimeStamp::operator+=(int64 seconds)
{
secondsPastEpoch += seconds;
return *this;
}
TimeStamp & TimeStamp::operator-=(int64 seconds)
{
secondsPastEpoch -= seconds;
return *this;
}
TimeStamp & TimeStamp::operator+=(double seconds)
{
int64 secs = seconds;
int64 nano = (seconds - secs)*1e9;
nanoSeconds += nano;
if(nanoSeconds>nanoSecPerSec) {
nanoSeconds -= nanoSecPerSec;
secondsPastEpoch += 1;
} else if(nanoSeconds<-nanoSecPerSec) {
nanoSeconds += -nanoSecPerSec;
secondsPastEpoch -= 1;
}
secondsPastEpoch += secs;
return *this;
}
TimeStamp & TimeStamp::operator-=(double seconds)
{
return operator+=(-seconds);
}
int64 TimeStamp::getMilliseconds()
{
return secondsPastEpoch*1000 + nanoSeconds/1000000;
}
}}

View File

@@ -0,0 +1,63 @@
/* timeStamp.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#ifndef TIMESTAMP_H
#define TIMESTAMP_H
#include <ctime>
#include "epicsTime.h"
#include "pvType.h"
namespace epics { namespace pvData {
extern int32 milliSecPerSec;
extern int32 microSecPerSec;
extern int32 nanoSecPerSec;
extern int64 posixEpochAtEpicsEpoch;
class TimeStamp {
public:
TimeStamp()
:secondsPastEpoch(0),nanoSeconds(0) {}
TimeStamp(int64 secondsPastEpoch,int32 nanoSeconds = 0);
//default constructors and destructor are OK
//This class should not be extended
void normalize();
void fromTime_t(const time_t &);
void toTime_t(time_t &) const;
int64 getSecondsPastEpoch() const {return secondsPastEpoch;}
int64 getEpicsSecondsPastEpoch() const {
return secondsPastEpoch - posixEpochAtEpicsEpoch;
}
int32 getNanoSeconds() const {return nanoSeconds;}
void put(int64 secondsPastEpoch,int32 nanoSeconds = 0) {
this->secondsPastEpoch = secondsPastEpoch;
this->nanoSeconds = nanoSeconds;
normalize();
}
void put(int64 milliseconds);
void getCurrent();
double toSeconds() const ;
bool operator==(TimeStamp const &) const;
bool operator!=(TimeStamp const &) const;
bool operator<=(TimeStamp const &) const;
bool operator< (TimeStamp const &) const;
bool operator>=(TimeStamp const &) const;
bool operator> (TimeStamp const &) const;
static double diff(TimeStamp const & a,TimeStamp const & b);
TimeStamp & operator+=(int64 seconds);
TimeStamp & operator-=(int64 seconds);
TimeStamp & operator+=(double seconds);
TimeStamp & operator-=(double seconds);
int64 getMilliseconds(); // milliseconds since epoch
private:
static int64 diffInt(TimeStamp const &left,TimeStamp const &right );
int64 secondsPastEpoch;
int32 nanoSeconds;
};
}}
#endif /* TIMESTAMP_H */

310
pvDataApp/misc/timer.cpp Normal file
View File

@@ -0,0 +1,310 @@
/* timer.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <stdexcept>
#include "pvType.h"
#include "lock.h"
#include "noDefaultMethods.h"
#include "showConstructDestruct.h"
#include "linkedList.h"
#include "thread.h"
#include "timeStamp.h"
#include "timer.h"
#include "event.h"
namespace epics { namespace pvData {
static volatile int64 totalNodeConstruct = 0;
static volatile int64 totalNodeDestruct = 0;
static volatile int64 totalTimerConstruct = 0;
static volatile int64 totalTimerDestruct = 0;
static Mutex *globalMutex = 0;
static int64 getTotalTimerNodeConstruct()
{
Lock xx(globalMutex);
return totalNodeConstruct;
}
static int64 getTotalTimerNodeDestruct()
{
Lock xx(globalMutex);
return totalNodeDestruct;
}
static int64 getTotalTimerConstruct()
{
Lock xx(globalMutex);
return totalTimerConstruct;
}
static int64 getTotalTimerDestruct()
{
Lock xx(globalMutex);
return totalTimerDestruct;
}
static ConstructDestructCallback *pCDCallbackTimerNode;
static ConstructDestructCallback *pCDCallbackTimer;
static void init()
{
static Mutex mutex = Mutex();
Lock xx(&mutex);
if(globalMutex==0) {
globalMutex = new Mutex();
pCDCallbackTimerNode = new ConstructDestructCallback(
"timerNode",
getTotalTimerNodeConstruct,getTotalTimerNodeDestruct,0);
pCDCallbackTimer = new ConstructDestructCallback(
"timer",
getTotalTimerConstruct,getTotalTimerDestruct,0);
}
}
ConstructDestructCallback * TimerNode::getConstructDestructCallback()
{
init();
return pCDCallbackTimerNode;
}
ConstructDestructCallback * Timer::getConstructDestructCallback()
{
init();
return pCDCallbackTimer;
}
class TimerNodePvt;
typedef LinkedListNode<TimerNodePvt> TimerListNode;
typedef LinkedList<TimerNodePvt> TimerList;
class TimerNodePvt {
public:
TimerNode *timerNode;
TimerCallback *callback;
TimerListNode *timerListNode;
TimeStamp timeToRun;
TimerPvt *timerPvt;
double period;
TimerNodePvt(TimerNode *timerNode,TimerCallback *callback);
~TimerNodePvt();
};
TimerNodePvt::TimerNodePvt(TimerNode *timerNode,TimerCallback *callback)
: timerNode(timerNode),callback(callback),
timerListNode(new TimerListNode(this)),timeToRun(TimeStamp()),
timerPvt(0), period(0.0)
{}
TimerNodePvt::~TimerNodePvt()
{
delete timerListNode;
}
struct TimerPvt : public Runnable{
public:
TimerPvt(String threadName,ThreadPriority priority);
~TimerPvt();
virtual void run();
public: // only used by this source module
TimerList *timerList;
Mutex mutex;
Event *waitForWork;
Event *waitForDone;
volatile bool alive;
Thread *thread;
};
TimerPvt::TimerPvt(String threadName,ThreadPriority priority)
: timerList(new TimerList()),
mutex(Mutex()),
waitForWork(new Event(false)),
waitForDone(new Event(false)),
alive(true),
thread(new Thread(threadName,priority,this))
{}
TimerPvt::~TimerPvt()
{
delete thread;
delete waitForDone;
delete waitForWork;
delete timerList;
}
static void addElement(TimerPvt *timer,TimerNodePvt *node)
{
TimerList *timerList = timer->timerList;
TimerListNode *nextNode = timerList->getHead();
if(nextNode==0) {
timerList->addTail(node->timerListNode);
return;
}
while(true) {
TimerNodePvt *timerListNode = nextNode->getObject();
if((node->timeToRun)<(timerListNode->timeToRun)) {
timerList->insertBefore(timerListNode->timerListNode,node->timerListNode);
return;
}
nextNode = timerList->getNext(timerListNode->timerListNode);
if(nextNode==0) {
timerList->addTail(node->timerListNode);
return;
}
}
}
TimerNode::TimerNode(TimerCallback *callback)
: pImpl(new TimerNodePvt(this,callback))
{
init();
Lock xx(globalMutex);
totalNodeConstruct++;
}
TimerNode::~TimerNode()
{
cancel();
delete pImpl;
Lock xx(globalMutex);
totalNodeDestruct++;
}
void TimerNode::cancel()
{
TimerPvt *timerPvt = pImpl->timerPvt;
if(timerPvt==0) return;
Lock xx(&timerPvt->mutex);
if(pImpl->timerPvt==0) return;
pImpl->timerPvt->timerList->remove(pImpl);
pImpl->timerPvt = 0;
}
bool TimerNode::isScheduled()
{
TimerPvt *pvt = pImpl->timerPvt;
if(pvt==0) return false;
Lock xx(&pvt->mutex);
return pImpl->timerListNode->isOnList();
}
void TimerPvt::run()
{
TimeStamp currentTime;
while(alive) {
currentTime.getCurrent();
TimeStamp *timeToRun = 0;
double period = 0.0;
TimerNodePvt *nodeToCall = 0;
{
Lock xx(&mutex);
TimerListNode *timerListNode = timerList->getHead();
if(timerListNode!=0) {
TimerNodePvt *timerNodePvt = timerListNode->getObject();
timeToRun = &timerNodePvt->timeToRun;
double diff = TimeStamp::diff(
*timeToRun,currentTime);
if(diff<=0.0) {
nodeToCall = timerNodePvt;
timerList->removeHead();
period = timerNodePvt->period;
if(period>0.0) {
timerNodePvt->timeToRun += period;
addElement(this,timerNodePvt);
} else {
timerNodePvt->timerPvt = 0;
}
timerListNode = timerList->getHead();
if(timerListNode!=0) {
timerNodePvt = timerListNode->getObject();
timeToRun = &timerNodePvt->timeToRun;
} else {
timeToRun = 0;
}
}
}
}
if(nodeToCall!=0) {
nodeToCall->callback->callback();
}
if(!alive) break;
if(timeToRun==0) {
waitForWork->wait();
} else {
double delay = TimeStamp::diff(*timeToRun,currentTime);
waitForWork->wait(delay);
}
}
waitForDone->signal();
}
Timer::Timer(String threadName, ThreadPriority priority)
: pImpl(new TimerPvt(threadName,priority))
{
init();
Lock xx(globalMutex);
totalTimerConstruct++;
}
Timer::~Timer() {
{
Lock xx(&pImpl->mutex);
pImpl->alive = false;
}
pImpl->waitForWork->signal();
pImpl->waitForDone->wait();
TimerList *timerList = pImpl->timerList;
TimerListNode *node = 0;
while((node = timerList->removeHead())!=0) {
node->getObject()->callback->timerStopped();
}
delete pImpl;
Lock xx(globalMutex);
totalTimerDestruct++;
}
void Timer::scheduleAfterDelay(TimerNode *timerNode,double delay)
{
schedulePeriodic(timerNode,delay,0.0);
}
void Timer::schedulePeriodic(TimerNode *timerNode,double delay,double period)
{
TimerNodePvt *timerNodePvt = timerNode->pImpl;
if(timerNodePvt->timerListNode->isOnList()) {
throw std::logic_error(String("already queued"));
}
if(!pImpl->alive) {
timerNodePvt->callback->timerStopped();
return;
}
TimeStamp *timeStamp = &timerNodePvt->timeToRun;
timeStamp->getCurrent();
*timeStamp += delay;
timerNodePvt->period = period;
bool isFirst = false;
{
Lock xx(&pImpl->mutex);
timerNodePvt->timerPvt = pImpl;
addElement(pImpl,timerNodePvt);
TimerNodePvt *first = pImpl->timerList->getHead()->getObject();
if(first==timerNodePvt) isFirst = true;
}
if(isFirst) pImpl->waitForWork->signal();
}
}}

53
pvDataApp/misc/timer.h Normal file
View File

@@ -0,0 +1,53 @@
/* timer.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#ifndef TIMER_H
#define TIMER_H
#include <stddef.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include "pvType.h"
#include "thread.h"
#include "noDefaultMethods.h"
#include "showConstructDestruct.h"
namespace epics { namespace pvData {
class TimerCallback {
public:
virtual void callback() = 0;
virtual void timerStopped() = 0;
};
class TimerNode : private NoDefaultMethods {
public:
TimerNode(TimerCallback *timerCallback);
~TimerNode();
static ConstructDestructCallback *getConstructDestructCallback();
void cancel();
bool isScheduled();
private:
class TimerNodePvt *pImpl;
friend class Timer;
};
class Timer : private NoDefaultMethods {
public:
Timer(String threadName, ThreadPriority priority);
~Timer();
static ConstructDestructCallback *getConstructDestructCallback();
void scheduleAfterDelay(TimerNode *timerNode,double delay);
void schedulePeriodic(TimerNode *timerNode,double delay,double period);
private:
class TimerPvt *pImpl;
friend class TimerNode;
};
}}
#endif /* TIMER_H */