Merge branch '7.0' into PSI-7.0
This commit is contained in:
@@ -497,7 +497,7 @@ long epicsStdCall asCompute(ASCLIENTPVT asClientPvt)
|
||||
return(status);
|
||||
}
|
||||
|
||||
/*The dump routines do not lock. Thus they may get inconsistant data.*/
|
||||
/*The dump routines do not lock. Thus they may get inconsistent data.*/
|
||||
/*HOWEVER if they did lock and a user interrupts one of then then BAD BAD*/
|
||||
static const char *asAccessName[] = {"NONE","READ","WRITE"};
|
||||
static const char *asTrapOption[] = {"NOTRAPWRITE","TRAPWRITE"};
|
||||
|
||||
@@ -30,8 +30,8 @@ extern "C" {
|
||||
* \brief The message passed to registered listeners.
|
||||
*/
|
||||
typedef struct asTrapWriteMessage {
|
||||
const char *userid; /**< \brief Userid of whoever orginated the request. */
|
||||
const char *hostid; /**< \brief Hostid of whoever orginated the request. */
|
||||
const char *userid; /**< \brief Userid of whoever originated the request. */
|
||||
const char *hostid; /**< \brief Hostid of whoever originated the request. */
|
||||
/** \brief A field for use by the server.
|
||||
*
|
||||
* Any listener that uses this field must know what type of
|
||||
|
||||
@@ -347,7 +347,7 @@ static int bucketAddItem(BUCKET *prb, bucketSET *pBSET, const void *pId, const v
|
||||
assert ((hashid & ~prb->hashIdMask) == 0);
|
||||
ppi = &prb->pTable[hashid];
|
||||
/*
|
||||
* Dont reuse a resource id !
|
||||
* Don't reuse a resource id !
|
||||
*/
|
||||
ppiExists = (*pBSET->pCompare) (ppi, pId);
|
||||
if (ppiExists) {
|
||||
|
||||
@@ -240,6 +240,11 @@ LIBCOM_API long
|
||||
*ptop = floor(*ptop);
|
||||
break;
|
||||
|
||||
case FMOD:
|
||||
top = *ptop--;
|
||||
*ptop = fmod(*ptop, top);
|
||||
break;
|
||||
|
||||
case FINITE:
|
||||
nargs = *pinst++;
|
||||
top = finite(*ptop);
|
||||
@@ -288,7 +293,7 @@ LIBCOM_API long
|
||||
break;
|
||||
|
||||
/* Be VERY careful converting double to int in case bit 31 is set!
|
||||
* Out-of-range errors give very different results on different sytems.
|
||||
* Out-of-range errors give very different results on different systems.
|
||||
* Convert negative doubles to signed and positive doubles to unsigned
|
||||
* first to avoid overflows if bit 32 is set.
|
||||
* The result is always signed, values with bit 31 set are negative
|
||||
|
||||
@@ -104,6 +104,7 @@ static const ELEMENT operands[] = {
|
||||
{"F", 0, 0, 1, OPERAND, FETCH_F},
|
||||
{"FINITE", 7, 8, 0, VARARG_OPERATOR,FINITE},
|
||||
{"FLOOR", 7, 8, 0, UNARY_OPERATOR, FLOOR},
|
||||
{"FMOD", 7, 8, -1, UNARY_OPERATOR, FMOD},
|
||||
{"G", 0, 0, 1, OPERAND, FETCH_G},
|
||||
{"H", 0, 0, 1, OPERAND, FETCH_H},
|
||||
{"I", 0, 0, 1, OPERAND, FETCH_I},
|
||||
|
||||
@@ -122,7 +122,7 @@ extern "C" {
|
||||
* \param perror Place to return an error code
|
||||
* \return Non-zero value in event of error
|
||||
*
|
||||
* It is the callers's responsibility to ensure that \c ppostfix points
|
||||
* It is the caller's responsibility to ensure that \c ppostfix points
|
||||
* to sufficient storage to hold the postfix expression. The macro
|
||||
* INFIX_TO_POSTFIX_SIZE(n) can be used to calculate an appropriate
|
||||
* postfix buffer size from the length of the infix buffer.
|
||||
@@ -203,16 +203,16 @@ extern "C" {
|
||||
* unary minus.
|
||||
*
|
||||
* - Examples:
|
||||
* - e:=a%10;
|
||||
* - d:=a/10%10;
|
||||
* - c:=a/100%10;
|
||||
* - b:=a/1000%10;
|
||||
* - e:=a%10
|
||||
* - d:=a/10%10
|
||||
* - c:=a/100%10
|
||||
* - b:=a/1000%10
|
||||
* - b*4096+c*256+d*16+e
|
||||
* - sqrt(a**2 + b**2)
|
||||
*
|
||||
* -# ***Algebraic Functions***
|
||||
* Various algebraic functions are available which take parameters inside
|
||||
* parentheses. The parameter seperator is a comma.
|
||||
* parentheses. The parameter separator is a comma.
|
||||
*
|
||||
* - Absolute value: abs(a)
|
||||
* - Exponential ea: exp(a)
|
||||
@@ -221,6 +221,8 @@ extern "C" {
|
||||
* - n parameter maximum value: max(a, b, ...)
|
||||
* - n parameter minimum value: min(a, b, ...)
|
||||
* - Square root: sqr(a) or sqrt(a)
|
||||
* - Floating point modulo: fmod(num, den)
|
||||
* \since The fmod() function was added in UNRELEASED
|
||||
*
|
||||
* -# ***Trigonometric Functions***
|
||||
* Standard circular trigonometric functions, with angles expressed in radians:
|
||||
@@ -261,16 +263,21 @@ extern "C" {
|
||||
* - Boolean not: !a
|
||||
*
|
||||
* -# ***Bitwise Operators***
|
||||
* The bitwise operators convert their arguments to an integer (by truncation),
|
||||
* perform the appropriate bitwise operation and convert back to a floating point
|
||||
* value. Unlike in C though, ^ is not a bitwise exclusive-or operator.
|
||||
* Most bitwise operators convert their arguments to 32-bit signed integer (by
|
||||
* truncation), perform the appropriate bitwise operation, then convert back
|
||||
* to a floating point value. The arithmetic right shift operator >> thus
|
||||
* retains the sign bit of the left-hand argument. The logical right shift
|
||||
* operator >>> is performed on an unsigned integer though, so injects zeros
|
||||
* while shifting. The right-hand shift argument is masked so only the lower
|
||||
* 5 bits are used. Unlike in C, ^ is not a bitwise exclusive-or operator.
|
||||
*
|
||||
* - Bitwise and: a & b or a and b
|
||||
* - Bitwise or: a | b or a or b
|
||||
* - Bitwise exclusive or: a xor b
|
||||
* - Bitwise not (ones complement): ~a or not a
|
||||
* - Bitwise left shift: a << b
|
||||
* - Bitwise right shift: a >> b
|
||||
* - Arithmetic left shift: a << b
|
||||
* - Arithmetic right shift: a >> b
|
||||
* - Logical right shift: a >>> b
|
||||
*
|
||||
* -# ***Relational Operators***
|
||||
* Standard numeric comparisons between two values:
|
||||
@@ -291,7 +298,7 @@ extern "C" {
|
||||
* - a < 360 ? a+1 : 0
|
||||
*
|
||||
* -# ***Parentheses***
|
||||
* Sub-expressions can be placed within parentheses to override operator precence rules.
|
||||
* Sub-expressions can be placed within parentheses to override operator presence rules.
|
||||
* Parentheses can be nested to any depth, but the intermediate value stack used by
|
||||
* the expression evaluation engine is limited to 80 results (which require an
|
||||
* expression at least 321 characters long to reach).
|
||||
@@ -323,7 +330,7 @@ LIBCOM_API long
|
||||
* bitmaps which return that information to the caller. Passing a NULL value
|
||||
* for either of these pointers is legal if only the other is needed.
|
||||
*
|
||||
* The least signficant bit (bit 0) of the bitmap at \c *pinputs will be set
|
||||
* The least significant bit (bit 0) of the bitmap at \c *pinputs will be set
|
||||
* if the expression depends on the argument A, and so on through bit 11 for
|
||||
* the argument L. An argument that is not used until after a value has been
|
||||
* assigned to it will not be set in the pinputs bitmap, thus the bits can
|
||||
|
||||
@@ -71,6 +71,7 @@ typedef enum {
|
||||
/* Numeric */
|
||||
CEIL,
|
||||
FLOOR,
|
||||
FMOD,
|
||||
FINITE,
|
||||
ISINF,
|
||||
ISNAN,
|
||||
|
||||
@@ -93,7 +93,7 @@ int cvtFloatToString(float flt_value, char *pdest,
|
||||
|
||||
/* fraction */
|
||||
if (precision > 0){
|
||||
/* convert fractional portional to ASCII */
|
||||
/* convert fractional portion to ASCII */
|
||||
*pdest = '.';
|
||||
pdest++;
|
||||
for (fplace /= 10, i = precision; i > 0; fplace /= 10,i--){
|
||||
@@ -174,7 +174,7 @@ int cvtDoubleToString(
|
||||
|
||||
/* fraction */
|
||||
if (precision > 0){
|
||||
/* convert fractional portional to ASCII */
|
||||
/* convert fractional portion to ASCII */
|
||||
*pdest = '.';
|
||||
pdest++;
|
||||
for (fplace /= 10, i = precision; i > 0; fplace /= 10,i--){
|
||||
|
||||
@@ -8,6 +8,14 @@
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*!
|
||||
* \file epicsGuard.h
|
||||
* \brief Provides classes for RAII style locking and unlocking of mutexes
|
||||
*
|
||||
* Provides classes for RAII style locking and unlocking of mutexes
|
||||
*
|
||||
**/
|
||||
|
||||
#ifndef epicsGuardh
|
||||
#define epicsGuardh
|
||||
|
||||
@@ -21,14 +29,39 @@
|
||||
|
||||
template < class T > class epicsGuardRelease;
|
||||
|
||||
// Automatically applies and releases the mutex.
|
||||
// This class is also useful in situations where
|
||||
// C++ exceptions are possible.
|
||||
/*!
|
||||
* \brief Provides an RAII style lock/unlock of a mutex.
|
||||
*
|
||||
* Provides an RAII style lock/unlock of a mutex. When this object is created,
|
||||
* it attempts to lock the mutex it was given. When control leaves the scope
|
||||
* where this was created, the destructor unlocks the mutex.
|
||||
*
|
||||
* This class is also useful in situations where C++ exceptions are possible.
|
||||
*
|
||||
* Example
|
||||
* =======
|
||||
* \code{.cpp}
|
||||
* epicsMutex mutex;
|
||||
* {
|
||||
* epicsGuard guard(mutex);
|
||||
* printf("mutex is locked")
|
||||
* }
|
||||
* printf("mutex is unlocked\n");
|
||||
* \endcode
|
||||
**/
|
||||
template < class T >
|
||||
class epicsGuard {
|
||||
public:
|
||||
typedef epicsGuardRelease<T> release_t;
|
||||
epicsGuard ( T & );
|
||||
|
||||
/*!
|
||||
* \brief Guard a mutex based on scope.
|
||||
*
|
||||
* Constructs an epicsGuard, locking the mutex for the scope of this object.
|
||||
*
|
||||
* \param mutexIn A mutex-like object to be lock()'ed and unlock()'ed
|
||||
*/
|
||||
epicsGuard ( T & mutexIn);
|
||||
void assertIdenticalMutex ( const T & ) const;
|
||||
~epicsGuard ();
|
||||
private:
|
||||
@@ -38,14 +71,45 @@ private:
|
||||
friend class epicsGuardRelease < T >;
|
||||
};
|
||||
|
||||
// Automatically releases and reapplies the mutex.
|
||||
// This class is also useful in situations where
|
||||
// C++ exceptions are possible.
|
||||
|
||||
/*!
|
||||
* \brief RAII style unlocking of an epicsGuard object
|
||||
*
|
||||
* RAII style unlocking of an epicsGuard object This class can be used while a
|
||||
* epicsGuard is active to temporarily release the mutex and automatically
|
||||
* re-apply the lock when this object goes out of scope.
|
||||
*
|
||||
* This class is also useful in situations where C++ exceptions are possible.
|
||||
*
|
||||
* Example
|
||||
* =======
|
||||
* \code{.cpp}
|
||||
* epicsMutex mutex;
|
||||
* {
|
||||
* epicsGuard guard(mutex);
|
||||
* printf("mutex is locked");
|
||||
* {
|
||||
* epicsGuardRelease grelease(guard);
|
||||
* printf("mutex is unlocked");
|
||||
* }
|
||||
* printf("mutex is locked");
|
||||
* }
|
||||
* printf("mutex is unlocked");
|
||||
* \endcode
|
||||
*
|
||||
*/
|
||||
template < class T >
|
||||
class epicsGuardRelease {
|
||||
public:
|
||||
typedef epicsGuard<T> guard_t;
|
||||
epicsGuardRelease ( epicsGuard < T > & );
|
||||
/*!
|
||||
* \brief Constructs an epicsGuardRelease, unlocking the given epicsGuard
|
||||
*
|
||||
* Constructs an epicsGuardRelease, unlocking the given epicsGuard for the duration of this object.
|
||||
*
|
||||
* \param guardIn The epicsGuard object to be temporarily released.
|
||||
*/
|
||||
epicsGuardRelease ( epicsGuard < T > & guardIn);
|
||||
~epicsGuardRelease ();
|
||||
private:
|
||||
epicsGuard < T > & _guard;
|
||||
@@ -55,11 +119,20 @@ private:
|
||||
};
|
||||
|
||||
// same interface as epicsMutex
|
||||
/*!
|
||||
* \brief Mutex-like object that does nothing.
|
||||
*
|
||||
* This object can be passed into an epicsGuard or similar interface when no actual locking is needed.
|
||||
*/
|
||||
class epicsMutexNOOP {
|
||||
public:
|
||||
//! Does nothing
|
||||
void lock ();
|
||||
//! Does nothing, always returns true.
|
||||
bool tryLock ();
|
||||
//! Does nothing
|
||||
void unlock ();
|
||||
//! Does nothing
|
||||
void show ( unsigned level ) const;
|
||||
};
|
||||
|
||||
|
||||
@@ -21,15 +21,27 @@
|
||||
#include "libComAPI.h"
|
||||
#include "epicsAssert.h"
|
||||
|
||||
class LIBCOM_API SingletonUntyped {
|
||||
class SingletonUntyped {
|
||||
public:
|
||||
SingletonUntyped ();
|
||||
~SingletonUntyped ();
|
||||
SingletonUntyped () :_pInstance ( 0 ), _refCount ( 0 ) {}
|
||||
# if 0
|
||||
~SingletonUntyped () {
|
||||
// we don't assert fail on non-zero _refCount
|
||||
// and or non nill _pInstance here because this
|
||||
// is designed to tolerate situations where
|
||||
// file scope epicsSingleton objects (which
|
||||
// theoretically don't have storage lifespan
|
||||
// issues) are deleted in a non-deterministic
|
||||
// order
|
||||
assert ( _refCount == 0 );
|
||||
assert ( _pInstance == 0 );
|
||||
}
|
||||
# endif
|
||||
typedef void * ( * PBuild ) ();
|
||||
void incrRefCount ( PBuild );
|
||||
LIBCOM_API void incrRefCount ( PBuild );
|
||||
typedef void ( * PDestroy ) ( void * );
|
||||
void decrRefCount ( PDestroy );
|
||||
void * pInstance () const;
|
||||
LIBCOM_API void decrRefCount ( PDestroy );
|
||||
inline void * pInstance () const { return _pInstance; }
|
||||
private:
|
||||
void * _pInstance;
|
||||
std :: size_t _refCount;
|
||||
@@ -46,171 +58,82 @@ class epicsSingleton {
|
||||
public:
|
||||
class reference {
|
||||
public:
|
||||
reference ( epicsSingleton & );
|
||||
reference ( const reference & );
|
||||
~reference ();
|
||||
reference ( epicsSingleton & es)
|
||||
:_pSingleton ( & es )
|
||||
{
|
||||
es._singletonUntyped.
|
||||
incrRefCount ( & epicsSingleton < TYPE > :: _build );
|
||||
}
|
||||
reference ( const reference & ref)
|
||||
:_pSingleton ( ref._pSingleton )
|
||||
{
|
||||
assert ( _pSingleton );
|
||||
_pSingleton->_singletonUntyped.
|
||||
incrRefCount ( & epicsSingleton < TYPE > :: _build );
|
||||
}
|
||||
~reference () {
|
||||
assert ( _pSingleton );
|
||||
_pSingleton->_singletonUntyped.
|
||||
decrRefCount ( & epicsSingleton < TYPE > :: _destroy );
|
||||
}
|
||||
// this somewhat convoluted reference of the return
|
||||
// type ref through the epicsSingleton template is
|
||||
// required for the archaic Tornado gnu compiler
|
||||
typename epicsSingleton < TYPE > :: reference &
|
||||
operator = ( const reference & );
|
||||
TYPE * operator -> ();
|
||||
const TYPE * operator -> () const;
|
||||
TYPE & operator * ();
|
||||
const TYPE & operator * () const;
|
||||
operator = ( const reference & ref) {
|
||||
if ( _pSingleton != ref._pSingleton ) {
|
||||
assert ( _pSingleton );
|
||||
_pSingleton->_singletonUntyped.
|
||||
decrRefCount ( epicsSingleton < TYPE > :: _destroy );
|
||||
_pSingleton = ref._pSingleton;
|
||||
assert ( _pSingleton );
|
||||
_pSingleton->_singletonUntyped.
|
||||
incrRefCount ( & epicsSingleton < TYPE > :: _build );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
TYPE * operator -> () {
|
||||
assert ( _pSingleton );
|
||||
return reinterpret_cast < TYPE * >
|
||||
( _pSingleton->_singletonUntyped.pInstance () );
|
||||
}
|
||||
const TYPE * operator -> () const {
|
||||
assert ( _pSingleton );
|
||||
return reinterpret_cast < const TYPE * >
|
||||
( _pSingleton->_singletonUntyped.pInstance () );
|
||||
}
|
||||
TYPE & operator * () {
|
||||
return * this->operator -> ();
|
||||
}
|
||||
const TYPE & operator * () const {
|
||||
return * this->operator -> ();
|
||||
}
|
||||
private:
|
||||
epicsSingleton * _pSingleton;
|
||||
};
|
||||
friend class reference;
|
||||
epicsSingleton () {}
|
||||
// mutex lock/unlock pair overhead incured
|
||||
// mutex lock/unlock pair overhead incurred
|
||||
// when either of these are called
|
||||
reference getReference ();
|
||||
const reference getReference () const;
|
||||
reference getReference () {
|
||||
return reference ( * this );
|
||||
}
|
||||
const reference getReference () const {
|
||||
epicsSingleton < TYPE > * pConstCastAway =
|
||||
const_cast < epicsSingleton < TYPE > * > ( this );
|
||||
return pConstCastAway->getReference ();
|
||||
}
|
||||
private:
|
||||
SingletonUntyped _singletonUntyped;
|
||||
static void * _build ();
|
||||
static void _destroy ( void * );
|
||||
static void * _build () { return new TYPE (); }
|
||||
static void _destroy ( void * pDestroyTypeless) {
|
||||
TYPE * pDestroy =
|
||||
reinterpret_cast < TYPE * > ( pDestroyTypeless );
|
||||
delete pDestroy;
|
||||
}
|
||||
epicsSingleton ( const epicsSingleton & );
|
||||
epicsSingleton & operator = ( const epicsSingleton & );
|
||||
};
|
||||
|
||||
template < class TYPE >
|
||||
inline epicsSingleton < TYPE > :: reference ::
|
||||
reference ( epicsSingleton & es ):
|
||||
_pSingleton ( & es )
|
||||
{
|
||||
es._singletonUntyped.
|
||||
incrRefCount ( & epicsSingleton < TYPE > :: _build );
|
||||
}
|
||||
|
||||
template < class TYPE >
|
||||
inline epicsSingleton < TYPE > :: reference ::
|
||||
reference ( const reference & ref ) :
|
||||
_pSingleton ( ref._pSingleton )
|
||||
{
|
||||
assert ( _pSingleton );
|
||||
_pSingleton->_singletonUntyped.
|
||||
incrRefCount ( & epicsSingleton < TYPE > :: _build );
|
||||
}
|
||||
|
||||
template < class TYPE >
|
||||
inline epicsSingleton < TYPE > :: reference ::
|
||||
~reference ()
|
||||
{
|
||||
assert ( _pSingleton );
|
||||
_pSingleton->_singletonUntyped.
|
||||
decrRefCount ( & epicsSingleton < TYPE > :: _destroy );
|
||||
}
|
||||
|
||||
template < class TYPE >
|
||||
typename epicsSingleton < TYPE > :: reference &
|
||||
epicsSingleton < TYPE > :: reference ::
|
||||
operator = ( const reference & ref )
|
||||
{
|
||||
if ( _pSingleton != ref._pSingleton ) {
|
||||
assert ( _pSingleton );
|
||||
_pSingleton->_singletonUntyped.
|
||||
decrRefCount ( epicsSingleton < TYPE > :: _destroy );
|
||||
_pSingleton = ref._pSingleton;
|
||||
assert ( _pSingleton );
|
||||
_pSingleton->_singletonUntyped.
|
||||
incrRefCount ( & epicsSingleton < TYPE > :: _build );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template < class TYPE >
|
||||
inline TYPE *
|
||||
epicsSingleton < TYPE > :: reference ::
|
||||
operator -> ()
|
||||
{
|
||||
assert ( _pSingleton );
|
||||
return reinterpret_cast < TYPE * >
|
||||
( _pSingleton->_singletonUntyped.pInstance () );
|
||||
}
|
||||
|
||||
template < class TYPE >
|
||||
inline const TYPE *
|
||||
epicsSingleton < TYPE > :: reference ::
|
||||
operator -> () const
|
||||
{
|
||||
assert ( _pSingleton );
|
||||
return reinterpret_cast < const TYPE * >
|
||||
( _pSingleton->_singletonUntyped.pInstance () );
|
||||
}
|
||||
|
||||
template < class TYPE >
|
||||
inline TYPE &
|
||||
epicsSingleton < TYPE > :: reference ::
|
||||
operator * ()
|
||||
{
|
||||
return * this->operator -> ();
|
||||
}
|
||||
|
||||
template < class TYPE >
|
||||
inline const TYPE &
|
||||
epicsSingleton < TYPE > :: reference ::
|
||||
operator * () const
|
||||
{
|
||||
return * this->operator -> ();
|
||||
}
|
||||
|
||||
inline SingletonUntyped :: SingletonUntyped () :
|
||||
_pInstance ( 0 ), _refCount ( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
inline void * SingletonUntyped :: pInstance () const
|
||||
{
|
||||
return _pInstance;
|
||||
}
|
||||
|
||||
inline SingletonUntyped :: ~SingletonUntyped ()
|
||||
{
|
||||
// we dont assert fail on non-zero _refCount
|
||||
// and or non nill _pInstance here because this
|
||||
// is designed to tolarate situations where
|
||||
// file scope epicsSingleton objects (which
|
||||
// theoretically dont have storage lifespan
|
||||
// issues) are deleted in a non-determanistic
|
||||
// order
|
||||
# if 0
|
||||
assert ( _refCount == 0 );
|
||||
assert ( _pInstance == 0 );
|
||||
# endif
|
||||
}
|
||||
|
||||
template < class TYPE >
|
||||
void * epicsSingleton < TYPE > :: _build ()
|
||||
{
|
||||
return new TYPE ();
|
||||
}
|
||||
|
||||
template < class TYPE >
|
||||
void epicsSingleton < TYPE > ::
|
||||
_destroy ( void * pDestroyTypeless )
|
||||
{
|
||||
TYPE * pDestroy =
|
||||
reinterpret_cast < TYPE * > ( pDestroyTypeless );
|
||||
delete pDestroy;
|
||||
}
|
||||
|
||||
template < class TYPE >
|
||||
inline typename epicsSingleton < TYPE > :: reference
|
||||
epicsSingleton < TYPE > :: getReference ()
|
||||
{
|
||||
return reference ( * this );
|
||||
}
|
||||
|
||||
template < class TYPE >
|
||||
inline const typename epicsSingleton < TYPE > :: reference
|
||||
epicsSingleton < TYPE > :: getReference () const
|
||||
{
|
||||
epicsSingleton < TYPE > * pConstCastAway =
|
||||
const_cast < epicsSingleton < TYPE > * > ( this );
|
||||
return pConstCastAway->getReference ();
|
||||
}
|
||||
|
||||
#endif // epicsSingleton_h
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
# define SIZE_MAX UINT_MAX
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
static epicsThreadOnceId epicsSigletonOnceFlag ( EPICS_THREAD_ONCE_INIT );
|
||||
static epicsMutex * pEPICSSigletonMutex = 0;
|
||||
|
||||
@@ -34,6 +36,8 @@ extern "C" void SingletonMutexOnce ( void * /* pParm */ )
|
||||
pEPICSSigletonMutex = newEpicsMutex;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void SingletonUntyped :: incrRefCount ( PBuild pBuild )
|
||||
{
|
||||
epicsThreadOnce ( & epicsSigletonOnceFlag, SingletonMutexOnce, 0 );
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* indexing is implemented with a hash lookup. The identifier type
|
||||
* implements the hash algorithm (or derives from one of the supplied
|
||||
* identifier types which provide a hashing routine). The table expands
|
||||
* dynamically depending on load, and without introducing non-determanistic
|
||||
* dynamically depending on load, and without introducing non-deterministic
|
||||
* latency.
|
||||
*
|
||||
* Unsigned integer and string identifier classes are supplied here.
|
||||
@@ -86,13 +86,13 @@ public:
|
||||
void removeAll ( tsSLList<T> & destination ); // remove all entries
|
||||
T * lookup ( const ID &idIn ) const; // locate entry
|
||||
// Call (pT->*pCB) () for each entry but expect poor performance
|
||||
// with sparcely populated tables
|
||||
// with sparsely populated tables
|
||||
void traverse ( void (T::*pCB)() );
|
||||
void traverseConst ( void (T::*pCB)() const ) const;
|
||||
unsigned numEntriesInstalled () const;
|
||||
void setTableSize ( const unsigned newTableSize );
|
||||
// iterate through all entries but expect poor performance
|
||||
// with sparcely populated tables
|
||||
// with sparsely populated tables
|
||||
typedef resTableIter < T, ID > iterator;
|
||||
typedef resTableIterConst < T, ID > iteratorConst;
|
||||
iterator firstIter ();
|
||||
@@ -523,7 +523,7 @@ inline unsigned resTable<T,ID>::tableSize () const
|
||||
}
|
||||
}
|
||||
|
||||
// it will be more efficent to call this once prior to installing
|
||||
// it will be more efficient to call this once prior to installing
|
||||
// the first entry
|
||||
template <class T, class ID>
|
||||
void resTable<T,ID>::setTableSize ( const unsigned newTableSize )
|
||||
@@ -550,12 +550,12 @@ void resTable<T,ID>::setTableSize ( const unsigned newTableSize )
|
||||
template <class T, class ID>
|
||||
bool resTable<T,ID>::setTableSizePrivate ( unsigned logBaseTwoTableSizeIn )
|
||||
{
|
||||
// dont shrink
|
||||
// don't shrink
|
||||
if ( this->logBaseTwoTableSize >= logBaseTwoTableSizeIn ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// dont allow ridiculously small tables
|
||||
// don't allow ridiculously small tables
|
||||
if ( logBaseTwoTableSizeIn < 4 ) {
|
||||
logBaseTwoTableSizeIn = 4;
|
||||
}
|
||||
@@ -1036,14 +1036,14 @@ inline resTableIndex integerHash ( unsigned MIN_INDEX_WIDTH,
|
||||
resTableIndex hashid = static_cast <resTableIndex> ( id );
|
||||
|
||||
//
|
||||
// the intent here is to gurantee that all components of the
|
||||
// the intent here is to guarantee that all components of the
|
||||
// integer contribute even if the resTableIndex returned might
|
||||
// index a small table.
|
||||
//
|
||||
// On most compilers the optimizer will unroll this loop so this
|
||||
// is actually a very small inline function
|
||||
//
|
||||
// Experiments using the microsoft compiler show that this isnt
|
||||
// Experiments using the microsoft compiler show that this isn't
|
||||
// slower than switching on the architecture size and unrolling the
|
||||
// loop explicitly (that solution has resulted in portability
|
||||
// problems in the past).
|
||||
@@ -1142,7 +1142,7 @@ stringId::~stringId()
|
||||
// each cast away of const, but in this case
|
||||
// it cant be avoided.
|
||||
//
|
||||
// The DEC compiler complains that const isnt
|
||||
// The DEC compiler complains that const isn't
|
||||
// really significant in a cast if it is present.
|
||||
//
|
||||
// I hope that deleting a pointer to "char"
|
||||
|
||||
@@ -434,7 +434,7 @@ inline void tsDLList<T>::push (T &item)
|
||||
|
||||
//
|
||||
// tsDLList<T>::find ()
|
||||
// returns -1 if the item isnt on the list
|
||||
// returns -1 if the item isn't on the list
|
||||
// and the node number (beginning with zero if
|
||||
// it is)
|
||||
//
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
//
|
||||
// NOTES:
|
||||
//
|
||||
// 1) A NOOP mutex class may be specified if mutual exclusion isnt required
|
||||
// 1) A NOOP mutex class may be specified if mutual exclusion isn't required
|
||||
//
|
||||
// 2) If you wish to force use of the new operator, then declare your class's
|
||||
// destructor as a protected member function.
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
* Author: Jim Kowalkowski and Marty Kraimer
|
||||
* Date: 4/97
|
||||
*
|
||||
* Intended for applications that create and free requently
|
||||
* Intended for applications that create and free frequently
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
*
|
||||
* Routines whin iocCore like dbLoadDatabase() have the following attributes:
|
||||
* - They repeatedly call malloc() followed soon afterwards by a call to
|
||||
* free() the temporaryily allocated storage.
|
||||
* free() the temporarily allocated storage.
|
||||
* - Between those calls to malloc() and free(), additional calls to
|
||||
* malloc() are made that do NOT have an associated free().
|
||||
*
|
||||
|
||||
@@ -39,9 +39,9 @@ void ellAdd (ELLLIST *pList, ELLNODE *pNode)
|
||||
}
|
||||
/****************************************************************************
|
||||
*
|
||||
* This function concatinates the second linked list to the end of the first
|
||||
* This function concatenates the second linked list to the end of the first
|
||||
* list. The second list is left empty. Either list (or both) lists may
|
||||
* be empty at the begining of the operation.
|
||||
* be empty at the beginning of the operation.
|
||||
*
|
||||
*****************************************************************************/
|
||||
void ellConcat (ELLLIST *pDstList, ELLLIST *pAddList)
|
||||
|
||||
@@ -152,6 +152,9 @@ const char* errSymLookupInternal(long status)
|
||||
ERRNUMNODE *pNextNode;
|
||||
ERRNUMNODE **phashnode = NULL;
|
||||
|
||||
if (!status)
|
||||
return "Ok";
|
||||
|
||||
if (!initialized)
|
||||
errSymBld();
|
||||
|
||||
|
||||
@@ -12,6 +12,11 @@
|
||||
* Date: 07JAN1998
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
# define VC_EXTRALEAN
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
@@ -33,6 +38,7 @@
|
||||
#include "errlog.h"
|
||||
#include "epicsStdio.h"
|
||||
#include "epicsExit.h"
|
||||
#include "osiUnistd.h"
|
||||
|
||||
|
||||
#define MIN_BUFFER_SIZE 1280
|
||||
@@ -60,12 +66,13 @@ typedef struct listenerNode{
|
||||
ELLNODE node;
|
||||
errlogListener listener;
|
||||
void *pPrivate;
|
||||
unsigned active:1;
|
||||
unsigned removed:1;
|
||||
} listenerNode;
|
||||
|
||||
typedef struct {
|
||||
char *base;
|
||||
size_t pos;
|
||||
size_t nchar;
|
||||
} buffer_t;
|
||||
|
||||
static struct {
|
||||
@@ -88,12 +95,13 @@ static struct {
|
||||
int atExit;
|
||||
int sevToLog;
|
||||
int toConsole;
|
||||
int ttyConsole;
|
||||
FILE *console;
|
||||
|
||||
/* A loop counter maintained by errlogThread. */
|
||||
epicsUInt32 flushSeq;
|
||||
unsigned long nFlushers;
|
||||
unsigned long nLost;
|
||||
size_t nFlushers;
|
||||
size_t nLost;
|
||||
|
||||
/* 'log' and 'print' combine to form a double buffer. */
|
||||
buffer_t *log;
|
||||
@@ -119,14 +127,9 @@ char* msgbufAlloc(void)
|
||||
|
||||
errlogInit(0);
|
||||
epicsMutexMustLock(pvt.msgQueueLock); /* matched in msgbufCommit() */
|
||||
if(pvt.bufSize - pvt.log->pos - pvt.log->nchar >= 1+pvt.maxMsgSize) {
|
||||
if(pvt.bufSize - pvt.log->pos >= 1+pvt.maxMsgSize) {
|
||||
/* there is enough space for the worst cast */
|
||||
ret = pvt.log->base + pvt.log->pos;
|
||||
if (pvt.log->nchar) {
|
||||
/* append to last message */
|
||||
return ret + 1 + pvt.log->nchar;
|
||||
}
|
||||
/* new message */
|
||||
ret[0] = ERL_STATE_WRITE;
|
||||
ret++;
|
||||
}
|
||||
@@ -144,7 +147,7 @@ size_t msgbufCommit(size_t nchar, int localEcho)
|
||||
int isOkToBlock = epicsThreadIsOkToBlock();
|
||||
int wasEmpty = pvt.log->pos==0;
|
||||
int atExit = pvt.atExit;
|
||||
char *start = pvt.log->base + pvt.log->pos + pvt.log->nchar;
|
||||
char *start = pvt.log->base + pvt.log->pos;
|
||||
|
||||
/* nchar returned by snprintf() is >= maxMsgSize when truncated */
|
||||
if(nchar >= pvt.maxMsgSize) {
|
||||
@@ -163,20 +166,18 @@ size_t msgbufCommit(size_t nchar, int localEcho)
|
||||
*/
|
||||
fprintf(pvt.console, "%s", start);
|
||||
|
||||
} else if (start[nchar] != '\n') {
|
||||
/* incomplete message, prepare to append */
|
||||
pvt.log->nchar += nchar;
|
||||
} else if(!atExit) {
|
||||
start[0u] = ERL_STATE_READY | (localEcho ? ERL_LOCALECHO : 0);
|
||||
|
||||
pvt.log->pos += 1u + nchar + 1u;
|
||||
|
||||
} else {
|
||||
pvt.log->base[pvt.log->pos] = ERL_STATE_READY | (localEcho ? ERL_LOCALECHO : 0);
|
||||
|
||||
pvt.log->pos += 1 + pvt.log->nchar + nchar + 1;
|
||||
pvt.log->nchar = 0;
|
||||
/* listeners will not see messages logged during errlog shutdown */
|
||||
}
|
||||
|
||||
epicsMutexUnlock(pvt.msgQueueLock); /* matched in msgbufAlloc() */
|
||||
|
||||
if(wasEmpty && !atExit && !pvt.log->nchar)
|
||||
if(wasEmpty && !atExit)
|
||||
epicsEventMustTrigger(pvt.waitForWork);
|
||||
|
||||
if(localEcho && isOkToBlock && !atExit)
|
||||
@@ -214,6 +215,103 @@ void errlogSequence(void)
|
||||
epicsEventMustTrigger(pvt.waitForSeq);
|
||||
}
|
||||
|
||||
#if !defined(_WIN32)
|
||||
static
|
||||
int isATTY(FILE* fp)
|
||||
{
|
||||
int ret = 0;
|
||||
const char* term = getenv("TERM");
|
||||
int fd = fileno(fp);
|
||||
|
||||
if(fd>=0 && isatty(fd)==1)
|
||||
ret = 1;
|
||||
/* We don't want to deal with the termcap database,
|
||||
* so assume any non-empty $TERM implies at least some
|
||||
* support for ANSI escapes
|
||||
*/
|
||||
/* only attempt to use ANSI escapes if some terminal type is specified */
|
||||
if(ret && (!term || !term[0]))
|
||||
ret = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else /* _WIN32 */
|
||||
static
|
||||
int isATTY(FILE* fp)
|
||||
{
|
||||
HANDLE hand = NULL;
|
||||
DWORD mode = 0;
|
||||
if(fp==stdout)
|
||||
hand = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
else if(fp==stderr)
|
||||
hand = GetStdHandle(STD_ERROR_HANDLE);
|
||||
#ifdef ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
if(hand && GetConsoleMode(hand, &mode)) {
|
||||
(void)SetConsoleMode(hand, mode|ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
mode = 0u;
|
||||
if(GetConsoleMode(hand, &mode) && (mode&ENABLE_VIRTUAL_TERMINAL_PROCESSING))
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
(void)hand;
|
||||
(void)mode;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* in-place removal of ANSI terminal escape sequences.
|
||||
* exported for use by unit-test only
|
||||
*/
|
||||
LIBCOM_API
|
||||
void errlogStripANSI(char *msg);
|
||||
|
||||
void errlogStripANSI(char *msg)
|
||||
{
|
||||
size_t pos = 0, shift = 0;
|
||||
|
||||
while(1) {
|
||||
char c = msg[pos];
|
||||
|
||||
if(c=='\033') { /* ESC */
|
||||
c = msg[++pos];
|
||||
shift++;
|
||||
|
||||
if(c=='[') {
|
||||
/* CSI escape sequence begins */
|
||||
pos++;
|
||||
shift++;
|
||||
|
||||
/* '\033' '[' [?;0=9]* [A-Za-z]
|
||||
*/
|
||||
while(1) {
|
||||
c = msg[pos];
|
||||
if(c=='?' || c==';' || (c>='0' && c<='9')) {
|
||||
pos++;
|
||||
shift++;
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
c = msg[pos];
|
||||
if((c>='A' && c<='Z') || (c>='a' && c<='z')) {
|
||||
pos++;
|
||||
shift++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(shift)
|
||||
msg[pos-shift] = c = msg[pos];
|
||||
|
||||
if(c=='\0')
|
||||
break;
|
||||
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
int errlogPrintf(const char *pFormat, ...)
|
||||
{
|
||||
int ret;
|
||||
@@ -346,9 +444,15 @@ int errlogRemoveListeners(errlogListener listener, void *pPrivate)
|
||||
listenerNode *pnext = (listenerNode *)ellNext(&plistenerNode->node);
|
||||
|
||||
if (plistenerNode->listener == listener &&
|
||||
plistenerNode->pPrivate == pPrivate) {
|
||||
ellDelete(&pvt.listenerList, &plistenerNode->node);
|
||||
free(plistenerNode);
|
||||
plistenerNode->pPrivate == pPrivate)
|
||||
{
|
||||
if(plistenerNode->active) { /* callback removing itself */
|
||||
plistenerNode->removed = 1;
|
||||
|
||||
} else {
|
||||
ellDelete(&pvt.listenerList, &plistenerNode->node);
|
||||
free(plistenerNode);
|
||||
}
|
||||
++count;
|
||||
}
|
||||
plistenerNode = pnext;
|
||||
@@ -364,6 +468,7 @@ int eltc(int yesno)
|
||||
epicsMutexMustLock(pvt.msgQueueLock);
|
||||
pvt.toConsole = yesno;
|
||||
epicsMutexUnlock(pvt.msgQueueLock);
|
||||
errlogFlush();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -372,6 +477,7 @@ int errlogSetConsole(FILE *stream)
|
||||
errlogInit(0);
|
||||
epicsMutexMustLock(pvt.msgQueueLock);
|
||||
pvt.console = stream ? stream : stderr;
|
||||
pvt.ttyConsole = isATTY(pvt.console);
|
||||
epicsMutexUnlock(pvt.msgQueueLock);
|
||||
/* make sure worker has stopped writing to the previous stream */
|
||||
errlogSequence();
|
||||
@@ -446,6 +552,7 @@ static void errlogInitPvt(void *arg)
|
||||
ellInit(&pvt.listenerList);
|
||||
pvt.toConsole = TRUE;
|
||||
pvt.console = stderr;
|
||||
pvt.ttyConsole = isATTY(stderr);
|
||||
pvt.waitForWork = epicsEventCreate(epicsEventEmpty);
|
||||
pvt.listenerLock = epicsMutexCreate();
|
||||
pvt.msgQueueLock = epicsMutexCreate();
|
||||
@@ -516,12 +623,15 @@ void errlogFlush(void)
|
||||
|
||||
static void errlogThread(void)
|
||||
{
|
||||
int wakeFlusher;
|
||||
epicsMutexMustLock(pvt.msgQueueLock);
|
||||
while (!pvt.atExit) {
|
||||
while (1) {
|
||||
pvt.flushSeq++;
|
||||
|
||||
if(pvt.log->pos==0u) {
|
||||
int wakeFlusher = pvt.nFlushers!=0;
|
||||
if(pvt.atExit)
|
||||
break;
|
||||
wakeFlusher = pvt.nFlushers!=0;
|
||||
epicsMutexUnlock(pvt.msgQueueLock);
|
||||
if(wakeFlusher)
|
||||
epicsEventMustTrigger(pvt.waitForSeq);
|
||||
@@ -530,8 +640,9 @@ static void errlogThread(void)
|
||||
|
||||
} else {
|
||||
/* snapshot and swap buffers for use while unlocked */
|
||||
unsigned long nLost = pvt.nLost;
|
||||
size_t nLost = pvt.nLost;
|
||||
FILE *console = pvt.toConsole ? pvt.console : NULL;
|
||||
int ttyConsole = pvt.ttyConsole;
|
||||
size_t pos = 0u;
|
||||
buffer_t *print;
|
||||
|
||||
@@ -546,8 +657,9 @@ static void errlogThread(void)
|
||||
|
||||
while(pos < print->pos) {
|
||||
listenerNode *plistenerNode;
|
||||
const char* base = print->base + pos;
|
||||
char* base = print->base + pos;
|
||||
size_t mlen = epicsStrnLen(base+1u, pvt.bufSize - pos);
|
||||
int stripped = 0;
|
||||
|
||||
if((base[0]&ERL_STATE_MASK) != ERL_STATE_READY || mlen>=pvt.bufSize - pos) {
|
||||
fprintf(stderr, "Logic Error: errlog buffer corruption. %02x, %zu\n",
|
||||
@@ -557,14 +669,32 @@ static void errlogThread(void)
|
||||
}
|
||||
|
||||
if(base[0]&ERL_LOCALECHO && console) {
|
||||
if(!ttyConsole) {
|
||||
errlogStripANSI(base+1u);
|
||||
stripped = 1;
|
||||
}
|
||||
fprintf(console, "%s", base+1u);
|
||||
}
|
||||
|
||||
if(!stripped)
|
||||
errlogStripANSI(base+1u);
|
||||
|
||||
epicsMutexMustLock(pvt.listenerLock);
|
||||
plistenerNode = (listenerNode *)ellFirst(&pvt.listenerList);
|
||||
while (plistenerNode) {
|
||||
listenerNode *next;
|
||||
|
||||
plistenerNode->active = 1;
|
||||
(*plistenerNode->listener)(plistenerNode->pPrivate, base+1u);
|
||||
plistenerNode = (listenerNode *)ellNext(&plistenerNode->node);
|
||||
plistenerNode->active = 0;
|
||||
|
||||
next = (listenerNode *)ellNext(&plistenerNode->node);
|
||||
if(plistenerNode->removed) {
|
||||
/* listener() called errlogRemoveListeners() */
|
||||
ellDelete(&pvt.listenerList, &plistenerNode->node);
|
||||
free(plistenerNode);
|
||||
}
|
||||
plistenerNode = next;
|
||||
}
|
||||
epicsMutexUnlock(pvt.listenerLock);
|
||||
|
||||
@@ -575,7 +705,7 @@ static void errlogThread(void)
|
||||
print->pos = 0u;
|
||||
|
||||
if(nLost && console)
|
||||
fprintf(console, "errlog: lost %lu messages\n", nLost);
|
||||
fprintf(console, "errlog: lost %zu messages\n", nLost);
|
||||
|
||||
if(console)
|
||||
fflush(console);
|
||||
@@ -584,5 +714,8 @@ static void errlogThread(void)
|
||||
|
||||
}
|
||||
}
|
||||
wakeFlusher = pvt.nFlushers!=0;
|
||||
epicsMutexUnlock(pvt.msgQueueLock);
|
||||
if(wakeFlusher)
|
||||
epicsEventMustTrigger(pvt.waitForSeq);
|
||||
}
|
||||
|
||||
@@ -15,14 +15,14 @@
|
||||
* \brief Functions for interacting with the errlog task
|
||||
*
|
||||
* This file contains functions for passing error messages with varying severity,
|
||||
* registering and un-registering listeners and modifying the log buffer size and
|
||||
* registering and un-registering listeners and modifying the log buffer size and
|
||||
* max message size.
|
||||
*
|
||||
* Some of these functions are similar to the standard C library functions printf
|
||||
* and vprintf. For details on the arguments and return codes it is useful to consult
|
||||
* any book that describes the standard C library such as
|
||||
* and vprintf. For details on the arguments and return codes it is useful to consult
|
||||
* any book that describes the standard C library such as
|
||||
* `The C Programming Language ANSI C Edition` by Kernighan and Ritchie.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
@@ -37,9 +37,9 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* errlogListener function type.
|
||||
*
|
||||
* This is used when adding or removing log listeners in ::errlogAddListener
|
||||
* errlogListener function type.
|
||||
*
|
||||
* This is used when adding or removing log listeners in ::errlogAddListener
|
||||
* and ::errlogRemoveListeners.
|
||||
*/
|
||||
typedef void (*errlogListener)(void *pPrivate, const char *message);
|
||||
@@ -52,6 +52,7 @@ typedef enum {
|
||||
errlogFatal
|
||||
} errlogSevEnum;
|
||||
|
||||
/** Boolean to control whether some messages include more detail */
|
||||
LIBCOM_API extern int errVerbose;
|
||||
|
||||
|
||||
@@ -63,24 +64,27 @@ LIBCOM_API extern int errVerbose;
|
||||
"fatal"
|
||||
};
|
||||
#else
|
||||
/** String representation of errlog severity values */
|
||||
LIBCOM_API extern const char * errlogSevEnumString[];
|
||||
#endif
|
||||
|
||||
/**
|
||||
* errMessage is a macro so it can get the file and line number. It prints the message,
|
||||
* the status symbol and string values, and the name of the task which invoked errMessage.
|
||||
* It also prints the name of the source file and the line number from which the call was issued.
|
||||
/**
|
||||
* errMessage is a macro so it can get the file and line number. It prints the message,
|
||||
* the status symbol and string values, and the name of the task which invoked errMessage.
|
||||
* It also prints the name of the source file and the line number from which the call was issued.
|
||||
*
|
||||
* The message to print should not include a newline as one is added implicitly.
|
||||
*
|
||||
* The status code used for the 1st argument is:
|
||||
* - 0: Find latest vxWorks or Unix error (errno value).
|
||||
* - -1: Don’t report status.
|
||||
* - Other: Use this status code and lookup the string value
|
||||
* - -1: Don't report status.
|
||||
* - Other: Use this status code and lookup the string value
|
||||
*
|
||||
* \param S Status code
|
||||
* \param PM The message to print
|
||||
*/
|
||||
#define errMessage(S, PM) \
|
||||
errPrintf(S, __FILE__, __LINE__, "%s", PM)
|
||||
errPrintf(S, __FILE__, __LINE__, " %s\n", PM)
|
||||
|
||||
/** epicsPrintf is an old name for errlog routines */
|
||||
#define epicsPrintf errlogPrintf
|
||||
@@ -90,58 +94,58 @@ LIBCOM_API extern int errVerbose;
|
||||
|
||||
/**
|
||||
* errlogPrintf is like the printf function provided by the standard C library, except
|
||||
* that the output is sent to the errlog task. Unless configured not to, the output
|
||||
* will appear on the console as well.
|
||||
* that the output is sent to the errlog task. Unless configured not to, the output
|
||||
* will appear on the console as well.
|
||||
*/
|
||||
LIBCOM_API int errlogPrintf(const char *pformat, ...)
|
||||
EPICS_PRINTF_STYLE(1,2);
|
||||
|
||||
/**
|
||||
* errlogVprintf is like the vprintf function provided by the standard C library, except
|
||||
* that the output is sent to the errlog task. Unless configured not to, the output
|
||||
* will appear on the console as well.
|
||||
* that the output is sent to the errlog task. Unless configured not to, the output
|
||||
* will appear on the console as well.
|
||||
*/
|
||||
LIBCOM_API int errlogVprintf(const char *pformat, va_list pvar);
|
||||
|
||||
/**
|
||||
* This function is like ::errlogPrintf except that it adds the severity to the beginning
|
||||
* of the message in the form `sevr=<value>` where value is one of the enumerated
|
||||
* severities in ::errlogSevEnum. Also the message is suppressed if severity is less than
|
||||
* the current severity to suppress.
|
||||
*
|
||||
* This function is like ::errlogPrintf except that it adds the severity to the beginning
|
||||
* of the message in the form `sevr=<value>` where value is one of the enumerated
|
||||
* severities in ::errlogSevEnum. Also the message is suppressed if severity is less than
|
||||
* the current severity to suppress.
|
||||
*
|
||||
* \param severity One of the severity enums from ::errlogSevEnum
|
||||
* \param pFormat The message to log or print
|
||||
* \return int Consult printf documentation in C standard library
|
||||
* \param pformat The message to log or print
|
||||
* \return int Consult printf documentation in C standard library
|
||||
*/
|
||||
LIBCOM_API int errlogSevPrintf(const errlogSevEnum severity,
|
||||
const char *pformat, ...) EPICS_PRINTF_STYLE(2,3);
|
||||
|
||||
/**
|
||||
* This function is like ::errlogVprintf except that it adds the severity to the beginning
|
||||
* of the message in the form `sevr=<value>` where value is one of the enumerated
|
||||
* severities in ::errlogSevEnum. Also the message is suppressed if severity is less than
|
||||
* the current severity to suppress. If epicsThreadIsOkToBlock is true, which is
|
||||
* This function is like ::errlogVprintf except that it adds the severity to the beginning
|
||||
* of the message in the form `sevr=<value>` where value is one of the enumerated
|
||||
* severities in ::errlogSevEnum. Also the message is suppressed if severity is less than
|
||||
* the current severity to suppress. If epicsThreadIsOkToBlock is true, which is
|
||||
* true during iocInit, errlogSevVprintf does NOT send output to the
|
||||
* errlog task.
|
||||
*
|
||||
*
|
||||
* \param severity One of the severity enums from ::errlogSevEnum
|
||||
* \param pFormat The message to log or print
|
||||
* \param pformat The message to log or print
|
||||
* \param pvar va_list
|
||||
* \return int Consult printf documentation in C standard library
|
||||
* \return int Consult printf documentation in C standard library
|
||||
*/
|
||||
LIBCOM_API int errlogSevVprintf(const errlogSevEnum severity,
|
||||
const char *pformat, va_list pvar);
|
||||
|
||||
/**
|
||||
/**
|
||||
* Sends message to the errlog task.
|
||||
*
|
||||
*
|
||||
* \param message The message to send
|
||||
*/
|
||||
LIBCOM_API int errlogMessage(const char *message);
|
||||
|
||||
/**
|
||||
* Gets the string value of severity.
|
||||
*
|
||||
*
|
||||
* \param severity The severity from ::errlogSevEnum
|
||||
* \return The string value
|
||||
*/
|
||||
@@ -174,13 +178,16 @@ LIBCOM_API void errlogAddListener(errlogListener listener, void *pPrivate);
|
||||
*
|
||||
* \param listener Function pointer of type ::errlogListener
|
||||
* \param pPrivate This will be passed as the first argument of listener()
|
||||
*
|
||||
* \since UNRELEASED Safe to call from a listener callback.
|
||||
* \until UNRELEASED Self-removal from a listener callback caused corruption.
|
||||
*/
|
||||
LIBCOM_API int errlogRemoveListeners(errlogListener listener,
|
||||
void *pPrivate);
|
||||
|
||||
/**
|
||||
* Normally the errlog system displays all messages on the console.
|
||||
* During error message storms this function can be used to suppress console messages.
|
||||
* During error message storms this function can be used to suppress console messages.
|
||||
* A argument of 0 suppresses the messages, any other value lets messages go to the console.
|
||||
*
|
||||
* \param yesno (0=No, 1=Yes)
|
||||
@@ -197,39 +204,40 @@ LIBCOM_API int eltc(int yesno);
|
||||
LIBCOM_API int errlogSetConsole(FILE *stream);
|
||||
|
||||
/**
|
||||
* Can be used to initialize the error logging system with a larger buffer. The default buffer size is 1280 bytes.
|
||||
* Can be used to initialize the error logging system with a larger buffer. The default buffer size is 1280 bytes.
|
||||
*
|
||||
* \param bufsize The desired buffer size
|
||||
*/
|
||||
LIBCOM_API int errlogInit(int bufsize);
|
||||
|
||||
/**
|
||||
* errlogInit2 can be used to initialize the error logging system with a larger buffer and maximum message size.
|
||||
* The default buffer size is 1280 bytes, and the default maximum message size is 256.
|
||||
* errlogInit2 can be used to initialize the error logging system with a larger buffer and maximum message size.
|
||||
* The default buffer size is 1280 bytes, and the default maximum message size is 256.
|
||||
*
|
||||
* \param bufsize The desired buffer size
|
||||
* \param maxMsgSize The desired max message size
|
||||
*/
|
||||
LIBCOM_API int errlogInit2(int bufsize, int maxMsgSize);
|
||||
|
||||
/** Wakes up the errlog task and then waits until all messages are flushed from the queue. */
|
||||
/** Wakes up the errlog task and then waits until all messages are flushed from the queue. */
|
||||
LIBCOM_API void errlogFlush(void);
|
||||
|
||||
/**
|
||||
* Routine errPrintf is normally called as follows:
|
||||
* `errPrintf(status, __FILE__, __LINE__,"<fmt>",...); `
|
||||
*
|
||||
* Where status is defined as:
|
||||
* `errPrintf(status, __FILE__, __LINE__, "<fmt>", ...); `
|
||||
*
|
||||
* Where status is defined as:
|
||||
* - 0: Find latest vxWorks or Unix error.
|
||||
* - -1: Don’t report status.
|
||||
* - Other: Use this status code and lookup the string value
|
||||
*
|
||||
* - -1: Don't report status.
|
||||
* - Other: Use this status code and lookup the string value
|
||||
*
|
||||
* \param status See above
|
||||
* \param __FILE__ As shown or NULL if the file name and line number should not be printed.
|
||||
* \param __LINE__ As shown
|
||||
*
|
||||
* The remaining arguments are just like the arguments to the C printf routine.
|
||||
* ::errVerbose determines if the filename and line number are shown.
|
||||
* \param pFileName As shown or NULL if the file name and line number should not be printed.
|
||||
* \param lineno As shown
|
||||
* \param pformat The message to log or print
|
||||
*
|
||||
* The remaining arguments are just like the arguments to the C printf routine.
|
||||
* ::errVerbose determines if the filename and line number are shown.
|
||||
*/
|
||||
LIBCOM_API void errPrintf(long status, const char *pFileName, int lineno,
|
||||
const char *pformat, ...) EPICS_PRINTF_STYLE(4,5);
|
||||
@@ -247,6 +255,44 @@ LIBCOM_API int errlogVprintfNoConsole(const char *pformat,va_list pvar);
|
||||
*/
|
||||
LIBCOM_API void errSymLookup(long status, char *pBuf, size_t bufLength);
|
||||
|
||||
/** @defgroup colormacros Color macros
|
||||
*
|
||||
* @brief Colorize string constants with ANSI terminal escapes.
|
||||
*
|
||||
* The ANSI_ESC_\* family of macros expand to individual escape sequences.
|
||||
* The ANSI_\* family expand around a string constant to prepend a color, and append a RESET.
|
||||
*
|
||||
* @code
|
||||
* // equivalent
|
||||
* errlogPrintf(ERL_ERROR ": something is amiss\n");
|
||||
* errlogPrintf(ANSI_RED("ERROR") ": something is amiss\n");
|
||||
* errlogPrintf(ANSI_ESC_RED "ERROR" ANSI_ESC_RESET ": something is amiss\n");
|
||||
* @endcode
|
||||
*
|
||||
* @since EPICS 7.0.7
|
||||
*
|
||||
* @see errlogPrintf()
|
||||
* @{
|
||||
*/
|
||||
#define ANSI_ESC_RED "\033[31;1m"
|
||||
#define ANSI_ESC_GREEN "\033[32;1m"
|
||||
#define ANSI_ESC_YELLOW "\033[33;1m"
|
||||
#define ANSI_ESC_BLUE "\033[34;1m"
|
||||
#define ANSI_ESC_MAGENTA "\033[35;1m"
|
||||
#define ANSI_ESC_CYAN "\033[36;1m"
|
||||
#define ANSI_ESC_BOLD "\033[1m"
|
||||
#define ANSI_ESC_RESET "\033[0m"
|
||||
#define ANSI_RED(STR) ANSI_ESC_RED STR ANSI_ESC_RESET
|
||||
#define ANSI_GREEN(STR) ANSI_ESC_GREEN STR ANSI_ESC_RESET
|
||||
#define ANSI_YELLOW(STR) ANSI_ESC_YELLOW STR ANSI_ESC_RESET
|
||||
#define ANSI_BLUE(STR) ANSI_ESC_BLUE STR ANSI_ESC_RESET
|
||||
#define ANSI_MAGENTA(STR) ANSI_ESC_MAGENTA STR ANSI_ESC_RESET
|
||||
#define ANSI_CYAN(STR) ANSI_ESC_CYAN STR ANSI_ESC_RESET
|
||||
#define ANSI_BOLD(STR) ANSI_ESC_BOLD STR ANSI_ESC_RESET
|
||||
#define ERL_ERROR ANSI_RED("ERROR")
|
||||
#define ERL_WARNING ANSI_MAGENTA("WARNING")
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -159,7 +159,7 @@ LIBCOM_API void fdManager::process (double delay)
|
||||
if (this->pCBReg != NULL) {
|
||||
//
|
||||
// check only after we see that it is non-null so
|
||||
// that we dont trigger bounds-checker dangling pointer
|
||||
// that we don't trigger bounds-checker dangling pointer
|
||||
// error
|
||||
//
|
||||
assert (this->pCBReg==pReg);
|
||||
@@ -177,8 +177,8 @@ LIBCOM_API void fdManager::process (double delay)
|
||||
else if ( status < 0 ) {
|
||||
int errnoCpy = SOCKERRNO;
|
||||
|
||||
// dont depend on flags being properly set if
|
||||
// an error is retuned from select
|
||||
// don't depend on flags being properly set if
|
||||
// an error is returned from select
|
||||
for ( size_t i = 0u; i < fdrNEnums; i++ ) {
|
||||
FD_ZERO ( &fdSetsPtr[i] );
|
||||
}
|
||||
|
||||
@@ -318,7 +318,7 @@ extern "C" LIBCOM_API int epicsStdCall fdmgr_delete (fdctx *pfdctx)
|
||||
}
|
||||
|
||||
/*
|
||||
* depricated interface
|
||||
* deprecated interface
|
||||
*/
|
||||
extern "C" LIBCOM_API int epicsStdCall fdmgr_clear_fd (fdctx *pfdctx, SOCKET fd)
|
||||
{
|
||||
@@ -326,7 +326,7 @@ extern "C" LIBCOM_API int epicsStdCall fdmgr_clear_fd (fdctx *pfdctx, SOCKET fd)
|
||||
}
|
||||
|
||||
/*
|
||||
* depricated interface
|
||||
* deprecated interface
|
||||
*/
|
||||
extern "C" LIBCOM_API int epicsStdCall fdmgr_add_fd (
|
||||
fdctx *pfdctx, SOCKET fd, void (*pfunc)(void *pParam), void *param)
|
||||
|
||||
@@ -117,7 +117,7 @@ void *param /* first parameter passed to the func */
|
||||
|
||||
/*
|
||||
*
|
||||
* Clear nterest in a type of file descriptor activity (IO).
|
||||
* Clear interest in a type of file descriptor activity (IO).
|
||||
*
|
||||
*/
|
||||
LIBCOM_API int epicsStdCall fdmgr_clear_callback(
|
||||
|
||||
@@ -128,7 +128,7 @@ void check_trailing_context(int *nfa_states, int num_states, int *accset, int na
|
||||
|
||||
/* dump_associated_rules - list the rules associated with a DFA state
|
||||
*
|
||||
* synopisis
|
||||
* synopsis
|
||||
* int ds;
|
||||
* FILE *file;
|
||||
* dump_associated_rules( file, ds );
|
||||
@@ -179,7 +179,7 @@ void dump_associated_rules(FILE *file, int ds)
|
||||
|
||||
/* dump_transitions - list the transitions associated with a DFA state
|
||||
*
|
||||
* synopisis
|
||||
* synopsis
|
||||
* int state[numecs];
|
||||
* FILE *file;
|
||||
* dump_transitions( file, state );
|
||||
@@ -449,7 +449,7 @@ void ntod(void)
|
||||
* since for them we don't have a simple state number lying around with
|
||||
* which to index the table. We also don't bother doing it for scanners
|
||||
* unless (1) NUL is in its own equivalence class (indicated by a
|
||||
* positive value of ecgroup[NUL]), (2) NUL's equilvalence class is
|
||||
* positive value of ecgroup[NUL]), (2) NUL's equivalence class is
|
||||
* the last equivalence class, and (3) the number of equivalence classes
|
||||
* is the same as the number of characters. This latter case comes about
|
||||
* when useecs is false or when its true but every character still
|
||||
|
||||
@@ -602,7 +602,7 @@ void *reallocate_array(void *array, int size, int element_size);
|
||||
#define reallocate_character_array(array,size) \
|
||||
(Char *) reallocate_array( (void *) array, size, sizeof( Char ) )
|
||||
|
||||
#if 0 /* JRW this might couse truuble... but not for IOC usage */
|
||||
#if 0 /* JRW this might couse trouble... but not for IOC usage */
|
||||
/* used to communicate between scanner and parser. The type should really
|
||||
* be YYSTYPE, but we can't easily get our hands on it.
|
||||
*/
|
||||
|
||||
@@ -16,3 +16,6 @@ Com_SRCS += iocsh.cpp
|
||||
Com_SRCS += initHooks.c
|
||||
Com_SRCS += registry.c
|
||||
Com_SRCS += libComRegister.c
|
||||
|
||||
iocsh_CXXFLAGS += -DEPICS_COMMANDLINE_LIBRARY=EPICS_COMMANDLINE_LIBRARY_$(COMMANDLINE_LIBRARY)
|
||||
iocsh_INCLUDES += $(INCLUDES_$(COMMANDLINE_LIBRARY))
|
||||
|
||||
@@ -7,12 +7,46 @@
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* Authors: Benjamin Franksen (BESY) and Marty Kraimer
|
||||
* Date: 06-01-91
|
||||
* major Revision: 07JuL97
|
||||
|
||||
/**
|
||||
* \file initHooks.h
|
||||
*
|
||||
* \author Benjamin Franksen (BESSY)
|
||||
* \author Marty Kraimer (ANL)
|
||||
*
|
||||
* \brief Facility to call functions during iocInit()
|
||||
*
|
||||
* The initHooks facility allows application functions to be called at various
|
||||
* stages/states during IOC initialization, pausing, restart and shutdown.
|
||||
*
|
||||
* All registered application functions will be called whenever the IOC
|
||||
* initialization, pause/resume or shutdown process reaches a new state.
|
||||
*
|
||||
* The following C++ example shows how to use this facility:
|
||||
*
|
||||
* \code{.cpp}
|
||||
* static void myHookFunction(initHookState state)
|
||||
* {
|
||||
* switch (state) {
|
||||
* case initHookAfterInitRecSup:
|
||||
* ...
|
||||
* break;
|
||||
* case initHookAfterDatabaseRunning:
|
||||
* ...
|
||||
* break;
|
||||
* default:
|
||||
* break;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* // A static constructor registers hook function at startup:
|
||||
* static int myHookStatus = initHookRegister(myHookFunction);
|
||||
* \endcode
|
||||
*
|
||||
* An arbitrary number of functions can be registered.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INC_initHooks_H
|
||||
#define INC_initHooks_H
|
||||
|
||||
@@ -22,52 +56,90 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This enum must agree with the array of names defined in initHookName() */
|
||||
typedef enum {
|
||||
initHookAtIocBuild = 0, /* Start of iocBuild/iocInit commands */
|
||||
initHookAtBeginning,
|
||||
initHookAfterCallbackInit,
|
||||
initHookAfterCaLinkInit,
|
||||
initHookAfterInitDrvSup,
|
||||
initHookAfterInitRecSup,
|
||||
initHookAfterInitDevSup,
|
||||
initHookAfterInitDatabase,
|
||||
initHookAfterFinishDevSup,
|
||||
initHookAfterScanInit,
|
||||
initHookAfterInitialProcess,
|
||||
initHookAfterCaServerInit,
|
||||
initHookAfterIocBuilt, /* End of iocBuild command */
|
||||
|
||||
initHookAtIocRun, /* Start of iocRun command */
|
||||
initHookAfterDatabaseRunning,
|
||||
initHookAfterCaServerRunning,
|
||||
initHookAfterIocRunning, /* End of iocRun/iocInit commands */
|
||||
|
||||
initHookAtIocPause, /* Start of iocPause command */
|
||||
initHookAfterCaServerPaused,
|
||||
initHookAfterDatabasePaused,
|
||||
initHookAfterIocPaused, /* End of iocPause command */
|
||||
|
||||
initHookAtShutdown, /* Start of iocShutdown commands */
|
||||
initHookAfterCloseLinks,
|
||||
initHookAfterStopScan, /* triggered only by unittest code. testIocShutdownOk() */
|
||||
initHookAfterStopCallback, /* triggered only by unittest code. testIocShutdownOk() */
|
||||
initHookAfterStopLinks,
|
||||
initHookBeforeFree, /* triggered only by unittest code. testIocShutdownOk() */
|
||||
initHookAfterShutdown, /* End of iocShutdown commands */
|
||||
|
||||
/* Deprecated states, provided for backwards compatibility.
|
||||
* These states are announced at the same point they were before,
|
||||
* but will not be repeated if the IOC gets paused and restarted.
|
||||
/** \brief Initialization stages
|
||||
*
|
||||
* The enum states must agree with the names in the initHookName() function.
|
||||
* New states may be added in the future if extra facilities get incorporated
|
||||
* into the IOC. The numerical value of any state enum may change between
|
||||
* EPICS releases; states are not guaranteed to appear in numerical order.
|
||||
*
|
||||
* Some states were deprecated when iocPause() and iocRun() were added, but
|
||||
* are still provided for backwards compatibility. These deprecated states
|
||||
* are announced at the same point they were before, but will not be repeated
|
||||
* if the IOC is later paused and restarted.
|
||||
*/
|
||||
initHookAfterInterruptAccept, /* After initHookAfterDatabaseRunning */
|
||||
initHookAtEnd, /* Before initHookAfterIocRunning */
|
||||
typedef enum {
|
||||
initHookAtIocBuild = 0, /**< Start of iocBuild() / iocInit() */
|
||||
initHookAtBeginning, /**< Database sanity checks passed */
|
||||
initHookAfterCallbackInit, /**< Callbacks, generalTime & taskwd init */
|
||||
initHookAfterCaLinkInit, /**< CA links init */
|
||||
initHookAfterInitDrvSup, /**< Driver support init */
|
||||
initHookAfterInitRecSup, /**< Record support init */
|
||||
initHookAfterInitDevSup, /**< Device support init pass 0 */
|
||||
initHookAfterInitDatabase, /**< Records and locksets init */
|
||||
initHookAfterFinishDevSup, /**< Device support init pass 1 */
|
||||
initHookAfterScanInit, /**< Scan, AS, ProcessNotify init */
|
||||
initHookAfterInitialProcess, /**< Records with PINI = YES processsed */
|
||||
initHookAfterCaServerInit, /**< RSRV init */
|
||||
initHookAfterIocBuilt, /**< End of iocBuild() */
|
||||
|
||||
initHookAtIocRun, /**< Start of iocRun() */
|
||||
initHookAfterDatabaseRunning, /**< Scan tasks and CA links running */
|
||||
initHookAfterCaServerRunning, /**< RSRV running */
|
||||
initHookAfterIocRunning, /**< End of iocRun() / iocInit() */
|
||||
|
||||
initHookAtIocPause, /**< Start of iocPause() */
|
||||
initHookAfterCaServerPaused, /**< RSRV paused */
|
||||
initHookAfterDatabasePaused, /**< CA links and scan tasks paused */
|
||||
initHookAfterIocPaused, /**< End of iocPause() */
|
||||
|
||||
initHookAtShutdown, /**< Start of iocShutdown() (unit tests only) */
|
||||
initHookAfterCloseLinks, /**< Links disabled/deleted */
|
||||
initHookAfterStopScan, /**< Scan tasks stopped */
|
||||
initHookAfterStopCallback, /**< Callback tasks stopped */
|
||||
initHookAfterStopLinks, /**< CA links stopped */
|
||||
initHookBeforeFree, /**< Resource cleanup about to happen */
|
||||
initHookAfterShutdown, /**< End of iocShutdown() */
|
||||
|
||||
/* Deprecated states: */
|
||||
initHookAfterInterruptAccept, /**< After initHookAfterDatabaseRunning */
|
||||
initHookAtEnd, /**< Before initHookAfterIocRunning */
|
||||
} initHookState;
|
||||
|
||||
/** \brief Type for application callback functions
|
||||
*
|
||||
* Application callback functions must match this typdef.
|
||||
* \param state initHook enumeration value
|
||||
*/
|
||||
typedef void (*initHookFunction)(initHookState state);
|
||||
|
||||
/** \brief Register a function for initHook notifications
|
||||
*
|
||||
* Registers \p func for initHook notifications
|
||||
* \param func Pointer to application's notification function.
|
||||
* \return 0 if Ok, -1 on error (memory allocation failure).
|
||||
*/
|
||||
LIBCOM_API int initHookRegister(initHookFunction func);
|
||||
|
||||
/** \brief Routine called by iocInit() to trigger notifications.
|
||||
*
|
||||
* Calls registered callbacks announcing \p state
|
||||
* \param state initHook enumeration value
|
||||
*/
|
||||
LIBCOM_API void initHookAnnounce(initHookState state);
|
||||
|
||||
/** \brief Returns printable representation of \p state
|
||||
*
|
||||
* Static string representation of \p state for printing
|
||||
* \param state enum value of an initHook
|
||||
* \return Pointer to name string
|
||||
*/
|
||||
LIBCOM_API const char *initHookName(int state);
|
||||
|
||||
/** \brief Forget all registered application functions
|
||||
*
|
||||
* This cleanup routine is called by unit test programs between IOC runs.
|
||||
*/
|
||||
LIBCOM_API void initHookFree(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
+543
-297
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,27 @@
|
||||
/* iocsh.h ioc: call registered function*/
|
||||
/* Author: Marty Kraimer Date: 27APR2000 */
|
||||
|
||||
/**
|
||||
* @file iocsh.h
|
||||
*
|
||||
* @brief C and C++ defintions of functions for IOC shell programming.
|
||||
*
|
||||
* @details
|
||||
* The iocsh API provides an interface for running commands in the shell
|
||||
* of the IOC, as well as registering commands and variables for use in the shell.
|
||||
* It consists of 4 functions for the former and 2 functions for the latter.
|
||||
*
|
||||
* @par Command functions:
|
||||
* int iocsh (const char *pathname)@n
|
||||
* int iocshLoad (const char *pathname, const char *macros)@n
|
||||
* int iocshCmd (const char *cmd)@n
|
||||
* int iocshRun (const char *cmd, const char *macros)
|
||||
*
|
||||
* @par Registration functions:
|
||||
* void iocshRegister (const iocshFuncDef * piocshFuncDef, iocshCallFunc func)@n
|
||||
* void epicsStdCall iocshRegisterVariable (const iocshVarDef *piocshVarDef)
|
||||
*/
|
||||
|
||||
#ifndef INCiocshH
|
||||
#define INCiocshH
|
||||
|
||||
@@ -27,37 +48,109 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @enum iocshArgType
|
||||
*
|
||||
* This typedef lists the values that can be used as argument data types
|
||||
* when building the piocshFuncDef parameter of iocshRegister().
|
||||
*
|
||||
* @code {.cpp}
|
||||
* static const iocshArg AsynGenericConfigArg0 = {"Port Name", iocshArgString};
|
||||
* static const iocshArg AsynGenericConfigArg1 = {"Number Devices", iocshArgInt};
|
||||
* @endcode
|
||||
*/
|
||||
typedef enum {
|
||||
iocshArgInt,
|
||||
iocshArgDouble,
|
||||
iocshArgString,
|
||||
iocshArgPdbbase,
|
||||
iocshArgArgv,
|
||||
iocshArgPersistentString
|
||||
iocshArgPersistentString,
|
||||
/** Equivalent to iocshArgString with a hint for tab completion as a record name.
|
||||
* @since UNRELEASED
|
||||
*/
|
||||
iocshArgStringRecord,
|
||||
/** Equivalent to iocshArgString with a hint for tab completion as a file system path.
|
||||
* @since UNRELEASED
|
||||
*/
|
||||
iocshArgStringPath,
|
||||
}iocshArgType;
|
||||
|
||||
/**
|
||||
* @union iocshArgBuf
|
||||
*
|
||||
* This union is used when building the func paramter of iocshRegister().
|
||||
* Each use should match the parameter type of the parameters of the
|
||||
* function being registered
|
||||
*
|
||||
* @code {.cpp}
|
||||
* static void AsynGenericConfigCallFunc (const iocshArgBuf *args)
|
||||
* {
|
||||
* AsynGenericConfig (args[0].sval, args[1].ival);
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
typedef union iocshArgBuf {
|
||||
int ival;
|
||||
double dval;
|
||||
char *sval;
|
||||
void *vval;
|
||||
struct {
|
||||
int ac;
|
||||
char **av;
|
||||
} aval;
|
||||
int ac;
|
||||
char **av;
|
||||
}aval;
|
||||
}iocshArgBuf;
|
||||
|
||||
/**
|
||||
* @struct iocshVarDef
|
||||
*
|
||||
* This struct is used with the function iocshRegisterVariable. Each
|
||||
* instance includes a name, a data type (see iocshArgType), and a
|
||||
* pointer to the value.
|
||||
*/
|
||||
typedef struct iocshVarDef {
|
||||
const char *name;
|
||||
iocshArgType type;
|
||||
void * pval;
|
||||
}iocshVarDef;
|
||||
|
||||
/**
|
||||
* @struct iocshArg
|
||||
*
|
||||
* This struct is used to indicate data types of function parameters
|
||||
* for iocshRegister(). The name element is used by the help command to print
|
||||
* a synopsis for the command. The type element describes the data type of
|
||||
* the argument and takes a value from iocshArgType.
|
||||
*
|
||||
* @code {.cpp}
|
||||
* static const iocshArg AsynGenericConfigArg0 = {"Port Name", iocshArgString};
|
||||
* static const iocshArg AsynGenericConfigArg1 = {"Number Devices", iocshArgInt};
|
||||
* static const iocshArg* const AsynGenericConfigArgs[]
|
||||
= { &AsynAXEConfigArg0, &AsynAXEConfigArg1 };
|
||||
|
||||
* @endcode
|
||||
*/
|
||||
typedef struct iocshArg {
|
||||
const char *name;
|
||||
iocshArgType type;
|
||||
}iocshArg;
|
||||
|
||||
/**
|
||||
* @struct iocshFuncDef
|
||||
*
|
||||
* This struct is used with iocshRegister to define the function that
|
||||
* is being registered.
|
||||
*
|
||||
* name - the name of the command or function@n
|
||||
* nargs - the number of entries in the array of pointers to argument descriptions@n
|
||||
* arg - an array of pointers to structs of type iocshArg@n
|
||||
*
|
||||
* @code {.cpp}
|
||||
* static const iocshFuncDef AsynGenericConfigFuncDef
|
||||
* = { "AsynGenericConfig", 2, AsynGenericConfigArgs };
|
||||
* @endcode
|
||||
*
|
||||
*/
|
||||
typedef struct iocshFuncDef {
|
||||
const char *name;
|
||||
int nargs;
|
||||
@@ -66,56 +159,158 @@ typedef struct iocshFuncDef {
|
||||
}iocshFuncDef;
|
||||
#define IOCSHFUNCDEF_HAS_USAGE
|
||||
|
||||
/**
|
||||
* @typedef
|
||||
*
|
||||
* This typedef defines a function that is used as the *piocshFuncDef
|
||||
* parameter of iocshRegister().
|
||||
*
|
||||
* @code {.cpp}
|
||||
* static void AsynGenericConfigCallFunc (const iocshArgBuf *args)
|
||||
* {
|
||||
* AsynGenericConfig (args[0].sval, args[1].ival);
|
||||
* }
|
||||
*
|
||||
* static void AsynGenericRegister(void)
|
||||
* {
|
||||
* iocshRegister(&AsynGenericConfigFuncDef, AsynGenericConfigCallFunc);
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
typedef void (*iocshCallFunc)(const iocshArgBuf *argBuf);
|
||||
|
||||
/**
|
||||
* @struct
|
||||
*
|
||||
* This struct is used as a return value for the function iocshFindCommand.
|
||||
*/
|
||||
typedef struct iocshCmdDef {
|
||||
iocshFuncDef const *pFuncDef;
|
||||
iocshCallFunc func;
|
||||
}iocshCmdDef;
|
||||
|
||||
/**
|
||||
* @brief This function is used to register a command with the IOC shell
|
||||
*
|
||||
* @param piocshFuncDef A pointer to a data structure that describes the command and its arguments.
|
||||
* @param func A pointer to a function which is called by iocsh() when the command is encountered.
|
||||
* @return void
|
||||
*/
|
||||
LIBCOM_API void epicsStdCall iocshRegister(
|
||||
const iocshFuncDef *piocshFuncDef, iocshCallFunc func);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param piocshVarDef
|
||||
* @return void
|
||||
*/
|
||||
LIBCOM_API void epicsStdCall iocshRegisterVariable (
|
||||
const iocshVarDef *piocshVarDef);
|
||||
|
||||
/**
|
||||
* @brief Returns a struct of type iocshCmdDef whose element values are determined
|
||||
* by the name parameter. This function calls the function registryFind, defined in
|
||||
* Registry.h
|
||||
*
|
||||
* @param name
|
||||
* @return const iocshCmdDef*
|
||||
*/
|
||||
LIBCOM_API const iocshCmdDef * epicsStdCall iocshFindCommand(
|
||||
const char* name) EPICS_DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Returns a struct of type iocshVarDef whose element values are determined
|
||||
* by the name parameter. This function calls the function registryFind, defined in
|
||||
* Registry.h
|
||||
*
|
||||
* @param name
|
||||
* @return const iocshVarDef*
|
||||
*/
|
||||
LIBCOM_API const iocshVarDef * epicsStdCall iocshFindVariable(
|
||||
const char* name);
|
||||
|
||||
/* iocshFree frees storage used by iocshRegister*/
|
||||
/* This should only be called when iocsh is no longer needed*/
|
||||
/**
|
||||
* @brief Frees all memory allocated to registered commands and variables.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
LIBCOM_API void epicsStdCall iocshFree(void);
|
||||
|
||||
/** shorthand for \code iocshLoad(pathname, NULL) \endcode */
|
||||
/**
|
||||
* @brief This function is used to execute IOC shell commands from a file.
|
||||
*
|
||||
* Commands are read from the file until and exit command is encountered or the
|
||||
* end-of-file character is reached.
|
||||
*
|
||||
* @param pathname A string that represents the path to a file from which commands are read.
|
||||
* @return 0 on success, non-zero on error
|
||||
*
|
||||
* Equivalent to:
|
||||
* @code iocshLoad(pathname, NULL) @endcode */
|
||||
LIBCOM_API int epicsStdCall iocsh(const char *pathname);
|
||||
/** shorthand for \code iocshRun(cmd, NULL) \endcode */
|
||||
|
||||
/**
|
||||
* @brief This function is used to exectute a single IOC shell command.
|
||||
*
|
||||
* @param cmd A string that represents the command to be executed.
|
||||
* @return 0 on success, non-zero on error
|
||||
*
|
||||
* Equivalent to:
|
||||
* @code iocshRun(cmd, NULL) @endcode */
|
||||
LIBCOM_API int epicsStdCall iocshCmd(const char *cmd);
|
||||
/** Read and evaluate IOC shell commands from the given file.
|
||||
* \param pathname Path to script file
|
||||
* \param macros NULL or a comma seperated list of macro definitions. eg. "VAR1=x,VAR2=y"
|
||||
* \return 0 on success, non-zero on error
|
||||
/**
|
||||
* @brief Read and evaluate IOC shell commands from the given file. A list of macros
|
||||
* can be supplied as a parameter. These macros are treated as environment variables during
|
||||
* exectution of the file's commands.
|
||||
*
|
||||
* @param pathname A string that represents the path to a file from which commands are read.
|
||||
* @param macros NULL or a comma separated list of macro definitions. eg. "VAR1=x,VAR2=y"
|
||||
* @return 0 on success, non-zero on error
|
||||
*/
|
||||
LIBCOM_API int epicsStdCall iocshLoad(const char *pathname, const char* macros);
|
||||
/** Evaluate a single IOC shell command
|
||||
* \param cmd Command string. eg. "echo \"something or other\""
|
||||
* \param macros NULL or a comma seperated list of macro definitions. eg. "VAR1=x,VAR2=y"
|
||||
* \return 0 on success, non-zero on error
|
||||
/**
|
||||
* @brief Evaluate a single IOC shell command. A list of macros can be supplied
|
||||
* as a parameter. These macros are treated as environment variables during
|
||||
* exectution of the command.
|
||||
*
|
||||
* @param cmd Command string. eg. "echo \"something or other\""
|
||||
* @param macros NULL or a comma separated list of macro definitions. eg. "VAR1=x,VAR2=y"
|
||||
* @return 0 on success, non-zero on error
|
||||
*/
|
||||
LIBCOM_API int epicsStdCall iocshRun(const char *cmd, const char* macros);
|
||||
|
||||
/** \brief Signal error from an IOC shell function.
|
||||
/**
|
||||
* @brief Signal error from an IOC shell function.
|
||||
*
|
||||
* \param err 0 - success (no op), !=0 - error
|
||||
* \return The err argument value.
|
||||
* @param err 0 - success (no op), !=0 - error
|
||||
* @return The err argument value.
|
||||
*/
|
||||
LIBCOM_API int iocshSetError(int err);
|
||||
|
||||
/* Makes macros that shadow environment variables work correctly with epicsEnvSet */
|
||||
/**
|
||||
* @brief Unsets macro values.
|
||||
*
|
||||
* This function sets the values of all macros passed to either iocshLoad or
|
||||
* iocshRun to NULL.
|
||||
*
|
||||
* @param name
|
||||
* @return void
|
||||
*/
|
||||
LIBCOM_API void epicsStdCall iocshEnvClear(const char *name);
|
||||
|
||||
/* 'weak' link to pdbbase */
|
||||
LIBCOM_API extern struct dbBase **iocshPpdbbase;
|
||||
|
||||
#ifdef EPICS_PRIVATE_API
|
||||
|
||||
LIBCOM_API
|
||||
extern char** (*iocshCompleteRecord)(const char *word);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -98,7 +98,7 @@ static void echoCallFunc(const iocshArgBuf *args)
|
||||
}
|
||||
|
||||
/* chdir */
|
||||
static const iocshArg chdirArg0 = { "directory name",iocshArgString};
|
||||
static const iocshArg chdirArg0 = { "directory name",iocshArgStringPath};
|
||||
static const iocshArg * const chdirArgs[1] = {&chdirArg0};
|
||||
static const iocshFuncDef chdirFuncDef = {"cd",1,chdirArgs,
|
||||
"Change directory to new directory provided as parameter\n"};
|
||||
|
||||
@@ -127,7 +127,7 @@ int epicsStdCall iocLogInit (void)
|
||||
return iocLogSuccess;
|
||||
}
|
||||
/*
|
||||
* dont init twice
|
||||
* don't init twice
|
||||
*/
|
||||
if (iocLogClient!=NULL) {
|
||||
return iocLogSuccess;
|
||||
|
||||
@@ -261,7 +261,7 @@ static int seekLatestLine (struct ioc_log_server *pserver)
|
||||
static const int tm_epoch_year = 1900;
|
||||
if (theDate.tm_year>tm_epoch_year) {
|
||||
theDate.tm_year -= tm_epoch_year;
|
||||
theDate.tm_isdst = -1; /* dont know */
|
||||
theDate.tm_isdst = -1; /* don't know */
|
||||
lineTime = mktime (&theDate);
|
||||
if ( lineTime != invalidTime ) {
|
||||
if (theLatestTime == invalidTime ||
|
||||
@@ -590,7 +590,7 @@ static void writeMessagesToLog (struct iocLogClient *pclient)
|
||||
* find the first carrage return and create
|
||||
* an entry in the log for the message associated
|
||||
* with it. If a carrage return does not exist and
|
||||
* the buffer isnt full then move the partial message
|
||||
* the buffer isn't full then move the partial message
|
||||
* to the front of the buffer and wait for a carrage
|
||||
* return to arrive. If the buffer is full and there
|
||||
* is no carrage return then force the message out and
|
||||
@@ -681,12 +681,6 @@ static void freeLogClient(struct iocLogClient *pclient)
|
||||
{
|
||||
int status;
|
||||
|
||||
# ifdef DEBUG
|
||||
if(length == 0){
|
||||
fprintf(stderr, "iocLogServer: nil message disconnect\n");
|
||||
}
|
||||
# endif
|
||||
|
||||
/*
|
||||
* flush any left overs
|
||||
*/
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "dbDefs.h"
|
||||
#include "epicsEvent.h"
|
||||
#include "iocLog.h"
|
||||
#include "errlog.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsThread.h"
|
||||
#include "epicsTime.h"
|
||||
@@ -557,8 +558,10 @@ void epicsStdCall iocLogPrefix(const char * prefix)
|
||||
*/
|
||||
|
||||
if (logClientPrefix) {
|
||||
printf ("iocLogPrefix: The prefix was already set to \"%s\" "
|
||||
"and can't be changed.\n", logClientPrefix);
|
||||
/* No error message if the new prefix is identical to the old one */
|
||||
if (strcmp(logClientPrefix, prefix))
|
||||
printf (ERL_WARNING " iocLogPrefix: The prefix was already set to "
|
||||
"\"%s\" and can't be changed.\n", logClientPrefix);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,15 @@
|
||||
* Author: Jeffrey O. Hill
|
||||
* Date: 080791
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file logClient.h
|
||||
*
|
||||
* \brief Client on the IOC that forwards log messages to the log server
|
||||
*
|
||||
* Together with the program iocLogServer, a log client provides generic
|
||||
* support for logging text messages from an IOC or other program to the log
|
||||
* server host machine.
|
||||
*/
|
||||
#ifndef INClogClienth
|
||||
#define INClogClienth 1
|
||||
#include "libComAPI.h"
|
||||
@@ -27,15 +35,68 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \brief Abstract type that represents handle to the log client
|
||||
*/
|
||||
typedef void *logClientId;
|
||||
|
||||
/** \brief Creates a new log client
|
||||
*
|
||||
* Starts a background thread to connect to server and returns immediately.
|
||||
* If a connection cannot be established, an error message is
|
||||
* printed on the console, but the log client will keep trying to connect in
|
||||
* the background. This thread will also periodically (every 5 seconds) flush
|
||||
* pending messages out to the server.
|
||||
*
|
||||
* \param server_addr log server IP address
|
||||
* \param server_port log server port
|
||||
*
|
||||
* \return log client handle.
|
||||
*/
|
||||
LIBCOM_API logClientId epicsStdCall logClientCreate (
|
||||
struct in_addr server_addr, unsigned short server_port);
|
||||
|
||||
/** \brief Log message
|
||||
*
|
||||
* Logs message to log server. Messages are not immediately sent to the log
|
||||
* server. Instead they are sent periodically (every 5 seconds), when the cache
|
||||
* overflows, or when logClientFlush() is called. If messages can't sent, an error
|
||||
* message will be printed to stderr
|
||||
*
|
||||
* \param id log client handle
|
||||
* \param message log message
|
||||
*/
|
||||
LIBCOM_API void epicsStdCall logClientSend (logClientId id, const char *message);
|
||||
|
||||
/** \brief Prints debug information about the log client state
|
||||
*
|
||||
* Print information about the log client's internal state
|
||||
* such as, connection status and cache state, to stdout
|
||||
*
|
||||
* \param id log client handle
|
||||
* \param level verbosity level. Level range is from 0 to 2
|
||||
*/
|
||||
LIBCOM_API void epicsStdCall logClientShow (logClientId id, unsigned level);
|
||||
|
||||
/** \brief Flushes all outstanding messages
|
||||
*
|
||||
* Immediately sends all outstanding messages to the server
|
||||
*
|
||||
* \param id log client handle
|
||||
*/
|
||||
LIBCOM_API void epicsStdCall logClientFlush (logClientId id);
|
||||
|
||||
/** \brief Set prefix to be sent infront of every log message
|
||||
*
|
||||
* Sets a prefix to prepend every log message. Can only be set
|
||||
* once. If already set, this function call will be ignored
|
||||
*
|
||||
* \param prefix the prefix
|
||||
*/
|
||||
LIBCOM_API void epicsStdCall iocLogPrefix(const char* prefix);
|
||||
|
||||
/* deprecated interface; retained for backward compatibility */
|
||||
/** \brief DEPRECATED
|
||||
* \deprecated deprecated interface; retained for backward compatibility
|
||||
*/
|
||||
/* note: implementations are in iocLog.c, not logClient.c */
|
||||
LIBCOM_API logClientId epicsStdCall logClientInit (void);
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ typedef struct mac_entry {
|
||||
/*** Local function prototypes ***/
|
||||
|
||||
/*
|
||||
* These static functions peform low-level operations on macro entries
|
||||
* These static functions perform low-level operations on macro entries
|
||||
*/
|
||||
static MAC_ENTRY *first ( MAC_HANDLE *handle );
|
||||
static MAC_ENTRY *last ( MAC_HANDLE *handle );
|
||||
@@ -772,7 +772,7 @@ static MAC_ENTRY *lookup( MAC_HANDLE *handle, const char *name, int special )
|
||||
}
|
||||
if ( (special == FALSE) && (entry == NULL) &&
|
||||
(handle->flags & FLAG_USE_ENVIRONMENT) ) {
|
||||
char *value = getenv(name);
|
||||
char *value = name && *name ? getenv(name) : NULL;
|
||||
if (value) {
|
||||
entry = create( handle, name, FALSE );
|
||||
if ( entry ) {
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
/* Up to now epicsShareThings have been declared as imports
|
||||
* (Appropriate for other stuff)
|
||||
* After setting the following they will be declared as exports
|
||||
* (Appropriate for what we implenment)
|
||||
* (Appropriate for what we implement)
|
||||
*/
|
||||
#include "adjustment.h"
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
/** \brief Find parent object from a member pointer
|
||||
*
|
||||
* Subtracts the byte offset of the member in the structure from the
|
||||
* pointer to the member itself, giving a pointer to parent strucure.
|
||||
* pointer to the member itself, giving a pointer to parent structure.
|
||||
* \param ptr Pointer to a member data field of a structure
|
||||
* \param structure Type name of the parent structure
|
||||
* \param member Field name of the data member
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2012 UChicago Argonna LLC, as Operator of Argonne
|
||||
* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
/**
|
||||
* \file epicsStdlib.h
|
||||
* \brief Functions to convert strings to primative types
|
||||
* \brief Functions to convert strings to primitive types
|
||||
*
|
||||
* These routines convert a string into an integer of the indicated type and
|
||||
* number base, or into a floating point type. The units pointer argument may
|
||||
@@ -163,7 +163,7 @@ LIBCOM_API int
|
||||
#define epicsParseFloat64(str, to, units) epicsParseDouble(str, to, units)
|
||||
|
||||
/* These macros return 1 if successful, 0 on failure.
|
||||
* This is analagous to the return value from sscanf()
|
||||
* This is analogous to the return value from sscanf()
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#ifndef vxWorks
|
||||
#include <stdint.h>
|
||||
#else
|
||||
/* VxWorks automaticaly includes stdint.h defining SIZE_MAX in 6.9 but not earlier */
|
||||
/* VxWorks automatically includes stdint.h defining SIZE_MAX in 6.9 but not earlier */
|
||||
#ifndef SIZE_MAX
|
||||
#define SIZE_MAX (size_t)-1
|
||||
#endif
|
||||
|
||||
@@ -13,6 +13,12 @@
|
||||
* Mark Rivers, Andrew Johnson, Ralph Lange
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file epicsString.h
|
||||
*
|
||||
* \brief Collection of string utility functions
|
||||
*/
|
||||
|
||||
#ifndef INC_epicsString_H
|
||||
#define INC_epicsString_H
|
||||
|
||||
@@ -24,20 +30,107 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \brief Converts C-style escape sequences to their binary form
|
||||
*
|
||||
* Copies characters from string to an output buffer and converts C-style escape sequences to
|
||||
* their binary form. Since the output string can never be longer than the source, it is legal for
|
||||
* \p inbuf and \p outbuf to point to the same buffer and \p outsize and \p inlen
|
||||
* be equal, thus performing the character translation in-place.
|
||||
*
|
||||
* \param outbuf buffer to copy string to. The resulting string will be zero-terminated as long as
|
||||
* \p outsize is non-zero.
|
||||
* \param outsize length of output buffer not including the null-terminator.
|
||||
* \param inbuf buffer to copy from. Null byte terminates the string.
|
||||
* \param inlen maximum number of characters to copy from input buffer.
|
||||
*
|
||||
* \return number of characters that were written into output buffer, not counting the null terminator.
|
||||
**/
|
||||
LIBCOM_API int epicsStrnRawFromEscaped(char *outbuf, size_t outsize,
|
||||
const char *inbuf, size_t inlen);
|
||||
|
||||
/** \brief Converts non-printable characters into C-style escape sequences
|
||||
*
|
||||
* Copies characters from the string into a output buffer converting non-printable characters into C-style
|
||||
* escape sequences. In-place translations are not allowed since the escaped results will usually be larger
|
||||
* than the input string.
|
||||
*
|
||||
* The following escaped character constants will be used in the output:
|
||||
* \verbatim \a \b \f \n \r \t \v \\ \’ \" \0 \endverbatim
|
||||
* All other non-printable characters appear in form `\xHH` where HH are two hex digits.
|
||||
* Non-printable characters are determined by the C runtime library’s isprint() function.
|
||||
*
|
||||
* \param outbuf buffer to copy string to. The resulting string will be zero-terminated as long as
|
||||
* @p outsize is non-zero.
|
||||
* \param outsize length of output buffer not including the null-terminator.
|
||||
* \param inbuf buffer to copy from. Null byte will not terminates the string.
|
||||
* \param inlen Number of characters to copy from input buffer.
|
||||
*
|
||||
* \return number of characters that would have been stored in the output buffer if it were large enough,
|
||||
* or a negative value if \p outbuf == \p inbuf.
|
||||
*
|
||||
*/
|
||||
LIBCOM_API int epicsStrnEscapedFromRaw(char *outbuf, size_t outsize,
|
||||
const char *inbuf, size_t inlen);
|
||||
|
||||
/** \brief Scans string and returns size of output buffer needed to escape that string
|
||||
*
|
||||
* Scans up to \p len characters of the string that may contain non-printable characters, and returns
|
||||
* the size of the output buffer that would be needed to escape that string.
|
||||
* This routine is faster than calling epicsStrnEscapedFromRaw() with a zero length output buffer; both
|
||||
* should return the same result.
|
||||
*
|
||||
*\param buf string to scan
|
||||
*\param len length of input string
|
||||
*
|
||||
*\return size of the output buffer that would be needed for converting to escape characters, not
|
||||
* including the null terminator.
|
||||
*/
|
||||
LIBCOM_API size_t epicsStrnEscapedFromRawSize(const char *buf, size_t len);
|
||||
|
||||
/** \brief Does case-insensitive comparison of two strings
|
||||
*
|
||||
* Implements strcmp from the C standard library, except is case insensitive
|
||||
*/
|
||||
LIBCOM_API int epicsStrCaseCmp(const char *s1, const char *s2);
|
||||
|
||||
/** \brief Does case-insensitive comparision of two strings
|
||||
*
|
||||
* Implements strncmp from the C standard library, except is case insensitive
|
||||
*/
|
||||
LIBCOM_API int epicsStrnCaseCmp(const char *s1, const char *s2, size_t len);
|
||||
|
||||
/** \brief Duplicates a string
|
||||
*
|
||||
* Implements strdup from the C standard library. Calls mallocMustSucceed() to allocate memory
|
||||
*/
|
||||
LIBCOM_API char * epicsStrDup(const char *s);
|
||||
|
||||
/** \brief Duplicates a string
|
||||
*
|
||||
* implements strndup from the C standard library. Calls mallocMustSucceed() to allocate memory
|
||||
*/
|
||||
LIBCOM_API char * epicsStrnDup(const char *s, size_t len);
|
||||
|
||||
/** \brief Prints escaped version of string
|
||||
*
|
||||
* Prints the contents of its input buffer to given file descriptor, substituting escape sequences
|
||||
* for non-printable characters.
|
||||
*
|
||||
* \param fp File descriptor to print to
|
||||
* \param s String to print
|
||||
* \param n Length of string
|
||||
*/
|
||||
LIBCOM_API int epicsStrPrintEscaped(FILE *fp, const char *s, size_t n);
|
||||
|
||||
#define epicsStrSnPrintEscaped epicsStrnEscapedFromRaw
|
||||
|
||||
/** \brief Calculates length of string
|
||||
*
|
||||
* Implements strnlen from the C standard library.
|
||||
*/
|
||||
LIBCOM_API size_t epicsStrnLen(const char *s, size_t maxlen);
|
||||
|
||||
/** Matches a string against a pattern.
|
||||
/** \brief Matches a string against a pattern.
|
||||
*
|
||||
* Checks if str matches the glob style pattern, which may contain ? or * wildcards.
|
||||
* A ? matches any single character.
|
||||
@@ -49,9 +142,9 @@ LIBCOM_API size_t epicsStrnLen(const char *s, size_t maxlen);
|
||||
*/
|
||||
LIBCOM_API int epicsStrGlobMatch(const char *str, const char *pattern);
|
||||
|
||||
/** Matches a string against a pattern.
|
||||
/** \brief Matches a string against a pattern.
|
||||
*
|
||||
* Like epicsStrGlobMatch but with limited string length.
|
||||
* Like epicsStrGlobMatch() but with limited string length.
|
||||
* If the length of str is less than len, the full string is matched.
|
||||
*
|
||||
* @returns 1 if the first len characters of str match the pattern, 0 if not.
|
||||
@@ -60,11 +153,40 @@ LIBCOM_API int epicsStrGlobMatch(const char *str, const char *pattern);
|
||||
*/
|
||||
LIBCOM_API int epicsStrnGlobMatch(const char *str, size_t len, const char *pattern);
|
||||
|
||||
/** \brief Extract tokens from string
|
||||
*
|
||||
* Implements strtok_r from the C standard library
|
||||
*/
|
||||
LIBCOM_API char * epicsStrtok_r(char *s, const char *delim, char **lasts);
|
||||
|
||||
/** \brief Calculates a hash of a null-terminated string
|
||||
*
|
||||
* Calculates a hash of a null-terminated string. Initial seed may be provided which
|
||||
* permits multiple strings to be combined into a single hash result.
|
||||
*
|
||||
*\param str null-terminated string
|
||||
*\param seed Optionally provide seed to combine multiple strings in a single hash. Otherwise
|
||||
* set to 0.
|
||||
*
|
||||
*\return Hash value for string
|
||||
*/
|
||||
LIBCOM_API unsigned int epicsStrHash(const char *str, unsigned int seed);
|
||||
|
||||
/** \brief Calculates a hash of a memory buffer
|
||||
*
|
||||
* Calculates a hash of a memory buffer that may contain null values. Initial seed may be provided which
|
||||
* permits multiple buffers to be combined into a single hash result.
|
||||
*
|
||||
*\param str buffer
|
||||
*\param length size of buffer
|
||||
*\param seed Optionally provide seed to combine multiple buffers in a single hash. Otherwise
|
||||
* set to 0.
|
||||
*
|
||||
*\return Hash value for buffer
|
||||
*/
|
||||
LIBCOM_API unsigned int epicsMemHash(const char *str, size_t length,
|
||||
unsigned int seed);
|
||||
/** Compare two strings and return a number in the range [0.0, 1.0] or -1.0 on error.
|
||||
/** \brief Compare two strings and return a number in the range [0.0, 1.0] or -1.0 on error.
|
||||
*
|
||||
* Computes a normalized edit distance representing the similarity between two strings.
|
||||
*
|
||||
@@ -75,7 +197,9 @@ LIBCOM_API unsigned int epicsMemHash(const char *str, size_t length,
|
||||
*/
|
||||
LIBCOM_API double epicsStrSimilarity(const char *A, const char *B);
|
||||
|
||||
/* dbTranslateEscape is deprecated, use epicsStrnRawFromEscaped instead */
|
||||
/** \brief DEPRECATED
|
||||
* \deprecated dbTranslateEscape is deprecated, use epicsStrnRawFromEscaped() instead
|
||||
*/
|
||||
LIBCOM_API int dbTranslateEscape(char *s, const char *ct);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -41,7 +41,7 @@ typedef enum {
|
||||
* These are sufficient for all our current archs
|
||||
* @{
|
||||
*/
|
||||
typedef char epicsInt8;
|
||||
typedef signed char epicsInt8;
|
||||
typedef unsigned char epicsUInt8;
|
||||
typedef short epicsInt16;
|
||||
typedef unsigned short epicsUInt16;
|
||||
@@ -59,7 +59,7 @@ typedef epicsInt32 epicsStatus;
|
||||
#define MAX_STRING_SIZE 40
|
||||
|
||||
/**
|
||||
* \brief !! Dont use this - it may vanish in the future !!
|
||||
* \brief !! Don't use this - it may vanish in the future !!
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned length;
|
||||
@@ -67,7 +67,7 @@ typedef struct {
|
||||
} epicsString;
|
||||
|
||||
/**
|
||||
* \brief !! Dont use this - it may vanish in the future !!
|
||||
* \brief !! Don't use this - it may vanish in the future !!
|
||||
*
|
||||
* Provided only for backwards compatibility with
|
||||
* db_access.h
|
||||
@@ -102,8 +102,8 @@ typedef union epics_any {
|
||||
* \brief Corresponding Type Codes
|
||||
* (this enum must start at zero)
|
||||
*
|
||||
* !! Update \ref epicsTypeToDBR_XXXX[] and \ref DBR_XXXXToEpicsType
|
||||
* in db_access.h if you edit this enum !!
|
||||
* \note Update \a epicsTypeToDBR_XXXX[] and \a DBR_XXXXToEpicsType
|
||||
* in db_access.h if you edit this enum
|
||||
*/
|
||||
typedef enum {
|
||||
epicsInt8T,
|
||||
|
||||
@@ -28,6 +28,13 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __rtems__
|
||||
# include <syslog.h>
|
||||
# ifndef RTEMS_LEGACY_STACK
|
||||
# include <rtems/bsd/bsd.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "epicsThread.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsUnitTest.h"
|
||||
@@ -95,11 +102,23 @@ static int testReportHook(int reportType, char *message, int *returnValue)
|
||||
static void testOnce(void *dummy) {
|
||||
testLock = epicsMutexMustCreate();
|
||||
perlHarness = (getenv("HARNESS_ACTIVE") != NULL);
|
||||
#ifdef __rtems__
|
||||
// syslog() on RTEMS prints to stdout, which will interfere with test output.
|
||||
// setlogmask() ignores empty mask, so must allow at least one level.
|
||||
(void)setlogmask(LOG_MASK(LOG_CRIT));
|
||||
printf("# mask syslog() output\n");
|
||||
#ifndef RTEMS_LEGACY_STACK
|
||||
// with libbsd setlogmask() is a no-op :(
|
||||
// name strings in sys/syslog.h
|
||||
rtems_bsd_setlogpriority("crit");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef HAVE_SETERROMODE
|
||||
/* SEM_FAILCRITICALERRORS - Don't display modal dialog
|
||||
* !SEM_NOALIGNMENTFAULTEXCEPT - auto-fix unaligned access
|
||||
* !SEM_NOGPFAULTERRORBOX - enable Windows Error Reporting (also enables post-mortem debugger hooks)
|
||||
* !SEM_NOGPFAULTERRORBOX - enable Windows Error Reporting (also enables postmortem debugger hooks)
|
||||
* SEM_NOOPENFILEERRORBOX - Don't display modal dialog
|
||||
*/
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
|
||||
|
||||
@@ -47,9 +47,9 @@
|
||||
* be recorded as failures.
|
||||
*
|
||||
* Additional information can be supplied using the testDiag() routine, which
|
||||
* displays the relevent information as a comment in the result output. None of
|
||||
* displays the relevant information as a comment in the result output. None of
|
||||
* the printable strings passed to any testXxx() routine should contain a newline
|
||||
* '\n' character, newlines will be added by the test routines as part of the
|
||||
* '\\n' character, newlines will be added by the test routines as part of the
|
||||
* Test Anything Protocol. For multiple lines of diagnostic output, call
|
||||
* testDiag() as many times as necessary.
|
||||
*
|
||||
@@ -80,7 +80,7 @@
|
||||
* server) can not be shut down cleanly. The function iocBuildIsolated() allows
|
||||
* to start an IOC without its Channel Access parts, so that it can be shutdown
|
||||
* quite cleanly using iocShutdown(). This feature is only intended to be used
|
||||
* from test programs, do not use it on productional IOCs. After building the
|
||||
* from test programs, do not use it on production IOCs. After building the
|
||||
* IOC using iocBuildIsolated() or iocBuild(), it has to be started by calling
|
||||
* iocRun(). The suggested call sequence in a test program that needs to run the
|
||||
* IOC without Channel Access is:
|
||||
@@ -176,8 +176,8 @@ LIBCOM_API void testPlan(int tests);
|
||||
*/
|
||||
LIBCOM_API int testOk(int pass, const char *fmt, ...)
|
||||
EPICS_PRINTF_STYLE(2, 3);
|
||||
/** \brief Test result using condition as description
|
||||
* \param cond Condition to be evaluated and displayed.
|
||||
/** \brief Test result using expression as description
|
||||
* \param cond Expression to be evaluated and displayed.
|
||||
* \return The value of \p cond.
|
||||
*/
|
||||
#define testOk1(cond) testOk(cond, "%s", #cond)
|
||||
@@ -191,7 +191,6 @@ LIBCOM_API int testOkV(int pass, const char *fmt, va_list pvar);
|
||||
/** \brief Passing test result with printf-style description.
|
||||
* \param fmt A printf-style format string describing the test.
|
||||
* \param ... Any parameters required for the format string.
|
||||
* \return The value of \p pass.
|
||||
*/
|
||||
LIBCOM_API void testPass(const char *fmt, ...)
|
||||
EPICS_PRINTF_STYLE(1, 2);
|
||||
@@ -204,7 +203,7 @@ LIBCOM_API void testFail(const char *fmt, ...)
|
||||
/** @} */
|
||||
|
||||
/** \name Missing or Failing Tests
|
||||
* \brief Routines for handling special situations.
|
||||
* Routines for handling special situations.
|
||||
*/
|
||||
/** @{ */
|
||||
|
||||
@@ -238,7 +237,7 @@ LIBCOM_API int testDiag(const char *fmt, ...)
|
||||
*/
|
||||
LIBCOM_API int testDone(void);
|
||||
|
||||
/** \brief Return non-zero in shared/oversubscribed testing envrionments
|
||||
/** \brief Return non-zero in shared/oversubscribed testing environments
|
||||
*
|
||||
* May be used to testSkip(), or select longer timeouts, for some cases
|
||||
* when the test process may be preempted for arbitrarily long times.
|
||||
@@ -261,7 +260,13 @@ typedef int (*TESTFUNC)(void);
|
||||
/** \brief Initialize test harness
|
||||
*/
|
||||
LIBCOM_API void testHarness(void);
|
||||
/** \brief End of testing
|
||||
*/
|
||||
LIBCOM_API void testHarnessExit(void *dummy);
|
||||
/** \brief Run a single test program
|
||||
* \param name Program name
|
||||
* \param func Function implementing test program
|
||||
*/
|
||||
LIBCOM_API void runTestFunc(const char *name, TESTFUNC func);
|
||||
|
||||
/** \brief Run a test program
|
||||
|
||||
@@ -338,7 +338,7 @@ void ipAddrToAsciiGlobal::run ()
|
||||
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
// dont call callback with lock applied
|
||||
// don't call callback with lock applied
|
||||
pCur->pCB->transactionComplete ( this->nameTmp );
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,65 @@
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/**
|
||||
* \file ipAddrToAsciiAsynchronous.h
|
||||
* \brief Convert ip addresses to ASCII asynchronously
|
||||
*
|
||||
* ipAddrToAsciiEngine is the first class needed to convert an ipAddr to an
|
||||
* ASCII address. From the engine, you can use createTransaction() to create a
|
||||
* transaction object. The transaction object lets you attach callbacks and
|
||||
* convert an address to ASCII.
|
||||
*
|
||||
* Example
|
||||
* -------------
|
||||
*
|
||||
* \code{.cpp}
|
||||
* class ConvertIPAddr: ipAddrToAsciiCallBack
|
||||
* {
|
||||
* ipAddrToAsciiTransaction & trans;
|
||||
*
|
||||
* public:
|
||||
* epicsEvent complete;
|
||||
*
|
||||
* ConvertIPAddr(ipAddrToAsciiEngine & engine, osiSockAddr & addr):
|
||||
* trans(engine.createTransaction())
|
||||
* {
|
||||
* trans.ipAddrToAscii(addr, *this);
|
||||
* }
|
||||
*
|
||||
* virtual void transactionComplete (char const * node) override
|
||||
* {
|
||||
* printf("Address is %s\n", node);
|
||||
* complete.signal();
|
||||
* }
|
||||
*
|
||||
* virtual void show(unsigned level) override const
|
||||
* {
|
||||
* printf("This is a ConvertIPAddr class object.");
|
||||
* }
|
||||
*
|
||||
* virtual ~ConvertIPAddr()
|
||||
* {
|
||||
* trans.release();
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* ipAddrToAsciiEngine & engine(ipAddrToAsciiEngine::allocate());
|
||||
*
|
||||
* osiSockAddr addr;
|
||||
* addr.ia.sin_family = AF_INET;
|
||||
* addr.ia.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
* addr.ia.sin_port = htons(8080);
|
||||
*
|
||||
* ConvertIPAddr result(engine, addr);
|
||||
*
|
||||
* // Do other work here before waiting on the result
|
||||
*
|
||||
* result.complete.wait(2.0);
|
||||
* engine.release();
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
/*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
@@ -19,28 +78,86 @@
|
||||
#include "osiSock.h"
|
||||
#include "libComAPI.h"
|
||||
|
||||
/** \brief Users implement this virtual class to use ipAddrToAsciiTransaction
|
||||
*
|
||||
* In order to use ipAddrToAsciiTranaction, users should implement this virtual
|
||||
* class to handle events that occur asynchronously while converting the IP
|
||||
* address.
|
||||
*
|
||||
*/
|
||||
class LIBCOM_API ipAddrToAsciiCallBack {
|
||||
public:
|
||||
/// Called once the ip address is converted to ASCII
|
||||
/*
|
||||
* \param pHostName The converted ASCII name */
|
||||
virtual void transactionComplete ( const char * pHostName ) = 0;
|
||||
|
||||
/// Called by the show() method of ipAddrToAsciiTransaction or
|
||||
/// ipAddrToAsciiEngine when passed a level >= 1.
|
||||
virtual void show ( unsigned level ) const;
|
||||
|
||||
virtual ~ipAddrToAsciiCallBack () = 0;
|
||||
};
|
||||
|
||||
/// Class which convert an ipAddr to ascii and call a user-supplied callback
|
||||
/// when finished.
|
||||
class LIBCOM_API ipAddrToAsciiTransaction {
|
||||
public:
|
||||
/// Destroy this transaction object and remove from the parent engine object
|
||||
virtual void release () = 0;
|
||||
virtual void ipAddrToAscii ( const osiSockAddr &, ipAddrToAsciiCallBack & ) = 0;
|
||||
|
||||
/** \brief Convert an IP address to ascii, asynchronously
|
||||
*
|
||||
* \note The ipAddrToAsciiCallBack referenced must remain valid until release() is called on this transaction.
|
||||
* \param addrIn Reference to the address to convert
|
||||
* \param cbIn Reference to the user supplied callbacks to call when the result is available
|
||||
*/
|
||||
virtual void ipAddrToAscii ( const osiSockAddr & addrIn, ipAddrToAsciiCallBack & cbIn ) = 0;
|
||||
|
||||
/** \brief Get the conversion address currently set
|
||||
* \return Get the last (or current) address converted to ascii
|
||||
*/
|
||||
virtual osiSockAddr address () const = 0;
|
||||
|
||||
/**
|
||||
* \brief Prints the converted IP address
|
||||
*
|
||||
* Prints to stdout
|
||||
*
|
||||
* \param level 0 prints basic info, greater than 0 prints information from the callback's show() method too
|
||||
*/
|
||||
virtual void show ( unsigned level ) const = 0;
|
||||
protected:
|
||||
virtual ~ipAddrToAsciiTransaction () = 0;
|
||||
};
|
||||
|
||||
/// Class which manages creating transactions for converting ipAddr's to ASCII
|
||||
class LIBCOM_API ipAddrToAsciiEngine {
|
||||
public:
|
||||
/// Cancel any pending transactions and destroy this ipAddrToAsciiEngine object.
|
||||
virtual void release () = 0;
|
||||
|
||||
/**
|
||||
* \brief Create a new transaction object used to do IP address conversions
|
||||
* \note Caller must release() the returned transaction
|
||||
* \return The newly created transaction object
|
||||
*/
|
||||
virtual ipAddrToAsciiTransaction & createTransaction () = 0;
|
||||
|
||||
/**
|
||||
* \brief Print information about this engine object and how many requests its processing
|
||||
*
|
||||
* Prints to stdout
|
||||
*
|
||||
* \param level 0 for basic information, 1 for extra info
|
||||
*/
|
||||
virtual void show ( unsigned level ) const = 0;
|
||||
|
||||
/**
|
||||
* \brief Creates a new ipAddrToAsciiEngine to convert IP addresses
|
||||
* \note Caller must release() this engine.
|
||||
* \return Newly created engine object
|
||||
*/
|
||||
static ipAddrToAsciiEngine & allocate ();
|
||||
protected:
|
||||
virtual ~ipAddrToAsciiEngine () = 0;
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
*
|
||||
* By default shareLib.h sets the DLL import / export keywords to import from
|
||||
* a DLL so that, for DLL consumers (users), nothing special must be done. However,
|
||||
* DLL implementors must set epicsExportSharedSymbols as above to specify
|
||||
* DLL implementers must set epicsExportSharedSymbols as above to specify
|
||||
* which functions are exported from the DLL and which of them are imported
|
||||
* from other DLLs.
|
||||
*
|
||||
|
||||
@@ -9,15 +9,20 @@
|
||||
#ifndef INC_testMain_H
|
||||
#define INC_testMain_H
|
||||
|
||||
/* This header defines a convenience macro for use by pure test programs.
|
||||
/*!
|
||||
* \file testMain.h
|
||||
*
|
||||
* \brief This header defines a platform independent macro for defining a test
|
||||
* main function, in pure test programs.
|
||||
*
|
||||
* A pure test program cannot take any arguments since it must be fully
|
||||
* automatable. If your program needs to use argv/argc, it may be doing
|
||||
* measurements not unit and/or regression testing. On Host architectures
|
||||
* these programs needs to be named main and take dummy argc/argv args,
|
||||
* but on vxWorks and RTEMS they must be named as the test program.
|
||||
*
|
||||
* Use this macro as follows:
|
||||
*
|
||||
* \section Example
|
||||
* \code{.cpp}
|
||||
* #include "testMain.h"
|
||||
* #include "epicsUnitTest.h"
|
||||
*
|
||||
@@ -26,8 +31,14 @@
|
||||
* testOk(...)
|
||||
* return testDone();
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \def MAIN
|
||||
* \brief Macro which defines a main function for your test program. Some platforms will name this function main(), others prog().
|
||||
* \param prog Name of the test program.
|
||||
**/
|
||||
#if defined(__rtems__)
|
||||
#ifdef __cplusplus
|
||||
#define MAIN(prog) extern "C" int prog(void); extern "C" int main() __attribute__((weak, alias(#prog))); extern "C" int prog(void)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#endif
|
||||
|
||||
/*
|
||||
* truncate to specified size (we dont use truncate()
|
||||
* truncate to specified size (we don't use truncate()
|
||||
* because it is not portable)
|
||||
*/
|
||||
LIBCOM_API enum TF_RETURN truncateFile (const char *pFileName, unsigned long size)
|
||||
|
||||
@@ -65,6 +65,10 @@ INC += osdVME.h
|
||||
INC += epicsMMIO.h
|
||||
INC += epicsMMIODef.h
|
||||
|
||||
INC_clang += epicsAtomicGCC.h
|
||||
INC_gcc += epicsAtomicGCC.h
|
||||
INC += $(INC_$(CMPLR_CLASS))
|
||||
|
||||
Com_SRCS += epicsThread.cpp
|
||||
Com_SRCS += epicsMutex.cpp
|
||||
Com_SRCS += epicsEvent.cpp
|
||||
|
||||
@@ -17,8 +17,18 @@
|
||||
#ifndef epicsAtomicCD_h
|
||||
#define epicsAtomicCD_h
|
||||
|
||||
#ifndef __clang__
|
||||
# error this header is only for use with the Clang compiler
|
||||
#endif
|
||||
|
||||
#define EPICS_ATOMIC_CMPLR_NAME "CLANG"
|
||||
|
||||
#include <epicsAtomicGCC.h>
|
||||
|
||||
/*
|
||||
* if currently unavailable as intrinsics we
|
||||
* will try for an os specific inline solution
|
||||
*/
|
||||
#include "epicsAtomicOSD.h"
|
||||
|
||||
#endif /* epicsAtomicCD_h */
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#ifndef compilerSpecific_h
|
||||
#define compilerSpecific_h
|
||||
|
||||
/* The 'inline' key work, possibily with compiler
|
||||
/* The 'inline' keyword, possibly with compiler
|
||||
* dependent flags to force inlineing where it would
|
||||
* otherwise not be done.
|
||||
*
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#ifdef __cplusplus
|
||||
|
||||
/*
|
||||
* in general we dont like ifdefs but they do allow us to check the
|
||||
* in general we don't like ifdefs but they do allow us to check the
|
||||
* compiler version and make the optimistic assumption that
|
||||
* standards incompliance issues will be fixed by future compiler
|
||||
* releases
|
||||
|
||||
@@ -23,168 +23,7 @@
|
||||
|
||||
#define EPICS_ATOMIC_CMPLR_NAME "GCC"
|
||||
|
||||
#define GCC_ATOMIC_CONCAT( A, B ) GCC_ATOMIC_CONCATR(A,B)
|
||||
#define GCC_ATOMIC_CONCATR( A, B ) ( A ## B )
|
||||
|
||||
#define GCC_ATOMIC_INTRINSICS_AVAIL_INT_T \
|
||||
GCC_ATOMIC_CONCAT ( \
|
||||
__GCC_HAVE_SYNC_COMPARE_AND_SWAP_, \
|
||||
__SIZEOF_INT__ )
|
||||
|
||||
#define GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T \
|
||||
GCC_ATOMIC_CONCAT ( \
|
||||
__GCC_HAVE_SYNC_COMPARE_AND_SWAP_, \
|
||||
__SIZEOF_SIZE_T__ )
|
||||
|
||||
#define GCC_ATOMIC_INTRINSICS_MIN_X86 \
|
||||
( defined ( __i486 ) || defined ( __pentium ) || \
|
||||
defined ( __pentiumpro ) || defined ( __MMX__ ) )
|
||||
|
||||
#define GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER \
|
||||
( ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 401 )
|
||||
|
||||
#define GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER \
|
||||
( GCC_ATOMIC_INTRINSICS_MIN_X86 && \
|
||||
GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER )
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We are optimistic that __sync_synchronize is implemented
|
||||
* in all version four gcc invariant of target. The gnu doc
|
||||
* seems to say that when not supported by architecture a call
|
||||
* to an external function is generated but in practice
|
||||
* this isn`t the case for some of the atomic intrinsics, and
|
||||
* so there is an undefined symbol. So far we have not seen
|
||||
* that with __sync_synchronize, but we can only guess based
|
||||
* on experimental evidence.
|
||||
*
|
||||
* For example we know that when generating object code for
|
||||
* 386 most of the atomic intrinsics are not present and
|
||||
* we see undefined symbols with mingw, but we don`t have
|
||||
* troubles with __sync_synchronize.
|
||||
*/
|
||||
#if GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER
|
||||
|
||||
#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER
|
||||
#define EPICS_ATOMIC_READ_MEMORY_BARRIER
|
||||
EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier (void)
|
||||
{
|
||||
__sync_synchronize ();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER
|
||||
#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER
|
||||
EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier (void)
|
||||
{
|
||||
__sync_synchronize ();
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER
|
||||
#if GCC_ATOMIC_INTRINSICS_MIN_X86
|
||||
#define EPICS_ATOMIC_READ_MEMORY_BARRIER
|
||||
EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier (void)
|
||||
{
|
||||
asm("mfence;");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER
|
||||
#if GCC_ATOMIC_INTRINSICS_MIN_X86
|
||||
#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER
|
||||
EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier (void)
|
||||
{
|
||||
asm("mfence;");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* if GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER */
|
||||
|
||||
#if GCC_ATOMIC_INTRINSICS_AVAIL_INT_T \
|
||||
|| GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER
|
||||
|
||||
#define EPICS_ATOMIC_INCR_INTT
|
||||
EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget )
|
||||
{
|
||||
return __sync_add_and_fetch ( pTarget, 1 );
|
||||
}
|
||||
|
||||
#define EPICS_ATOMIC_DECR_INTT
|
||||
EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget )
|
||||
{
|
||||
return __sync_sub_and_fetch ( pTarget, 1 );
|
||||
}
|
||||
|
||||
#define EPICS_ATOMIC_ADD_INTT
|
||||
EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta )
|
||||
{
|
||||
return __sync_add_and_fetch ( pTarget, delta );
|
||||
}
|
||||
|
||||
#define EPICS_ATOMIC_CAS_INTT
|
||||
EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget,
|
||||
int oldVal, int newVal )
|
||||
{
|
||||
return __sync_val_compare_and_swap ( pTarget, oldVal, newVal);
|
||||
}
|
||||
|
||||
#endif /* if GCC_ATOMIC_INTRINSICS_AVAIL_INT_T */
|
||||
|
||||
#if GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T \
|
||||
|| GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER
|
||||
|
||||
#define EPICS_ATOMIC_INCR_SIZET
|
||||
EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
|
||||
{
|
||||
return __sync_add_and_fetch ( pTarget, 1u );
|
||||
}
|
||||
|
||||
#define EPICS_ATOMIC_DECR_SIZET
|
||||
EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
|
||||
{
|
||||
return __sync_sub_and_fetch ( pTarget, 1u );
|
||||
}
|
||||
|
||||
#define EPICS_ATOMIC_ADD_SIZET
|
||||
EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta )
|
||||
{
|
||||
return __sync_add_and_fetch ( pTarget, delta );
|
||||
}
|
||||
|
||||
#define EPICS_ATOMIC_SUB_SIZET
|
||||
EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta )
|
||||
{
|
||||
return __sync_sub_and_fetch ( pTarget, delta );
|
||||
}
|
||||
|
||||
#define EPICS_ATOMIC_CAS_SIZET
|
||||
EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget,
|
||||
size_t oldVal, size_t newVal )
|
||||
{
|
||||
return __sync_val_compare_and_swap ( pTarget, oldVal, newVal);
|
||||
}
|
||||
|
||||
#define EPICS_ATOMIC_CAS_PTRT
|
||||
EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT (
|
||||
EpicsAtomicPtrT * pTarget,
|
||||
EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal )
|
||||
{
|
||||
return __sync_val_compare_and_swap ( pTarget, oldVal, newVal);
|
||||
}
|
||||
|
||||
#endif /* if GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
#include <epicsAtomicGCC.h>
|
||||
|
||||
/*
|
||||
* if currently unavailable as gcc intrinsics we
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#ifdef __cplusplus
|
||||
|
||||
/*
|
||||
* in general we dont like ifdefs but they do allow us to check the
|
||||
* in general we don't like ifdefs but they do allow us to check the
|
||||
* compiler version and make the optimistic assumption that
|
||||
* standards incompliance issues will be fixed by future compiler
|
||||
* releases
|
||||
|
||||
@@ -149,7 +149,7 @@ long devBusToLocalAddr(
|
||||
volatile void *localAddress;
|
||||
|
||||
/*
|
||||
* Make sure that devLib has been intialized
|
||||
* Make sure that devLib has been initialized
|
||||
*/
|
||||
if (!devLibInitFlag) {
|
||||
status = devLibInit();
|
||||
@@ -264,7 +264,7 @@ long devRegisterAddress(
|
||||
* devReadProbe()
|
||||
*
|
||||
* a bus error safe "wordSize" read at the specified address which returns
|
||||
* unsuccessful status if the device isnt present
|
||||
* unsuccessful status if the device isn't present
|
||||
*/
|
||||
long devReadProbe (unsigned wordSize, volatile const void *ptr, void *pValue)
|
||||
{
|
||||
@@ -284,7 +284,7 @@ long devReadProbe (unsigned wordSize, volatile const void *ptr, void *pValue)
|
||||
* devWriteProbe
|
||||
*
|
||||
* a bus error safe "wordSize" write at the specified address which returns
|
||||
* unsuccessful status if the device isnt present
|
||||
* unsuccessful status if the device isn't present
|
||||
*/
|
||||
long devWriteProbe (unsigned wordSize, volatile void *ptr, const void *pValue)
|
||||
{
|
||||
@@ -1112,7 +1112,7 @@ long locationProbe (epicsAddressType addrType, char *pLocation)
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* The follwing may, or may not be present in the BSP for the CPU in use.
|
||||
* The following may, or may not be present in the BSP for the CPU in use.
|
||||
*
|
||||
*/
|
||||
/******************************************************************************
|
||||
|
||||
@@ -67,7 +67,7 @@ extern "C" {
|
||||
|
||||
/** \brief Print a map of registered bus addresses.
|
||||
*
|
||||
* Display a table of registsred bus address ranges, including the owner of
|
||||
* Display a table of registered bus address ranges, including the owner of
|
||||
* each registered address.
|
||||
* \return 0, or an error status value
|
||||
*/
|
||||
@@ -246,7 +246,7 @@ LIBCOM_API int devInterruptInUseVME (unsigned vectorNumber);
|
||||
/** \brief Enable a VME interrupt level onto the CPU.
|
||||
*
|
||||
* The VMEbus allows multiple CPU boards to be installed in the same
|
||||
* backplane. When this is done, the differente VME interrupt levels
|
||||
* backplane. When this is done, the different VME interrupt levels
|
||||
* must be assigned to the CPUs since they cannot be shared. This
|
||||
* routine tells the VME interface that it should connect interrupts
|
||||
* from the indicated interrupt level to a CPU interrupt line.
|
||||
|
||||
@@ -31,7 +31,7 @@ extern "C" {
|
||||
* \brief A table of function pointers for devLibVME implementations
|
||||
*
|
||||
* The global virtual OS table \ref pdevLibVME controls
|
||||
* the behaviour of the functions defined in devLib.h.
|
||||
* the behavior of the functions defined in devLib.h.
|
||||
* All of which call into the functions found in this table
|
||||
* to perform system specific tasks.
|
||||
*/
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
*
|
||||
* This header also provides a compile-time assertion macro STATIC_ASSERT()
|
||||
* which can be used to check a constant-expression at compile-time. The C or
|
||||
* C++ compiler will flag an error if the expresstion evaluates to 0. The
|
||||
* C++ compiler will flag an error if the expression evaluates to 0. The
|
||||
* STATIC_ASSERT() macro can only be used where a \c typedef is syntactically
|
||||
* legal.
|
||||
**/
|
||||
|
||||
@@ -8,6 +8,25 @@
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/**
|
||||
* \file epicsAtomic.h
|
||||
*
|
||||
* \brief OS independent interface to perform atomic operations
|
||||
*
|
||||
* This is an operating system and compiler independent interface to an operating system and or compiler
|
||||
* dependent implementation of several atomic primitives.
|
||||
*
|
||||
* These primitives can be safely used in a multithreaded programs on symmetric multiprocessing (SMP)
|
||||
* systems. Where possible the primitives are implemented with compiler intrinsic wrappers for architecture
|
||||
* specific instructions. Otherwise they are implemeted with OS specific functions and otherwise, when lacking
|
||||
* a sufficently capable OS specific interface, then in some rare situations a mutual exclusion primitive is
|
||||
* used for synchronization.
|
||||
*
|
||||
* In operating systems environments which allow C code to run at interrupt level the implementation must
|
||||
* use interrupt level invokable CPU instruction primitives.
|
||||
*
|
||||
* All C++ functions are implemented in the namespace atomics which is nested inside of namespace epics.
|
||||
*/
|
||||
/*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
@@ -26,67 +45,217 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Argument type for atomic operations on pointers*/
|
||||
typedef void * EpicsAtomicPtrT;
|
||||
|
||||
/* load target into cache */
|
||||
/** \brief load target into cache
|
||||
*
|
||||
* load target into cache
|
||||
**/
|
||||
EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier (void);
|
||||
|
||||
/* push cache version of target into target */
|
||||
/** \brief push cache version of target into target
|
||||
*
|
||||
* push cache version of target into target
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier (void);
|
||||
|
||||
/*
|
||||
* lock out other smp processors from accessing the target,
|
||||
/** \brief atomic increment on size_t value
|
||||
*
|
||||
* Lock out other smp processors from accessing the target,
|
||||
* load target into cache, add one to target, flush cache
|
||||
* to target, allow other smp processors to access the target,
|
||||
* return new value of target as modified by this operation
|
||||
*
|
||||
* \param pTarget pointer to target
|
||||
*
|
||||
* \return New value of target
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget );
|
||||
|
||||
/** \brief atomic increment on int value
|
||||
*
|
||||
* Lock out other smp processors from accessing the target,
|
||||
* load target into cache, add one to target, flush cache
|
||||
* to target, allow other smp processors to access the target,
|
||||
* return new value of target as modified by this operation
|
||||
*
|
||||
* \param pTarget pointer to target
|
||||
*
|
||||
* \return New value of target
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget );
|
||||
|
||||
/*
|
||||
* lock out other smp processors from accessing the target,
|
||||
/** \brief atomic decrement on size_t value
|
||||
*
|
||||
* Lock out other smp processors from accessing the target,
|
||||
* load target into cache, subtract one from target, flush cache
|
||||
* to target, allow out other smp processors to access the target,
|
||||
* return new value of target as modified by this operation
|
||||
*
|
||||
* \param pTarget pointer to target
|
||||
*
|
||||
* \return New value of target
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget );
|
||||
|
||||
/** \brief atomic decrement on int value
|
||||
*
|
||||
* Lock out other smp processors from accessing the target,
|
||||
* load target into cache, subtract one from target, flush cache
|
||||
* to target, allow out other smp processors to access the target,
|
||||
* return new value of target as modified by this operation
|
||||
*
|
||||
* \param pTarget pointer to target
|
||||
*
|
||||
* \return New value of target
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget );
|
||||
|
||||
/*
|
||||
* lock out other smp processors from accessing the target,
|
||||
* load target into cache, add/sub delta to/from target, flush cache
|
||||
/** \brief atomic addition on size_t value
|
||||
*
|
||||
* Lock out other smp processors from accessing the target,
|
||||
* load target into cache, add \p delta to target, flush cache
|
||||
* to target, allow other smp processors to access the target,
|
||||
* return new value of target as modified by this operation
|
||||
*
|
||||
* \param pTarget pointer to target
|
||||
* \param delta value to add to target
|
||||
*
|
||||
* \return New value of target
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta );
|
||||
|
||||
/** \brief atomic subtraction on size_t value
|
||||
*
|
||||
* Lock out other smp processors from accessing the target,
|
||||
* load target into cache, subtract \p delta from target, flush cache
|
||||
* to target, allow other smp processors to access the target,
|
||||
* return new value of target as modified by this operation
|
||||
*
|
||||
* \param pTarget pointer to target
|
||||
* \param delta value to subtract from target
|
||||
*
|
||||
* \return New value of target
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta );
|
||||
EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta );
|
||||
|
||||
/** \brief atomic addition on int value
|
||||
*
|
||||
* Lock out other smp processors from accessing the target,
|
||||
* load target into cache, add \p delta to target, flush cache
|
||||
* to target, allow other smp processors to access the target,
|
||||
* return new value of target as modified by this operation
|
||||
*
|
||||
* \param pTarget pointer to target
|
||||
* \param delta value to add to target
|
||||
*
|
||||
* \return New value of target
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta );
|
||||
|
||||
/*
|
||||
* set cache version of target, flush cache to target
|
||||
*/
|
||||
/** \brief atomically assign size_t value to variable
|
||||
*
|
||||
* set cache version of target to new value, flush cache to target
|
||||
*
|
||||
* \param pTarget pointer to target
|
||||
* \param newValue desired value of target
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newValue );
|
||||
|
||||
/** \brief atomically assign int value to variable
|
||||
*
|
||||
* set cache version of target to new value, flush cache to target
|
||||
*
|
||||
* \param pTarget pointer to target
|
||||
* \param newValue desired value of target
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE void epicsAtomicSetIntT ( int * pTarget, int newValue );
|
||||
|
||||
/** \brief atomically assign pointer value to variable
|
||||
*
|
||||
* set cache version of target to new value, flush cache to target
|
||||
*
|
||||
* \param pTarget pointer to target
|
||||
* \param newValue desired value of target
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newValue );
|
||||
|
||||
/*
|
||||
/** \brief atomically load and return size_t value
|
||||
*
|
||||
* fetch target into cache, return new value of target
|
||||
*
|
||||
* \param pTarget pointer to target
|
||||
*
|
||||
* \return value of target
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget );
|
||||
|
||||
/** \brief atomically load and return int value
|
||||
*
|
||||
* fetch target into cache, return new value of target
|
||||
*
|
||||
* \param pTarget pointer to target
|
||||
*
|
||||
* \return value of target
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE int epicsAtomicGetIntT ( const int * pTarget );
|
||||
|
||||
/** \brief atomically load and return pointer value
|
||||
*
|
||||
* fetch target into cache, return new value of target
|
||||
*
|
||||
* \param pTarget pointer to target
|
||||
*
|
||||
* \return value of target
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget );
|
||||
|
||||
/*
|
||||
/** \brief atomically compare size_t value with expected and if equal swap with new value
|
||||
*
|
||||
* lock out other smp processors from accessing the target,
|
||||
* load target into cache, if target is equal to oldVal set target
|
||||
* to newVal, flush cache to target, allow other smp processors
|
||||
* to access the target, return the original value stored in the
|
||||
* target
|
||||
* load target into cache. If target is equal to \p oldVal, set target
|
||||
* to \p newVal, flush cache to target, allow other smp processors
|
||||
* to access the target
|
||||
*
|
||||
* \param pTarget pointer to target
|
||||
* \param oldVal value that will be compared with target
|
||||
* \param newVal value that will be set to target if oldVal == target
|
||||
*
|
||||
* \return the original value stored in the target
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget,
|
||||
size_t oldVal, size_t newVal );
|
||||
|
||||
/** \brief atomically compare int value with expected and if equal swap with new value
|
||||
*
|
||||
* lock out other smp processors from accessing the target,
|
||||
* load target into cache. If target is equal to \p oldVal, set target
|
||||
* to \p newVal, flush cache to target, allow other smp processors
|
||||
* to access the target
|
||||
*
|
||||
* \param pTarget pointer to target
|
||||
* \param oldVal value that will be compared with target
|
||||
* \param newVal value that will be set to target if oldVal == target
|
||||
*
|
||||
* \return the original value stored in the target
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget,
|
||||
int oldVal, int newVal );
|
||||
|
||||
/** \brief atomically compare int value with expected and if equal swap with new value
|
||||
*
|
||||
* lock out other smp processors from accessing the target,
|
||||
* load target into cache. If target is equal to \p oldVal, set target
|
||||
* to \p newVal, flush cache to target, allow other smp processors
|
||||
* to access the target
|
||||
*
|
||||
* \param pTarget pointer to target
|
||||
* \param oldVal value that will be compared with target
|
||||
* \param newVal value that will be set to target if oldVal == target
|
||||
*
|
||||
* \return the original value stored in the target
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT (
|
||||
EpicsAtomicPtrT * pTarget,
|
||||
EpicsAtomicPtrT oldVal,
|
||||
@@ -115,94 +284,233 @@ namespace atomic {
|
||||
* overloaded c++ interface
|
||||
*/
|
||||
|
||||
/************* incr ***************/
|
||||
/** \brief C++ API for atomic size_t increment
|
||||
*
|
||||
* C++ API for atomic size_t increment.
|
||||
*
|
||||
* \param v variable to increment
|
||||
*
|
||||
* \return new value
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE size_t increment ( size_t & v )
|
||||
{
|
||||
return epicsAtomicIncrSizeT ( & v );
|
||||
}
|
||||
|
||||
/** \brief C++ API for atomic int increment
|
||||
*
|
||||
* C++ API for atomic int increment.
|
||||
*
|
||||
* \param v variable to increment
|
||||
*
|
||||
* \return new value
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE int increment ( int & v )
|
||||
{
|
||||
return epicsAtomicIncrIntT ( & v );
|
||||
}
|
||||
|
||||
/************* decr ***************/
|
||||
/** \brief C++ API for atomic size_t decrement
|
||||
*
|
||||
* C++ API for atomic size_t decrement
|
||||
*
|
||||
* \param v variable to decrement
|
||||
*
|
||||
* \return new value
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE size_t decrement ( size_t & v )
|
||||
{
|
||||
return epicsAtomicDecrSizeT ( & v );
|
||||
}
|
||||
|
||||
/** \brief C++ API for atomic int decrement
|
||||
*
|
||||
* C++ API for atomic int decrement
|
||||
*
|
||||
* \param v variable to decrement
|
||||
*
|
||||
* \return new value
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE int decrement ( int & v )
|
||||
{
|
||||
return epicsAtomicDecrIntT ( & v );
|
||||
}
|
||||
|
||||
/************* add ***************/
|
||||
/** \brief C++ API for atomic size_t addition
|
||||
*
|
||||
* C++ API for atomic size_t addition
|
||||
*
|
||||
* \param v variable to add to
|
||||
* \param delta value to add to \p v
|
||||
*
|
||||
* \return new value
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE size_t add ( size_t & v, size_t delta )
|
||||
{
|
||||
return epicsAtomicAddSizeT ( & v, delta );
|
||||
}
|
||||
|
||||
/** \brief C++ API for atomic int addition
|
||||
*
|
||||
* C++ API for atomic int addition
|
||||
*
|
||||
* \param v variable to add to
|
||||
* \param delta value to add to \p v
|
||||
*
|
||||
* \return new value
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE int add ( int & v, int delta )
|
||||
{
|
||||
return epicsAtomicAddIntT ( & v, delta );
|
||||
}
|
||||
|
||||
/************* sub ***************/
|
||||
/** \brief C++ API for atomic size_t subtraction
|
||||
*
|
||||
* C++ API for atomic size_t subtraction
|
||||
*
|
||||
* \param v variable to subtract from
|
||||
* \param delta value to subtract from \p v
|
||||
*
|
||||
* \return new value
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE size_t subtract ( size_t & v, size_t delta )
|
||||
{
|
||||
return epicsAtomicSubSizeT ( & v, delta );
|
||||
}
|
||||
|
||||
/** \brief C++ API for atomic int subtraction
|
||||
*
|
||||
* C++ API for atomic int subtraction
|
||||
*
|
||||
* \param v variable to subtract from
|
||||
* \param delta value to subtract from \p v
|
||||
*
|
||||
* \return new value
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE int subtract ( int & v, int delta )
|
||||
{
|
||||
return epicsAtomicAddIntT ( & v, -delta );
|
||||
}
|
||||
|
||||
/************* set ***************/
|
||||
/** \brief C++ API for atomic size_t assignment
|
||||
*
|
||||
* C++ API for atomic size_t assignment
|
||||
*
|
||||
* \param v variable to assign to
|
||||
* \param newValue new value for \p v
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE void set ( size_t & v , size_t newValue )
|
||||
{
|
||||
epicsAtomicSetSizeT ( & v, newValue );
|
||||
}
|
||||
|
||||
/** \brief C++ API for atomic int assignment
|
||||
*
|
||||
* C++ API for atomic int assignment
|
||||
*
|
||||
* \param v variable to assign to
|
||||
* \param newValue new value for \p v
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE void set ( int & v, int newValue )
|
||||
{
|
||||
epicsAtomicSetIntT ( & v, newValue );
|
||||
}
|
||||
|
||||
/** \brief C++ API for atomic pointer assignment
|
||||
*
|
||||
* C++ API for atomic pointer assignment
|
||||
*
|
||||
* \param v variable to assign to
|
||||
* \param newValue new value for \p v
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE void set ( EpicsAtomicPtrT & v, EpicsAtomicPtrT newValue )
|
||||
{
|
||||
epicsAtomicSetPtrT ( & v, newValue );
|
||||
}
|
||||
|
||||
/************* get ***************/
|
||||
/** \brief C++ API for atomic size_t load value
|
||||
*
|
||||
* C++ API for atomic size_t load value
|
||||
*
|
||||
* \param v variable to load
|
||||
*
|
||||
* \return value of \p v
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE size_t get ( const size_t & v )
|
||||
{
|
||||
return epicsAtomicGetSizeT ( & v );
|
||||
}
|
||||
|
||||
/** \brief C++ API for atomic int load value
|
||||
*
|
||||
* C++ API for atomic int load value
|
||||
*
|
||||
* \param v variable to load
|
||||
*
|
||||
* \return value of \p v
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE int get ( const int & v )
|
||||
{
|
||||
return epicsAtomicGetIntT ( & v );
|
||||
}
|
||||
|
||||
/** \brief C++ API for atomic pointer load value
|
||||
*
|
||||
* C++ API for atomic pointer load value
|
||||
*
|
||||
* \param v variable to load
|
||||
*
|
||||
* \return value of \p v
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE EpicsAtomicPtrT get ( const EpicsAtomicPtrT & v )
|
||||
{
|
||||
return epicsAtomicGetPtrT ( & v );
|
||||
}
|
||||
|
||||
/************* cas ***************/
|
||||
/** \brief C++ API for atomic size_t compare-and-swap
|
||||
*
|
||||
* C++ API for atomic size_t compare-and-swap. Atomic operation that compares \p v with \p oldVal
|
||||
* and if \p v == \v oldVal, sets \p v to \v newVal
|
||||
*
|
||||
* \param v variable to compare and swap
|
||||
* \param oldVal value to compare to \p \v
|
||||
* \param newVal value to set to \p v
|
||||
*
|
||||
* \return original value stored in \p v
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE size_t compareAndSwap ( size_t & v,
|
||||
size_t oldVal, size_t newVal )
|
||||
{
|
||||
return epicsAtomicCmpAndSwapSizeT ( & v, oldVal, newVal );
|
||||
}
|
||||
|
||||
/** \brief C++ API for atomic int compare-and-swap
|
||||
*
|
||||
* C++ API for atomic size_t compare-and-swap. Atomic operation that compares \p v with \p oldVal
|
||||
* and if \p v == \v oldVal, sets \p v to \v newVal
|
||||
*
|
||||
* \param v variable to compare and swap
|
||||
* \param oldVal value to compare to \p \v
|
||||
* \param newVal value to set to \p v
|
||||
*
|
||||
* \return original value stored in \p v
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE int compareAndSwap ( int & v, int oldVal, int newVal )
|
||||
{
|
||||
return epicsAtomicCmpAndSwapIntT ( & v, oldVal, newVal );
|
||||
}
|
||||
|
||||
/** \brief C++ API for atomic pointer compare-and-swap
|
||||
*
|
||||
* C++ API for atomic size_t compare-and-swap. Atomic operation that compares \p v with \p oldVal
|
||||
* and if \p v == \v oldVal, sets \p v to \v newVal
|
||||
*
|
||||
* \param v variable to compare and swap
|
||||
* \param oldVal value to compare to \p \v
|
||||
* \param newVal value to set to \p v
|
||||
*
|
||||
* \return original value stored in \p v
|
||||
*/
|
||||
EPICS_ATOMIC_INLINE EpicsAtomicPtrT compareAndSwap ( EpicsAtomicPtrT & v,
|
||||
EpicsAtomicPtrT oldVal,
|
||||
EpicsAtomicPtrT newVal )
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2011 LANS LLC, as Operator of
|
||||
* Los Alamos National Laboratory.
|
||||
* Copyright (c) 2021 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* SPDX-License-Identifier: EPICS
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
*/
|
||||
|
||||
/*
|
||||
* These implementations are the same for both GCC and Clang
|
||||
*/
|
||||
|
||||
#ifndef INC_epicsAtomicGCC_H
|
||||
#define INC_epicsAtomicGCC_H
|
||||
|
||||
/* expands __GCC_HAVE_SYNC_COMPARE_AND_SWAP_ concatenating
|
||||
* the numeric value __SIZEOF_*__
|
||||
*/
|
||||
#define GCC_ATOMIC_CONCAT( A, B ) GCC_ATOMIC_CONCATR(A,B)
|
||||
#define GCC_ATOMIC_CONCATR( A, B ) ( A ## B )
|
||||
|
||||
#define GCC_ATOMIC_INTRINSICS_AVAIL_INT_T \
|
||||
GCC_ATOMIC_CONCAT ( \
|
||||
__GCC_HAVE_SYNC_COMPARE_AND_SWAP_, \
|
||||
__SIZEOF_INT__ )
|
||||
|
||||
/* we assume __SIZEOF_POINTER__ == __SIZEOF_SIZE_T__ */
|
||||
#define GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T \
|
||||
GCC_ATOMIC_CONCAT ( \
|
||||
__GCC_HAVE_SYNC_COMPARE_AND_SWAP_, \
|
||||
__SIZEOF_SIZE_T__ )
|
||||
|
||||
/*
|
||||
* As of GCC 8, the __sync_synchronize() is inlined for all
|
||||
* known targets (aarch64, arm, i386, powerpc, and x86_64)
|
||||
* except for arm <=6.
|
||||
* Note that i386 inlines __sync_synchronize() but does not
|
||||
* define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_*
|
||||
*/
|
||||
#if GCC_ATOMIC_INTRINSICS_AVAIL_INT_T || \
|
||||
GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T || \
|
||||
defined(__i386)
|
||||
#define GCC_ATOMIC_INTRINSICS_AVAIL_SYNC 1
|
||||
#else
|
||||
#define GCC_ATOMIC_INTRINSICS_AVAIL_SYNC 0
|
||||
#endif
|
||||
/* The above macro is also used in epicsAtomicTest.cpp */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if GCC_ATOMIC_INTRINSICS_AVAIL_SYNC
|
||||
|
||||
#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER
|
||||
#define EPICS_ATOMIC_READ_MEMORY_BARRIER
|
||||
EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier (void)
|
||||
{
|
||||
__sync_synchronize ();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER
|
||||
#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER
|
||||
EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier (void)
|
||||
{
|
||||
__sync_synchronize ();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if GCC_ATOMIC_INTRINSICS_AVAIL_INT_T
|
||||
|
||||
#define EPICS_ATOMIC_INCR_INTT
|
||||
EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget )
|
||||
{
|
||||
return __sync_add_and_fetch ( pTarget, 1 );
|
||||
}
|
||||
|
||||
#define EPICS_ATOMIC_DECR_INTT
|
||||
EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget )
|
||||
{
|
||||
return __sync_sub_and_fetch ( pTarget, 1 );
|
||||
}
|
||||
|
||||
#define EPICS_ATOMIC_ADD_INTT
|
||||
EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta )
|
||||
{
|
||||
return __sync_add_and_fetch ( pTarget, delta );
|
||||
}
|
||||
|
||||
#define EPICS_ATOMIC_CAS_INTT
|
||||
EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget,
|
||||
int oldVal, int newVal )
|
||||
{
|
||||
return __sync_val_compare_and_swap ( pTarget, oldVal, newVal);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T
|
||||
|
||||
#define EPICS_ATOMIC_INCR_SIZET
|
||||
EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
|
||||
{
|
||||
return __sync_add_and_fetch ( pTarget, 1u );
|
||||
}
|
||||
|
||||
#define EPICS_ATOMIC_DECR_SIZET
|
||||
EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
|
||||
{
|
||||
return __sync_sub_and_fetch ( pTarget, 1u );
|
||||
}
|
||||
|
||||
#define EPICS_ATOMIC_ADD_SIZET
|
||||
EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta )
|
||||
{
|
||||
return __sync_add_and_fetch ( pTarget, delta );
|
||||
}
|
||||
|
||||
#define EPICS_ATOMIC_SUB_SIZET
|
||||
EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta )
|
||||
{
|
||||
return __sync_sub_and_fetch ( pTarget, delta );
|
||||
}
|
||||
|
||||
#define EPICS_ATOMIC_CAS_SIZET
|
||||
EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget,
|
||||
size_t oldVal, size_t newVal )
|
||||
{
|
||||
return __sync_val_compare_and_swap ( pTarget, oldVal, newVal);
|
||||
}
|
||||
|
||||
#define EPICS_ATOMIC_CAS_PTRT
|
||||
EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT (
|
||||
EpicsAtomicPtrT * pTarget,
|
||||
EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal )
|
||||
{
|
||||
return __sync_val_compare_and_swap ( pTarget, oldVal, newVal);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* INC_epicsAtomicGCC_H */
|
||||
@@ -34,7 +34,7 @@ const char * epicsEvent::invalidSemaphore::what () const throw ()
|
||||
|
||||
//
|
||||
// Its probably preferable to not make these inline because they are in
|
||||
// the sharable library interface. The use of inline or not here is probably
|
||||
// the shareable library interface. The use of inline or not here is probably
|
||||
// not an issue because all of this ends up in the operating system in system
|
||||
// calls
|
||||
//
|
||||
@@ -70,9 +70,9 @@ void epicsEvent::wait ()
|
||||
}
|
||||
}
|
||||
|
||||
bool epicsEvent::wait (double timeOut)
|
||||
bool epicsEvent::wait (double timeout)
|
||||
{
|
||||
epicsEventStatus status = epicsEventWaitWithTimeout (this->id, timeOut);
|
||||
epicsEventStatus status = epicsEventWaitWithTimeout (this->id, timeout);
|
||||
|
||||
if (status == epicsEventOK) {
|
||||
return true;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* \brief APIs for the epicsEvent binary semaphore.
|
||||
*
|
||||
* Defines the C++ and C API's for a simple binary semaphore. If multiple threads are
|
||||
* waiting on the same event, only one of them will be woken when the event is signalled.
|
||||
* waiting on the same event, only one of them will be woken when the event is signaled.
|
||||
*
|
||||
* The primary use of an event semaphore is for thread synchronization. An example of using an
|
||||
* event semaphore is a consumer thread that processes requests from one or more producer threads.
|
||||
@@ -99,17 +99,19 @@ public:
|
||||
**/
|
||||
void wait ();
|
||||
/**\brief Wait for the event or until the specified timeout.
|
||||
* \param timeOut The timeout delay in seconds.
|
||||
* \param timeout The timeout delay in seconds. A timeout of zero is
|
||||
* equivalent to calling tryWait(); NaN or any value too large to be
|
||||
* represented to the target OS is equivalent to no timeout.
|
||||
* \return True if the event was triggered, False if it timed out.
|
||||
**/
|
||||
bool wait ( double timeOut );
|
||||
/**\brief Similar to wait() except that if the event is currenly empty the
|
||||
bool wait ( double timeout );
|
||||
/**\brief Similar to wait() except that if the event is currently empty the
|
||||
* call will return immediately.
|
||||
* \return True if the event was full (triggered), False if empty.
|
||||
**/
|
||||
bool tryWait ();
|
||||
/**\brief Display information about the semaphore.
|
||||
* \note The information displayed is architecture dependant.
|
||||
* \note The information displayed is architecture dependent.
|
||||
* \param level An unsigned int for the level of information to be displayed.
|
||||
**/
|
||||
void show ( unsigned level ) const;
|
||||
@@ -190,13 +192,15 @@ LIBCOM_API void epicsEventMustWait(epicsEventId id);
|
||||
/**\brief Wait an the event or until the specified timeout period is over.
|
||||
* \note Blocks until full or timeout.
|
||||
* \param id The event identifier.
|
||||
* \param timeOut The timeout delay in seconds.
|
||||
* \param timeout The timeout delay in seconds. A timeout of zero is
|
||||
* equivalent to calling epicsEventTryWait(); NaN or any value too large
|
||||
* to be represented to the target OS is equivalent to no timeout.
|
||||
* \return Status indicator.
|
||||
**/
|
||||
LIBCOM_API epicsEventStatus epicsEventWaitWithTimeout(
|
||||
epicsEventId id, double timeOut);
|
||||
epicsEventId id, double timeout);
|
||||
|
||||
/**\brief Similar to wait() except that if the event is currenly empty the
|
||||
/**\brief Similar to wait() except that if the event is currently empty the
|
||||
* call will return immediately with status \c epicsEventWaitTimeout.
|
||||
* \param id The event identifier.
|
||||
* \return Status indicator, \c epicsEventWaitTimeout when the event is empty.
|
||||
@@ -205,7 +209,7 @@ LIBCOM_API epicsEventStatus epicsEventTryWait(
|
||||
epicsEventId id);
|
||||
|
||||
/**\brief Display information about the semaphore.
|
||||
* \note The information displayed is architecture dependant.
|
||||
* \note The information displayed is architecture dependent.
|
||||
* \param id The event identifier.
|
||||
* \param level An unsigned int for the level of information to be displayed.
|
||||
**/
|
||||
|
||||
@@ -56,7 +56,7 @@ extern "C" {
|
||||
**/
|
||||
#define NUM_TIME_EVENTS 256
|
||||
|
||||
/**\brief Initialise the framework.
|
||||
/**\brief Initialize the framework.
|
||||
*
|
||||
* This routine is called automatically by any function that requires the
|
||||
* framework. It does not need to be called explicitly.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2010 UChicago Argonna LLC, as Operator of Argonne
|
||||
* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* SPDX-License-Identifier: EPICS
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
@@ -33,8 +33,8 @@ static float makeINF ( void )
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
float epicsNAN = NAN;
|
||||
float epicsINF = INFINITY;
|
||||
const float epicsNAN = NAN;
|
||||
const float epicsINF = INFINITY;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
@@ -84,6 +84,11 @@ public:
|
||||
|
||||
/**
|
||||
* \brief Send a message or timeout.
|
||||
* \param message Pointer to the message to be sent
|
||||
* \param messageSize The size of \p message
|
||||
* \param timeout The timeout delay in seconds. A timeout of zero is
|
||||
* equivalent to calling trySend(); NaN or any value too large to be
|
||||
* represented to the target OS is equivalent to no timeout.
|
||||
* \returns 0 if the message was sent to a receiver or queued for
|
||||
* future delivery.
|
||||
* \returns -1 if the timeout was reached before the
|
||||
@@ -94,6 +99,9 @@ public:
|
||||
|
||||
/**
|
||||
* \brief Try to receive a message.
|
||||
* \param[out] message Output buffer to store the received message
|
||||
* \param size Size of the buffer pointed to by \p message
|
||||
*
|
||||
* If the queue holds at least one message,
|
||||
* the first message on the queue is moved to the specified location
|
||||
* and the length of that message is returned.
|
||||
@@ -110,6 +118,9 @@ public:
|
||||
|
||||
/**
|
||||
* \brief Fetch the next message on the queue.
|
||||
* \param[out] message Output buffer to store the received message
|
||||
* \param size Size of the buffer pointed to by \p message
|
||||
*
|
||||
* Wait for a message to be sent if the queue is empty, then move
|
||||
* the first message queued to the specified location.
|
||||
*
|
||||
@@ -124,12 +135,18 @@ public:
|
||||
int receive ( void *message, unsigned int size );
|
||||
|
||||
/**
|
||||
* \brief Wait for a message to be queued.
|
||||
* Wait up to \p timeout seconds for a message to be sent if the queue
|
||||
* is empty, then move the first message to the specified location.
|
||||
* \brief Wait for and fetch the next message.
|
||||
* \param[out] message Output buffer to store the received message
|
||||
* \param size Size of the buffer pointed to by \p message
|
||||
* \param timeout The timeout delay in seconds. A timeout of zero is
|
||||
* equivalent to calling tryReceive(); NaN or any value too large to
|
||||
* be represented to the target OS is equivalent to no timeout.
|
||||
*
|
||||
* If the received message is larger than the specified
|
||||
* messageBufferSize it may either return -1, or truncate the
|
||||
* Waits up to \p timeout seconds for a message to arrive if the queue
|
||||
* is empty, then moves the first message to the message buffer.
|
||||
*
|
||||
* If the received message is larger than the buffer size
|
||||
* the implementation may either return -1, or truncate the
|
||||
* message. It is most efficient if the messageBufferSize is equal
|
||||
* to the maximumMessageSize with which the message queue was
|
||||
* created.
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
epicsMutex::guard_t G(lock); // lock
|
||||
// process resources
|
||||
} // unlock
|
||||
// or for compatiblity
|
||||
// or for compatibility
|
||||
{
|
||||
epicsGuard<epicsMutex> G(lock); // lock
|
||||
// process resources
|
||||
@@ -99,7 +99,7 @@ public:
|
||||
|
||||
/**\brief Display information about the semaphore.
|
||||
*
|
||||
* \note Results are architecture dependant.
|
||||
* \note Results are architecture dependent.
|
||||
*
|
||||
* \param level Desired information level to report
|
||||
**/
|
||||
@@ -229,7 +229,7 @@ LIBCOM_API epicsMutexLockStatus epicsStdCall epicsMutexTryLock(
|
||||
|
||||
/**\brief Display information about the semaphore.
|
||||
*
|
||||
* \note Results are architecture dependant.
|
||||
* \note Results are architecture dependent.
|
||||
*
|
||||
* \param id The mutex identifier.
|
||||
* \param level Desired information level to report
|
||||
@@ -239,7 +239,7 @@ LIBCOM_API void epicsStdCall epicsMutexShow(
|
||||
|
||||
/**\brief Display information about all epicsMutex semaphores.
|
||||
*
|
||||
* \note Results are architecture dependant.
|
||||
* \note Results are architecture dependent.
|
||||
*
|
||||
* \param onlyLocked Non-zero to show only locked semaphores.
|
||||
* \param level Desired information level to report
|
||||
|
||||
@@ -13,31 +13,7 @@
|
||||
#include <errno.h>
|
||||
|
||||
#include "envDefs.h"
|
||||
#include "epicsReadline.h"
|
||||
|
||||
/* Basic command-line input, no editing or history: */
|
||||
#define EPICS_COMMANDLINE_LIBRARY_EPICS 0
|
||||
|
||||
/* OS-specific command-line editing and/or history: */
|
||||
#define EPICS_COMMANDLINE_LIBRARY_LIBTECLA 1
|
||||
#define EPICS_COMMANDLINE_LIBRARY_LEDLIB 1
|
||||
#define EPICS_COMMANDLINE_LIBRARY_OTHER 1
|
||||
|
||||
/* GNU readline, or Apple's libedit wrapper: */
|
||||
#define EPICS_COMMANDLINE_LIBRARY_READLINE 2
|
||||
#define EPICS_COMMANDLINE_LIBRARY_READLINE_CURSES 2
|
||||
#define EPICS_COMMANDLINE_LIBRARY_READLINE_NCURSES 2
|
||||
|
||||
#ifndef EPICS_COMMANDLINE_LIBRARY
|
||||
# define EPICS_COMMANDLINE_LIBRARY EPICS_COMMANDLINE_LIBRARY_EPICS
|
||||
#endif
|
||||
|
||||
struct osdContext;
|
||||
struct readlineContext {
|
||||
FILE *in;
|
||||
char *line;
|
||||
struct osdContext *osd;
|
||||
};
|
||||
#include "epicsReadlinePvt.h"
|
||||
|
||||
static void osdReadlineBegin(struct readlineContext *);
|
||||
static char * osdReadline(const char *prompt, struct readlineContext *);
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Saskatchewan
|
||||
* Copyright (c) 2015 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* SPDX-License-Identifier: EPICS
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
#ifndef EPICSREADLINEPVT_H
|
||||
#define EPICSREADLINEPVT_H
|
||||
|
||||
#include "epicsReadline.h"
|
||||
|
||||
/* Basic command-line input, no editing or history: */
|
||||
#define EPICS_COMMANDLINE_LIBRARY_EPICS 0
|
||||
|
||||
/* OS-specific command-line editing and/or history: */
|
||||
#define EPICS_COMMANDLINE_LIBRARY_LIBTECLA 1
|
||||
#define EPICS_COMMANDLINE_LIBRARY_LEDLIB 1
|
||||
#define EPICS_COMMANDLINE_LIBRARY_OTHER 1
|
||||
|
||||
/* GNU readline, or Apple's libedit wrapper: */
|
||||
#define EPICS_COMMANDLINE_LIBRARY_READLINE 2
|
||||
#define EPICS_COMMANDLINE_LIBRARY_READLINE_CURSES 2
|
||||
#define EPICS_COMMANDLINE_LIBRARY_READLINE_NCURSES 2
|
||||
|
||||
#ifndef EPICS_COMMANDLINE_LIBRARY
|
||||
# define EPICS_COMMANDLINE_LIBRARY EPICS_COMMANDLINE_LIBRARY_EPICS
|
||||
#endif
|
||||
|
||||
struct osdContext;
|
||||
struct readlineContext {
|
||||
FILE *in;
|
||||
char *line;
|
||||
struct osdContext *osd;
|
||||
};
|
||||
|
||||
#endif // EPICSREADLINEPVT_H
|
||||
@@ -7,6 +7,14 @@
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/**
|
||||
* \file epicsSpin.h
|
||||
*
|
||||
* \brief OS independent interface for creating spin locks
|
||||
*
|
||||
* OS independent interface for creating spin locks. Implemented using the
|
||||
* OS-specific spinlock interface if available. Otherwise uses epicsMutexLock.
|
||||
*/
|
||||
#ifndef epicsSpinh
|
||||
#define epicsSpinh
|
||||
|
||||
@@ -16,15 +24,61 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/** Handle to spin lock*/
|
||||
typedef struct epicsSpin *epicsSpinId;
|
||||
|
||||
/** \brief Creates a spin lock
|
||||
*
|
||||
* Creates a spin lock
|
||||
*
|
||||
* \return Handle to spinlock or NULL if failed
|
||||
* to create the lock
|
||||
*/
|
||||
LIBCOM_API epicsSpinId epicsSpinCreate(void);
|
||||
LIBCOM_API epicsSpinId epicsSpinMustCreate(void);
|
||||
LIBCOM_API void epicsSpinDestroy(epicsSpinId);
|
||||
|
||||
LIBCOM_API void epicsSpinLock(epicsSpinId);
|
||||
LIBCOM_API int epicsSpinTryLock(epicsSpinId);
|
||||
LIBCOM_API void epicsSpinUnlock(epicsSpinId);
|
||||
/** \brief Creates a spin lock
|
||||
*
|
||||
* Creates a spin lock. Calls cantProceed() if unable
|
||||
* to create lock
|
||||
*/
|
||||
LIBCOM_API epicsSpinId epicsSpinMustCreate(void);
|
||||
|
||||
/** \brief Destroys spin lock
|
||||
*
|
||||
* Destroys the spin lock
|
||||
*
|
||||
* \param lockId identifies the spinlock
|
||||
*/
|
||||
LIBCOM_API void epicsSpinDestroy(epicsSpinId lockId);
|
||||
|
||||
/** \brief Acquires the spin lock
|
||||
*
|
||||
* Acquires the lock. Blocks if lock is unavailable
|
||||
*
|
||||
* \param lockId identifies the spinlock
|
||||
*/
|
||||
LIBCOM_API void epicsSpinLock(epicsSpinId lockId);
|
||||
|
||||
/** \brief Tries to acquire the spin lock
|
||||
*
|
||||
* Tries to acquire the lock. If failed, return immediately
|
||||
* with non-zero error code.
|
||||
*
|
||||
* \param lockId identifies the spinlock
|
||||
*
|
||||
* \return 0 if lock was acquired. 1 if failed because acquired by another thread.
|
||||
* Otherwise returns non-zero OS specific return code if failed for any other reason
|
||||
*/
|
||||
LIBCOM_API int epicsSpinTryLock(epicsSpinId lockId);
|
||||
|
||||
/** \brief Releases spin lock
|
||||
*
|
||||
* Releases spin lock
|
||||
*
|
||||
* \param lockId identifies the spinlock
|
||||
*/
|
||||
LIBCOM_API void epicsSpinUnlock(epicsSpinId lockId);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
* Author: Till Straumann <strauman@slac.stanford.edu>, 2011, 2014
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file epicsStackTrace.h
|
||||
*
|
||||
* Functions for printing the stack trace
|
||||
*/
|
||||
#ifndef INC_epicsStackTrace_H
|
||||
#define INC_epicsStackTrace_H
|
||||
|
||||
@@ -17,24 +22,34 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Dump a stack trace to the errlog */
|
||||
/** \brief Dump a stack trace
|
||||
*
|
||||
* Dump a stack trace to the errlog.
|
||||
*/
|
||||
LIBCOM_API void epicsStackTrace(void);
|
||||
|
||||
/* Inquire about functionality implemented on your system */
|
||||
|
||||
/* StackTrace provides numerical addresses */
|
||||
/** Bit mask to check if stack trace provides numerical addresses.*/
|
||||
#define EPICS_STACKTRACE_ADDRESSES (1<<0)
|
||||
|
||||
/* StackTrace is able to lookup dynamic symbols */
|
||||
/** Bit mask to check if stack trace is able to lookup dynamic symbols.*/
|
||||
#define EPICS_STACKTRACE_DYN_SYMBOLS (1<<1)
|
||||
|
||||
/* StackTrace is able to lookup global symbols */
|
||||
/** Bit mask to check if stack trace is able to lookup global symbols */
|
||||
#define EPICS_STACKTRACE_GBL_SYMBOLS (1<<2)
|
||||
|
||||
/* StackTrace is able to lookup local symbols */
|
||||
/** Bit mask to check if stack trace is able to lookup local symbols */
|
||||
#define EPICS_STACKTRACE_LCL_SYMBOLS (1<<3)
|
||||
|
||||
/* returns ORed bitset of supported features */
|
||||
/** \brief Get supported stacktrace features
|
||||
*
|
||||
* Returns an ORed bitset of supported features. Use the EPICS_STACKTRACE_ masks to
|
||||
* check if a feature is supported.
|
||||
*
|
||||
* \return 0 if getting the stack trace is unsupported. Otherwise
|
||||
* returns an ORed bitset of supported features.
|
||||
*/
|
||||
LIBCOM_API int epicsStackTraceGetFeatures(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -118,6 +118,11 @@ int epicsStdCall epicsStdoutPrintf(const char *pFormat, ...)
|
||||
return nchar;
|
||||
}
|
||||
|
||||
int epicsStdCall epicsStdoutVPrintf(const char *pformat, va_list ap)
|
||||
{
|
||||
return vfprintf(epicsGetStdout(), pformat, ap);
|
||||
}
|
||||
|
||||
int epicsStdCall epicsStdoutPuts(const char *str)
|
||||
{
|
||||
return fprintf(epicsGetStdout(), "%s\n", str);
|
||||
|
||||
@@ -9,16 +9,19 @@
|
||||
\*************************************************************************/
|
||||
/**
|
||||
* \file epicsStdio.h
|
||||
* \brief Standardize the behaviour of stdio across EPICS targets
|
||||
* \brief Standardize the behavior of stdio across EPICS targets
|
||||
*
|
||||
* \details
|
||||
* The `epicsStdio.h` header includes the operating system's `stdio.h` header
|
||||
* and if used should replace it.
|
||||
*
|
||||
* epicsSnprintf() and epicsVsnprintf() have the same semantics as the C99
|
||||
* functions snprintf() and vsnprintf(), but correct the behaviour of the
|
||||
* functions snprintf() and vsnprintf(), but correct the behavior of the
|
||||
* implementations on some operating systems.
|
||||
*
|
||||
* @note Define `epicsStdioStdStreams` and/or `epicsStdioStdPrintfEtc`
|
||||
* to opt out of the redirection described below.
|
||||
*
|
||||
* The routines epicsGetStdin(), epicsGetStdout(), epicsGetStderr(),
|
||||
* epicsStdoutPrintf(), epicsStdoutPuts(), and epicsStdoutPutchar()
|
||||
* are not normally named directly in user code. They are provided for use by
|
||||
@@ -36,12 +39,19 @@
|
||||
* - `printf` becomes epicsStdoutPrintf()
|
||||
* - `puts` becomes epicsStdoutPuts()
|
||||
* - `putchar` becomes epicsStdoutPutchar()
|
||||
* - `vprintf` becomes epicsStdoutVPrintf()
|
||||
*
|
||||
* The epicsSetThreadStdin(), epicsSetThreadStdout() and epicsSetThreadStderr()
|
||||
* routines allow the standard file streams to be redirected on a per thread
|
||||
* basis, e.g. calling epicsThreadStdout() will affect only the thread which
|
||||
* calls it. To cancel a stream redirection, pass a NULL argument in another
|
||||
* call to the same redirection routine that was used to set it.
|
||||
*
|
||||
* @since 3.15.6 define `epicsStdioStdPrintfEtc` to opt out of redefinition
|
||||
* for `printf`, `vprintf`, `puts`, and `putchar`.
|
||||
*
|
||||
* @since 3.15.0 define `epicsStdioStdStreams` to opt out of redefinition
|
||||
* of `stdin`, `stdout`, and `stderr`.
|
||||
*/
|
||||
|
||||
#ifndef epicsStdioh
|
||||
@@ -75,6 +85,11 @@ extern "C" {
|
||||
# endif
|
||||
# define printf epicsStdoutPrintf
|
||||
|
||||
# ifdef vprintf
|
||||
# undef vprintf
|
||||
# endif
|
||||
# define vprintf epicsStdoutVPrintf
|
||||
|
||||
# ifdef puts
|
||||
# undef puts
|
||||
# endif
|
||||
@@ -172,6 +187,8 @@ LIBCOM_API void epicsStdCall epicsSetThreadStderr(FILE *);
|
||||
|
||||
LIBCOM_API int epicsStdCall epicsStdoutPrintf(
|
||||
const char *pformat, ...) EPICS_PRINTF_STYLE(1,2);
|
||||
LIBCOM_API int epicsStdCall epicsStdoutVPrintf(
|
||||
const char *pformat, va_list ap);
|
||||
LIBCOM_API int epicsStdCall epicsStdoutPuts(const char *str);
|
||||
LIBCOM_API int epicsStdCall epicsStdoutPutchar(int c);
|
||||
|
||||
@@ -185,6 +202,7 @@ using ::epicsGetStdin;
|
||||
using ::epicsGetStdout;
|
||||
using ::epicsGetStderr;
|
||||
using ::epicsStdoutPrintf;
|
||||
using ::epicsStdoutVPrintf;
|
||||
using ::epicsStdoutPuts;
|
||||
using ::epicsStdoutPutchar;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
/* epicsStdioRedirect.h */
|
||||
|
||||
/* This file is now obselete, and is likely to be
|
||||
/* This file is now obsolete, and is likely to be
|
||||
* deleted in a future release of EPICS Base.
|
||||
*
|
||||
* Use the epicsStdio.h header file instead.
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* \brief C++ and C descriptions for a thread.
|
||||
*
|
||||
* The epicsThread API is meant as a somewhat minimal interface for
|
||||
* multithreaded applications. It can be implementedon a wide variety of
|
||||
* multithreaded applications. It can be implemented on a wide variety of
|
||||
* systems with the restriction that the system MUST support a
|
||||
* multithreaded environment.
|
||||
* A POSIX pthreads version is provided.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+339
-364
@@ -26,6 +26,14 @@
|
||||
/** \brief The EPICS Epoch is 00:00:00 Jan 1, 1990 UTC */
|
||||
#define POSIX_TIME_AT_EPICS_EPOCH 631152000u
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <stdexcept>
|
||||
#include <ostream>
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \brief EPICS time stamp, for use from C code.
|
||||
*
|
||||
* Because it uses an unsigned 32-bit integer to hold the seconds count, an
|
||||
@@ -65,277 +73,6 @@ struct timespec; /* POSIX real time */
|
||||
*/
|
||||
struct timeval; /* BSD */
|
||||
|
||||
/** \struct l_fp
|
||||
* \brief Network Time Protocol timestamp
|
||||
*
|
||||
* Network Time Protocol timestamp. The fields are:
|
||||
* \li \c lui - Number of seconds since 1900 (The NTP epoch)
|
||||
* \li \c luf - Fraction of a second. For example 0x800000000 represents 1/2 second.
|
||||
*/
|
||||
struct l_fp; /* NTP timestamp */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
/** \brief C++ only ANSI C <tt>struct tm</tt> with nanoseconds, local timezone
|
||||
*
|
||||
* Extend ANSI C "struct tm" to include nano seconds within a second
|
||||
* and a struct tm that is adjusted for the local timezone.
|
||||
*/
|
||||
struct local_tm_nano_sec {
|
||||
struct tm ansi_tm; /**< \brief ANSI C time details */
|
||||
unsigned long nSec; /**< \brief nanoseconds extension */
|
||||
};
|
||||
|
||||
/** \brief C++ only ANSI C <tt>sruct tm</tt> with nanoseconds, UTC
|
||||
*
|
||||
* Extend ANSI C "struct tm" to include nanoseconds within a second
|
||||
* and a struct tm that is adjusted for GMT (UTC).
|
||||
*/
|
||||
struct gm_tm_nano_sec {
|
||||
struct tm ansi_tm; /**< \brief ANSI C time details */
|
||||
unsigned long nSec; /**< \brief nanoseconds extension */
|
||||
};
|
||||
|
||||
/** \brief C++ only ANSI C time_t
|
||||
*
|
||||
* This is for converting to/from the ANSI C \c time_t. Since \c time_t
|
||||
* is usually an elementary type providing a conversion operator from
|
||||
* \c time_t to/from epicsTime could cause undesirable implicit
|
||||
* conversions. Providing a conversion operator to/from the
|
||||
* \c time_t_wrapper instead prevents implicit conversions.
|
||||
*/
|
||||
struct time_t_wrapper {
|
||||
time_t ts;
|
||||
};
|
||||
|
||||
/** \brief C++ Event number wrapper class
|
||||
*
|
||||
* Stores an event number for use by the epicsTime::getEvent() static
|
||||
* class method.
|
||||
*/
|
||||
class LIBCOM_API epicsTimeEvent
|
||||
{
|
||||
public:
|
||||
epicsTimeEvent (const int &number); /**< \brief Constructor */
|
||||
operator int () const; /**< \brief Extractor */
|
||||
private:
|
||||
int eventNumber;
|
||||
};
|
||||
|
||||
/** \brief C++ time stamp object
|
||||
*
|
||||
* Holds an EPICS time stamp, and provides conversion functions for both
|
||||
* input and output from/to other types.
|
||||
*
|
||||
* \note Time conversions: The epicsTime implementation will properly
|
||||
* convert between the various formats from the beginning of the EPICS
|
||||
* epoch until at least 2038. Unless the underlying architecture support
|
||||
* has defective POSIX, BSD/SRV5, or standard C time support the EPICS
|
||||
* implementation should be valid until 2106.
|
||||
*/
|
||||
class LIBCOM_API epicsTime
|
||||
{
|
||||
public:
|
||||
/// \brief Exception: Time provider problem
|
||||
class unableToFetchCurrentTime {};
|
||||
/// \brief Exception: Bad field(s) in <tt>struct tm</tt>
|
||||
class formatProblemWithStructTM {};
|
||||
|
||||
/** \brief The default constructor sets the time to the EPICS epoch. */
|
||||
epicsTime ();
|
||||
|
||||
/** \brief Get time of event system event.
|
||||
*
|
||||
* Returns an epicsTime indicating when the associated event system
|
||||
* event last occurred.
|
||||
*/
|
||||
static epicsTime getEvent ( const epicsTimeEvent & );
|
||||
/** \brief Get current clock time
|
||||
*
|
||||
* Returns an epicsTime containing the current time. For example:
|
||||
* \code{.cpp}
|
||||
* epicsTime now = epicsTime::getCurrent();
|
||||
* \endcode
|
||||
*/
|
||||
static epicsTime getCurrent ();
|
||||
/** \brief Get current monotonic time
|
||||
*
|
||||
* Returns an epicsTime containing the current monotonic time, an
|
||||
* OS clock which never going backwards or jumping forwards.
|
||||
* This time is has an undefined epoch, and is only useful for
|
||||
* measuring time differences.
|
||||
*/
|
||||
static epicsTime getMonotonic ();
|
||||
|
||||
/** \name epicsTimeStamp conversions
|
||||
* Convert to and from EPICS epicsTimeStamp format
|
||||
* @{ */
|
||||
/** \brief Convert to epicsTimeStamp */
|
||||
operator epicsTimeStamp () const;
|
||||
/** \brief Construct from epicsTimeStamp */
|
||||
epicsTime ( const epicsTimeStamp & ts );
|
||||
/** \brief Assign from epicsTimeStamp */
|
||||
epicsTime & operator = ( const epicsTimeStamp & );
|
||||
/** @} */
|
||||
|
||||
/** \name ANSI C time_t conversions
|
||||
* Convert to and from ANSI C \c time_t wrapper .
|
||||
* @{ */
|
||||
/** \brief Convert to ANSI C \c time_t */
|
||||
operator time_t_wrapper () const;
|
||||
/** \brief Construct from ANSI C \c time_t */
|
||||
epicsTime ( const time_t_wrapper & );
|
||||
/** \brief Assign from ANSI C \c time_t */
|
||||
epicsTime & operator = ( const time_t_wrapper & );
|
||||
/** @} */
|
||||
|
||||
/** \name ANSI C struct tm local-time conversions
|
||||
* Convert to and from ANSI Cs <tt>struct tm</tt> (with nano seconds),
|
||||
* adjusted for the local time zone.
|
||||
* @{ */
|
||||
/** \brief Convert to <tt>struct tm</tt> in local time zone */
|
||||
operator local_tm_nano_sec () const;
|
||||
/** \brief Construct from <tt>struct tm</tt> in local time zone */
|
||||
epicsTime ( const local_tm_nano_sec & );
|
||||
/** \brief Assign from <tt>struct tm</tt> in local time zone */
|
||||
epicsTime & operator = ( const local_tm_nano_sec & );
|
||||
/** @} */
|
||||
|
||||
/** \name ANSI C struct tm UTC conversions
|
||||
* Convert to and from ANSI Cs <tt>struct tm</tt> (with nano seconds),
|
||||
* adjusted for Greenwich Mean Time (UTC).
|
||||
* @{ */
|
||||
/** \brief Convert to <tt>struct tm</tt> in UTC/GMT */
|
||||
operator gm_tm_nano_sec () const;
|
||||
/** \brief Construct from <tt>struct tm</tt> in UTC/GMT */
|
||||
epicsTime ( const gm_tm_nano_sec & );
|
||||
/** \brief Assign from <tt>struct tm</tt> in UTC */
|
||||
epicsTime & operator = ( const gm_tm_nano_sec & );
|
||||
/** @} */
|
||||
|
||||
/** \name POSIX RT struct timespec conversions
|
||||
* Convert to and from the POSIX RealTime <tt>struct timespec</tt>
|
||||
* format.
|
||||
* @{ */
|
||||
/** \brief Convert to <tt>struct timespec</tt> */
|
||||
operator struct timespec () const;
|
||||
/** \brief Construct from <tt>struct timespec</tt> */
|
||||
epicsTime ( const struct timespec & );
|
||||
/** \brief Assign from <tt>struct timespec</tt> */
|
||||
epicsTime & operator = ( const struct timespec & );
|
||||
/** @} */
|
||||
|
||||
/** \name BSD's struct timeval conversions
|
||||
* Convert to and from the BSD <tt>struct timeval</tt> format.
|
||||
* @{ */
|
||||
/** \brief Convert to <tt>struct timeval</tt> */
|
||||
operator struct timeval () const;
|
||||
/** \brief Construct from <tt>struct timeval</tt> */
|
||||
epicsTime ( const struct timeval & );
|
||||
/** \brief Assign from <tt>struct timeval</tt> */
|
||||
epicsTime & operator = ( const struct timeval & );
|
||||
/** @} */
|
||||
|
||||
/** \name NTP timestamp conversions
|
||||
* Convert to and from the NTP timestamp structure \c l_fp
|
||||
* @{ */
|
||||
/** \brief Convert to NTP format */
|
||||
operator l_fp () const;
|
||||
/** \brief Construct from NTP format */
|
||||
epicsTime ( const l_fp & );
|
||||
/** \brief Assign from NTP format */
|
||||
epicsTime & operator = ( const l_fp & );
|
||||
/** @} */
|
||||
|
||||
/** \name WIN32 FILETIME conversions
|
||||
* Convert to and from WIN32s <tt> _FILETIME</tt>
|
||||
* \note These are only implemented on Windows targets.
|
||||
* @{ */
|
||||
/** \brief Convert to Windows <tt>struct _FILETIME</tt> */
|
||||
operator struct _FILETIME () const;
|
||||
/** \brief Constuct from Windows <tt>struct _FILETIME</tt> */
|
||||
epicsTime ( const struct _FILETIME & );
|
||||
/** \brief Assign from Windows <tt>struct _FILETIME</tt> */
|
||||
epicsTime & operator = ( const struct _FILETIME & );
|
||||
/** @} */
|
||||
|
||||
/** \name Arithmetic operators
|
||||
* Standard operators involving epicsTime objects and time differences
|
||||
* which are always expressed as a \c double in seconds.
|
||||
* @{ */
|
||||
/// \brief \p lhs minus \p rhs, in seconds
|
||||
double operator- ( const epicsTime & ) const;
|
||||
/// \brief \p lhs plus rhs seconds
|
||||
epicsTime operator+ ( const double & ) const;
|
||||
/// \brief \p lhs minus rhs seconds
|
||||
epicsTime operator- ( const double & ) const;
|
||||
/// \brief add rhs seconds to \p lhs
|
||||
epicsTime operator+= ( const double & );
|
||||
/// \brief subtract rhs seconds from \p lhs
|
||||
epicsTime operator-= ( const double & );
|
||||
/** @} */
|
||||
|
||||
/** \name Comparison operators
|
||||
* Standard comparisons between epicsTime objects.
|
||||
* @{ */
|
||||
/// \brief \p lhs equals \p rhs
|
||||
bool operator == ( const epicsTime & ) const;
|
||||
/// \brief \p lhs not equal to \p rhs
|
||||
bool operator != ( const epicsTime & ) const;
|
||||
/// \brief \p rhs no later than \p lhs
|
||||
bool operator <= ( const epicsTime & ) const;
|
||||
/// \brief \p lhs was before \p rhs
|
||||
bool operator < ( const epicsTime & ) const;
|
||||
/// \brief \p rhs not before \p lhs
|
||||
bool operator >= ( const epicsTime & ) const;
|
||||
/// \brief \p lhs was after \p rhs
|
||||
bool operator > ( const epicsTime & ) const;
|
||||
/** @} */
|
||||
|
||||
/** \brief Convert to string in user-specified format
|
||||
*
|
||||
* This method extends the standard C library routine strftime().
|
||||
* See your OS documentation for details about the standard routine.
|
||||
* The epicsTime method adds support for printing the fractional
|
||||
* portion of the time. It searches the format string for the
|
||||
* sequence <tt>%0<i>n</i>f</tt> where \a n is the desired precision,
|
||||
* and uses this format to convert the fractional seconds with the
|
||||
* requested precision. For example:
|
||||
* \code{.cpp}
|
||||
* epicsTime time = epicsTime::getCurrent();
|
||||
* char buf[30];
|
||||
* time.strftime(buf, 30, "%Y-%m-%d %H:%M:%S.%06f");
|
||||
* printf("%s\n", buf);
|
||||
* \endcode
|
||||
* This will print the current time in the format:
|
||||
* \code
|
||||
* 2001-01-26 20:50:29.813505
|
||||
* \endcode
|
||||
*/
|
||||
size_t strftime ( char * pBuff, size_t bufLength, const char * pFormat ) const;
|
||||
|
||||
/** \brief Dump current state to standard out */
|
||||
void show ( unsigned interestLevel ) const;
|
||||
|
||||
private:
|
||||
/*
|
||||
* private because:
|
||||
* a) application does not break when EPICS epoch is changed
|
||||
* b) no assumptions about internal storage or internal precision
|
||||
* in the application
|
||||
* c) it would be easy to forget which argument is nanoseconds
|
||||
* and which argument is seconds (no help from compiler)
|
||||
*/
|
||||
epicsTime ( const unsigned long secPastEpoch, const unsigned long nSec );
|
||||
void addNanoSec ( long nanoSecAdjust );
|
||||
|
||||
unsigned long secPastEpoch; /* seconds since O000 Jan 1, 1990 */
|
||||
unsigned long nSec; /* nanoseconds within second */
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/** \name Return status values
|
||||
* epicsTime routines return \c S_time_ error status values:
|
||||
* @{
|
||||
@@ -447,7 +184,7 @@ LIBCOM_API int epicsStdCall epicsTimeFromTimeval (
|
||||
|
||||
/** \name Arithmetic operations
|
||||
* Arithmetic operations on epicsTimeStamp objects and time differences
|
||||
* which are always expressed as a \c double in seconds.
|
||||
* which are normally expressed as a \c double in seconds.
|
||||
* @{ */
|
||||
/** \brief Time difference between \p left and \p right in seconds. */
|
||||
LIBCOM_API double epicsStdCall epicsTimeDiffInSeconds (
|
||||
@@ -455,6 +192,12 @@ LIBCOM_API double epicsStdCall epicsTimeDiffInSeconds (
|
||||
/** \brief Add some number of seconds to \p dest */
|
||||
LIBCOM_API void epicsStdCall epicsTimeAddSeconds (
|
||||
epicsTimeStamp * pDest, double secondsToAdd ); /* adds seconds to *pDest */
|
||||
/** \brief Time difference between \p left and \p right, as a signed integer
|
||||
* number of nanoseconds.
|
||||
* @since EPICS 7.0.6.1
|
||||
*/
|
||||
LIBCOM_API epicsInt64 epicsStdCall epicsTimeDiffInNS (
|
||||
const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight);
|
||||
/** @} */
|
||||
|
||||
/** \name Comparison operators
|
||||
@@ -488,7 +231,7 @@ LIBCOM_API size_t epicsStdCall epicsTimeToStrftime (
|
||||
LIBCOM_API void epicsStdCall epicsTimeShow (
|
||||
const epicsTimeStamp *, unsigned interestLevel );
|
||||
|
||||
/** \name Reentrant time_t to struct tm conversions
|
||||
/** \name Re-entrant time_t to struct tm conversions
|
||||
* OS-specific reentrant versions of the ANSI C interface because the
|
||||
* vxWorks \c gmtime_r interface does not match POSIX standards
|
||||
* @{ */
|
||||
@@ -515,98 +258,330 @@ LIBCOM_API void osdMonotonicInit(void);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
/** \brief C++ only ANSI C <tt>struct tm</tt> with nanoseconds, local timezone
|
||||
*
|
||||
* Extend ANSI C "struct tm" to include nano seconds within a second
|
||||
* and a struct tm that is adjusted for the local timezone.
|
||||
*/
|
||||
struct local_tm_nano_sec {
|
||||
struct tm ansi_tm; /**< \brief ANSI C time details */
|
||||
unsigned long nSec; /**< \brief nanoseconds extension */
|
||||
};
|
||||
|
||||
/** \brief C++ only ANSI C <tt>sruct tm</tt> with nanoseconds, UTC
|
||||
*
|
||||
* Extend ANSI C "struct tm" to include nanoseconds within a second
|
||||
* and a struct tm that is adjusted for GMT (UTC).
|
||||
*/
|
||||
struct gm_tm_nano_sec {
|
||||
struct tm ansi_tm; /**< \brief ANSI C time details */
|
||||
unsigned long nSec; /**< \brief nanoseconds extension */
|
||||
};
|
||||
|
||||
/** \brief C++ only ANSI C time_t
|
||||
*
|
||||
* This is for converting to/from the ANSI C \c time_t. Since \c time_t
|
||||
* is usually an elementary type providing a conversion operator from
|
||||
* \c time_t to/from epicsTime could cause undesirable implicit
|
||||
* conversions. Providing a conversion operator to/from the
|
||||
* \c time_t_wrapper instead prevents implicit conversions.
|
||||
*/
|
||||
struct time_t_wrapper {
|
||||
time_t ts;
|
||||
};
|
||||
|
||||
/** \brief C++ Event number wrapper class
|
||||
*
|
||||
* Stores an event number for use by the epicsTime::getEvent() static
|
||||
* class method.
|
||||
*/
|
||||
class LIBCOM_API epicsTimeEvent
|
||||
{
|
||||
public:
|
||||
epicsTimeEvent (const int &number) :eventNumber(number) {}
|
||||
operator int () const { return eventNumber; }
|
||||
private:
|
||||
int eventNumber;
|
||||
};
|
||||
|
||||
/** \brief C++ time stamp object
|
||||
*
|
||||
* Holds an EPICS time stamp, and provides conversion functions for both
|
||||
* input and output from/to other types.
|
||||
*
|
||||
* \note Time conversions: The epicsTime implementation will properly
|
||||
* convert between the various formats from the beginning of the EPICS
|
||||
* epoch until at least 2038. Unless the underlying architecture support
|
||||
* has defective POSIX, BSD/SRV5, or standard C time support the EPICS
|
||||
* implementation should be valid until 2106.
|
||||
*/
|
||||
class LIBCOM_API epicsTime
|
||||
{
|
||||
// translate S_time_* code to exception
|
||||
static void throwError(int code);
|
||||
public:
|
||||
/// \brief Exception: Time provider problem
|
||||
typedef std::runtime_error unableToFetchCurrentTime;
|
||||
/// \brief Exception: Bad field(s) in <tt>struct tm</tt>
|
||||
typedef std::logic_error formatProblemWithStructTM;
|
||||
|
||||
/** \brief The default constructor sets the time to the EPICS epoch. */
|
||||
#if __cplusplus>=201103L
|
||||
constexpr epicsTime() :ts{} {}
|
||||
#else
|
||||
epicsTime () {
|
||||
ts.secPastEpoch = ts.nsec = 0u;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** \brief Get time of event system event.
|
||||
*
|
||||
* Returns an epicsTime indicating when the associated event system
|
||||
* event last occurred.
|
||||
*/
|
||||
static inline epicsTime getEvent ( const epicsTimeEvent & evt) ;
|
||||
/** \brief Get current clock time
|
||||
*
|
||||
* Returns an epicsTime containing the current time. For example:
|
||||
* \code{.cpp}
|
||||
* epicsTime now = epicsTime::getCurrent();
|
||||
* \endcode
|
||||
*/
|
||||
static epicsTime getCurrent ();
|
||||
/** \brief Get current monotonic time
|
||||
*
|
||||
* Returns an epicsTime containing the current monotonic time, an
|
||||
* OS clock which never going backwards or jumping forwards.
|
||||
* This time is has an undefined epoch, and is only useful for
|
||||
* measuring time differences.
|
||||
*/
|
||||
static epicsTime getMonotonic () {
|
||||
epicsTime ret;
|
||||
epicsTimeGetMonotonic(&ret.ts); // can't fail
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** \name epicsTimeStamp conversions
|
||||
* Convert to and from EPICS epicsTimeStamp format
|
||||
* @{ */
|
||||
/** \brief Convert to epicsTimeStamp */
|
||||
operator const epicsTimeStamp& () const { return ts; }
|
||||
/** \brief Construct from epicsTimeStamp */
|
||||
epicsTime ( const epicsTimeStamp & replace );
|
||||
/** \brief Assign from epicsTimeStamp */
|
||||
epicsTime & operator = ( const epicsTimeStamp & replace) {
|
||||
ts = replace;
|
||||
return *this;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** \name ANSI C time_t conversions
|
||||
* Convert to and from ANSI C \c time_t wrapper .
|
||||
* @{ */
|
||||
/** \brief Convert to ANSI C \c time_t */
|
||||
operator time_t_wrapper () const {
|
||||
time_t_wrapper ret;
|
||||
throwError(epicsTimeToTime_t(&ret.ts, &ts));
|
||||
return ret;
|
||||
}
|
||||
/** \brief Construct from ANSI C \c time_t */
|
||||
epicsTime ( const time_t_wrapper & replace ) {
|
||||
throwError(epicsTimeFromTime_t(&ts, replace.ts));
|
||||
}
|
||||
/** \brief Assign from ANSI C \c time_t */
|
||||
epicsTime & operator = ( const time_t_wrapper & replace) {
|
||||
throwError(epicsTimeFromTime_t(&ts, replace.ts));
|
||||
return *this;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** \name ANSI C struct tm local-time conversions
|
||||
* Convert to and from ANSI Cs <tt>struct tm</tt> (with nano seconds),
|
||||
* adjusted for the local time zone.
|
||||
* @{ */
|
||||
/** \brief Convert to <tt>struct tm</tt> in local time zone */
|
||||
operator local_tm_nano_sec () const {
|
||||
local_tm_nano_sec ret;
|
||||
throwError(epicsTimeToTM(&ret.ansi_tm, 0, &ts));
|
||||
ret.nSec = ts.nsec;
|
||||
return ret;
|
||||
}
|
||||
/** \brief Construct from <tt>struct tm</tt> in local time zone */
|
||||
epicsTime ( const local_tm_nano_sec & replace) {
|
||||
throwError(epicsTimeFromTM(&ts, &replace.ansi_tm, replace.nSec));
|
||||
}
|
||||
/** \brief Assign from <tt>struct tm</tt> in local time zone */
|
||||
epicsTime & operator = ( const local_tm_nano_sec & replace) {
|
||||
throwError(epicsTimeFromTM(&ts, &replace.ansi_tm, replace.nSec));
|
||||
return *this;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** \name ANSI C struct tm UTC conversions
|
||||
* Convert to and from ANSI Cs <tt>struct tm</tt> (with nano seconds),
|
||||
* adjusted for Greenwich Mean Time (UTC).
|
||||
* @{ */
|
||||
/** \brief Convert to <tt>struct tm</tt> in UTC/GMT */
|
||||
operator gm_tm_nano_sec () const {
|
||||
gm_tm_nano_sec ret;
|
||||
throwError(epicsTimeToGMTM(&ret.ansi_tm, 0, &ts));
|
||||
ret.nSec = ts.nsec;
|
||||
return ret;
|
||||
}
|
||||
/** \brief Construct from <tt>struct tm</tt> in UTC/GMT */
|
||||
epicsTime ( const gm_tm_nano_sec & replace) {
|
||||
throwError(epicsTimeFromGMTM(&ts, &replace.ansi_tm, replace.nSec));
|
||||
}
|
||||
/** \brief Assign from <tt>struct tm</tt> in UTC */
|
||||
epicsTime & operator = ( const gm_tm_nano_sec & replace) {
|
||||
throwError(epicsTimeFromGMTM(&ts, &replace.ansi_tm, replace.nSec));
|
||||
return *this;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** \name POSIX RT struct timespec conversions
|
||||
* Convert to and from the POSIX RealTime <tt>struct timespec</tt>
|
||||
* format.
|
||||
* @{ */
|
||||
/** \brief Convert to <tt>struct timespec</tt> */
|
||||
operator struct timespec () const {
|
||||
timespec ret;
|
||||
epicsTimeToTimespec(&ret, &ts);
|
||||
return ret;
|
||||
}
|
||||
/** \brief Construct from <tt>struct timespec</tt> */
|
||||
epicsTime ( const struct timespec & replace) {
|
||||
throwError(epicsTimeFromTimespec(&ts, &replace));
|
||||
}
|
||||
/** \brief Assign from <tt>struct timespec</tt> */
|
||||
epicsTime & operator = ( const struct timespec & replace ) {
|
||||
throwError(epicsTimeFromTimespec(&ts, &replace));
|
||||
return *this;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** \name BSD's struct timeval conversions
|
||||
* Convert to and from the BSD <tt>struct timeval</tt> format.
|
||||
* @{ */
|
||||
/** \brief Convert to <tt>struct timeval</tt> */
|
||||
operator struct timeval () const ;
|
||||
/** \brief Construct from <tt>struct timeval</tt> */
|
||||
epicsTime ( const struct timeval & replace);
|
||||
/** \brief Assign from <tt>struct timeval</tt> */
|
||||
epicsTime & operator = ( const struct timeval & replace);
|
||||
/** @} */
|
||||
|
||||
#ifdef _WIN32
|
||||
/** \name WIN32 FILETIME conversions
|
||||
* Convert to and from WIN32s <tt> _FILETIME</tt>
|
||||
* \note These are only implemented on Windows targets.
|
||||
* @{ */
|
||||
/** \brief Convert to Windows <tt>struct _FILETIME</tt> */
|
||||
operator struct _FILETIME () const;
|
||||
/** \brief Construct from Windows <tt>struct _FILETIME</tt> */
|
||||
epicsTime ( const struct _FILETIME & );
|
||||
/** \brief Assign from Windows <tt>struct _FILETIME</tt> */
|
||||
epicsTime & operator = ( const struct _FILETIME & );
|
||||
/** @} */
|
||||
#endif /* _WIN32 */
|
||||
|
||||
/** \name Arithmetic operators
|
||||
* Standard operators involving epicsTime objects and time differences
|
||||
* which are always expressed as a \c double in seconds.
|
||||
* @{ */
|
||||
/// \brief \p lhs minus \p rhs, in seconds
|
||||
double operator- ( const epicsTime & other) const {
|
||||
return epicsTimeDiffInSeconds(&ts, &other.ts);
|
||||
}
|
||||
/// \brief \p lhs plus rhs seconds
|
||||
epicsTime operator+ (double delta) const {
|
||||
epicsTime ret(*this);
|
||||
epicsTimeAddSeconds(&ret.ts, delta);
|
||||
return ret;
|
||||
}
|
||||
/// \brief \p lhs minus rhs seconds
|
||||
epicsTime operator- (double delta ) const {
|
||||
return (*this)+(-delta);
|
||||
}
|
||||
/// \brief add rhs seconds to \p lhs
|
||||
epicsTime operator+= (double delta) {
|
||||
epicsTimeAddSeconds(&ts, delta);
|
||||
return *this;
|
||||
}
|
||||
/// \brief subtract rhs seconds from \p lhs
|
||||
epicsTime operator-= ( double delta ) {
|
||||
return (*this) += (-delta);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** \name Comparison operators
|
||||
* Standard comparisons between epicsTime objects.
|
||||
* @{ */
|
||||
/// \brief \p lhs equals \p rhs
|
||||
bool operator == ( const epicsTime & other) const {
|
||||
return epicsTimeEqual(&ts, &other.ts);
|
||||
}
|
||||
/// \brief \p lhs not equal to \p rhs
|
||||
bool operator != ( const epicsTime & other) const {
|
||||
return epicsTimeNotEqual(&ts, &other.ts);
|
||||
}
|
||||
/// \brief \p rhs no later than \p lhs
|
||||
bool operator <= ( const epicsTime & other) const {
|
||||
return epicsTimeLessThanEqual(&ts, &other.ts);
|
||||
}
|
||||
/// \brief \p lhs was before \p rhs
|
||||
bool operator < ( const epicsTime & other) const {
|
||||
return epicsTimeLessThan(&ts, &other.ts);
|
||||
}
|
||||
/// \brief \p rhs not before \p lhs
|
||||
bool operator >= ( const epicsTime & other) const {
|
||||
return epicsTimeGreaterThanEqual(&ts, &other.ts);
|
||||
}
|
||||
/// \brief \p lhs was after \p rhs
|
||||
bool operator > ( const epicsTime & other) const {
|
||||
return epicsTimeGreaterThan(&ts, &other.ts);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** \brief Convert to string in user-specified format
|
||||
*
|
||||
* This method extends the standard C library routine strftime().
|
||||
* See your OS documentation for details about the standard routine.
|
||||
* The epicsTime method adds support for printing the fractional
|
||||
* portion of the time. It searches the format string for the
|
||||
* sequence <tt>%0<i>n</i>f</tt> where \a n is the desired precision,
|
||||
* and uses this format to convert the fractional seconds with the
|
||||
* requested precision. For example:
|
||||
* \code{.cpp}
|
||||
* epicsTime time = epicsTime::getCurrent();
|
||||
* char buf[30];
|
||||
* time.strftime(buf, 30, "%Y-%m-%d %H:%M:%S.%06f");
|
||||
* printf("%s\n", buf);
|
||||
* \endcode
|
||||
* This will print the current time in the format:
|
||||
* \code
|
||||
* 2001-01-26 20:50:29.813505
|
||||
* \endcode
|
||||
*/
|
||||
size_t strftime ( char * pBuff, size_t bufLength, const char * pFormat ) const {
|
||||
return epicsTimeToStrftime(pBuff, bufLength, pFormat, &ts);
|
||||
}
|
||||
|
||||
/** \brief Dump current state to standard out */
|
||||
void show ( unsigned interestLevel ) const {
|
||||
epicsTimeShow(&ts, interestLevel);
|
||||
}
|
||||
|
||||
private:
|
||||
epicsTimeStamp ts;
|
||||
};
|
||||
|
||||
LIBCOM_API
|
||||
std::ostream& operator<<(std::ostream& strm, const epicsTime& ts);
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* inline member functions ,*/
|
||||
#ifdef __cplusplus
|
||||
|
||||
/* epicsTimeEvent */
|
||||
|
||||
inline epicsTimeEvent::epicsTimeEvent (const int &number) :
|
||||
eventNumber(number) {}
|
||||
|
||||
inline epicsTimeEvent::operator int () const
|
||||
{
|
||||
return this->eventNumber;
|
||||
}
|
||||
|
||||
|
||||
/* epicsTime */
|
||||
|
||||
inline epicsTime epicsTime::operator - ( const double & rhs ) const
|
||||
{
|
||||
return epicsTime::operator + ( -rhs );
|
||||
}
|
||||
|
||||
inline epicsTime epicsTime::operator += ( const double & rhs )
|
||||
{
|
||||
*this = epicsTime::operator + ( rhs );
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline epicsTime epicsTime::operator -= ( const double & rhs )
|
||||
{
|
||||
*this = epicsTime::operator + ( -rhs );
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bool epicsTime::operator == ( const epicsTime & rhs ) const
|
||||
{
|
||||
if ( this->secPastEpoch == rhs.secPastEpoch && this->nSec == rhs.nSec ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool epicsTime::operator != ( const epicsTime & rhs ) const
|
||||
{
|
||||
return !epicsTime::operator == ( rhs );
|
||||
}
|
||||
|
||||
inline bool epicsTime::operator >= ( const epicsTime & rhs ) const
|
||||
{
|
||||
return ! ( *this < rhs );
|
||||
}
|
||||
|
||||
inline bool epicsTime::operator > ( const epicsTime & rhs ) const
|
||||
{
|
||||
return ! ( *this <= rhs );
|
||||
}
|
||||
|
||||
inline epicsTime & epicsTime::operator = ( const local_tm_nano_sec & rhs )
|
||||
{
|
||||
return *this = epicsTime ( rhs );
|
||||
}
|
||||
|
||||
inline epicsTime & epicsTime::operator = ( const gm_tm_nano_sec & rhs )
|
||||
{
|
||||
return *this = epicsTime ( rhs );
|
||||
}
|
||||
|
||||
inline epicsTime & epicsTime::operator = ( const struct timespec & rhs )
|
||||
{
|
||||
*this = epicsTime ( rhs );
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline epicsTime & epicsTime::operator = ( const epicsTimeStamp & rhs )
|
||||
{
|
||||
*this = epicsTime ( rhs );
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline epicsTime & epicsTime::operator = ( const l_fp & rhs )
|
||||
{
|
||||
*this = epicsTime ( rhs );
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline epicsTime & epicsTime::operator = ( const time_t_wrapper & rhs )
|
||||
{
|
||||
*this = epicsTime ( rhs );
|
||||
return *this;
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* epicsTimehInclude */
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
LIBCOM_API extern float epicsNAN;
|
||||
LIBCOM_API extern float epicsINF;
|
||||
LIBCOM_API extern const float epicsNAN;
|
||||
LIBCOM_API extern const float epicsINF;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#define HOST_GETCLOCK
|
||||
#define TIMESPEC struct timespec
|
||||
#define CLOCK_GETTIME(ts) clock_gettime(CLOCK_REALTIME, ts)
|
||||
#define TP_NAME "OS Clock"
|
||||
#define TP_NAME "macOS Clock"
|
||||
#endif
|
||||
|
||||
#define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE
|
||||
|
||||
@@ -21,8 +21,7 @@ char *epicsGetExecName(void)
|
||||
if(!temp) {
|
||||
/* we treat alloc failure as terminal */
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
break;
|
||||
return NULL;
|
||||
}
|
||||
ret = temp;
|
||||
|
||||
@@ -35,9 +34,11 @@ char *epicsGetExecName(void)
|
||||
/* max has been updated with required size */
|
||||
}
|
||||
|
||||
/* TODO: _NSGetExecutablePath() doesn't follow symlinks */
|
||||
/* Resolve soft-links */
|
||||
char *res = realpath(ret, NULL);
|
||||
free(ret);
|
||||
|
||||
return ret;
|
||||
return res;
|
||||
}
|
||||
|
||||
char *epicsGetExecDir(void)
|
||||
@@ -46,7 +47,7 @@ char *epicsGetExecDir(void)
|
||||
if(ret) {
|
||||
char *sep = strrchr(ret, '/');
|
||||
if(sep) {
|
||||
/* nil the charactor after the / */
|
||||
/* nil the character after the / */
|
||||
sep[1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ char *epicsGetExecDir(void)
|
||||
if(ret) {
|
||||
char *sep = strrchr(ret, '/');
|
||||
if(sep) {
|
||||
/* nil the charactor after the / */
|
||||
/* nil the character after the / */
|
||||
sep[1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2021 Fritz Haber Institute, Berlin
|
||||
* SPDX-License-Identifier: EPICS
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* RTEMS osdEvent.c
|
||||
* Author: H. Junkes
|
||||
* junkes@fhi.mpg.de
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <stdint.h>
|
||||
#include <rtems.h>
|
||||
#include <rtems/error.h>
|
||||
|
||||
#include <rtems/thread.h>
|
||||
|
||||
#include "libComAPI.h"
|
||||
#include "epicsEvent.h"
|
||||
|
||||
typedef struct epicsEventOSD {
|
||||
rtems_binary_semaphore rbs;
|
||||
} epicsEventOSD;
|
||||
|
||||
/*
|
||||
* Create a simple binary semaphore
|
||||
*/
|
||||
LIBCOM_API epicsEventId
|
||||
epicsEventCreate(epicsEventInitialState initialState)
|
||||
{
|
||||
epicsEventOSD *pSem = malloc (sizeof(*pSem));
|
||||
|
||||
if (pSem) {
|
||||
rtems_binary_semaphore_init(&pSem->rbs, NULL);
|
||||
if (initialState)
|
||||
rtems_binary_semaphore_post(&pSem->rbs);
|
||||
}
|
||||
return pSem;
|
||||
}
|
||||
|
||||
LIBCOM_API void
|
||||
epicsEventDestroy(epicsEventId pSem)
|
||||
{
|
||||
rtems_binary_semaphore_destroy(&pSem->rbs);
|
||||
}
|
||||
|
||||
LIBCOM_API epicsEventStatus
|
||||
epicsEventTrigger(epicsEventId pSem)
|
||||
{
|
||||
rtems_binary_semaphore_post(&pSem->rbs);
|
||||
return epicsEventOK;
|
||||
}
|
||||
|
||||
LIBCOM_API epicsEventStatus
|
||||
epicsEventWait(epicsEventId pSem)
|
||||
{
|
||||
rtems_binary_semaphore_wait(&pSem->rbs);
|
||||
return epicsEventOK;
|
||||
}
|
||||
|
||||
LIBCOM_API epicsEventStatus
|
||||
epicsEventWaitWithTimeout(epicsEventId pSem, double timeout)
|
||||
{
|
||||
int sc;
|
||||
rtems_interval delay;
|
||||
rtems_interval rate = rtems_clock_get_ticks_per_second();
|
||||
|
||||
if (!rate)
|
||||
return epicsEventError;
|
||||
|
||||
if (timeout <= 0.0) {
|
||||
sc = rtems_binary_semaphore_try_wait(&pSem->rbs);
|
||||
if (!sc)
|
||||
return epicsEventOK;
|
||||
else
|
||||
return epicsEventWaitTimeout;
|
||||
}
|
||||
else if (timeout < (double) UINT32_MAX / rate) {
|
||||
delay = timeout * rate;
|
||||
if (delay == 0) {
|
||||
/* 0 < timeout < 1/rate; round up */
|
||||
delay = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* timeout is NaN or too big to represent; wait forever */
|
||||
delay = RTEMS_NO_TIMEOUT;
|
||||
}
|
||||
|
||||
sc = rtems_binary_semaphore_wait_timed_ticks(&pSem->rbs, delay);
|
||||
if (!sc)
|
||||
return epicsEventOK;
|
||||
else if (sc == ETIMEDOUT)
|
||||
return epicsEventWaitTimeout;
|
||||
else
|
||||
return epicsEventError;
|
||||
}
|
||||
|
||||
LIBCOM_API epicsEventStatus
|
||||
epicsEventTryWait(epicsEventId pSem)
|
||||
{
|
||||
int sc = rtems_binary_semaphore_try_wait(&pSem->rbs);
|
||||
|
||||
if (!sc)
|
||||
return epicsEventOK;
|
||||
else
|
||||
return epicsEventWaitTimeout;
|
||||
}
|
||||
|
||||
LIBCOM_API void
|
||||
epicsEventShow(epicsEventId pSem, unsigned int level)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2021 Fritz Haber Institute, Berlin
|
||||
* SPDX-License-Identifier: EPICS
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/* No definitions are needed for this implementation */
|
||||
@@ -81,13 +81,13 @@ static long rtemsDevMapAddr (epicsAddressType addrType, unsigned options,
|
||||
|
||||
/*
|
||||
* a bus error safe "wordSize" read at the specified address which returns
|
||||
* unsuccessful status if the device isnt present
|
||||
* unsuccessful status if the device isn't present
|
||||
*/
|
||||
static long rtemsDevReadProbe (unsigned wordSize, volatile const void *ptr, void *pValue);
|
||||
|
||||
/*
|
||||
* a bus error safe "wordSize" write at the specified address which returns
|
||||
* unsuccessful status if the device isnt present
|
||||
* unsuccessful status if the device isn't present
|
||||
*/
|
||||
static long rtemsDevWriteProbe (unsigned wordSize, volatile void *ptr, const void *pValue);
|
||||
|
||||
@@ -306,7 +306,7 @@ rtems_status_code bspExtMemProbe(void *addr, int write, int size, void *pval)
|
||||
|
||||
/*
|
||||
* a bus error safe "wordSize" read at the specified address which returns
|
||||
* unsuccessful status if the device isnt present
|
||||
* unsuccessful status if the device isn't present
|
||||
*/
|
||||
static long rtemsDevReadProbe (unsigned wordSize, volatile const void *ptr, void *pValue)
|
||||
{
|
||||
@@ -322,7 +322,7 @@ static long rtemsDevReadProbe (unsigned wordSize, volatile const void *ptr, void
|
||||
|
||||
/*
|
||||
* a bus error safe "wordSize" write at the specified address which returns
|
||||
* unsuccessful status if the device isnt present
|
||||
* unsuccessful status if the device isn't present
|
||||
*/
|
||||
static long rtemsDevWriteProbe (unsigned wordSize, volatile void *ptr, const void *pValue)
|
||||
{
|
||||
|
||||
@@ -35,11 +35,11 @@ extern "C" {
|
||||
#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER
|
||||
EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier (void)
|
||||
{
|
||||
epicsAtomicMemoryBarrierFallback();
|
||||
rbarr();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER
|
||||
#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER
|
||||
EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier (void)
|
||||
{
|
||||
rwbarr();
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
LIBCOM_API extern float epicsNAN;
|
||||
LIBCOM_API extern float epicsINF;
|
||||
LIBCOM_API extern const float epicsNAN;
|
||||
LIBCOM_API extern const float epicsINF;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ 1
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <rtems.h>
|
||||
#include <rtems/error.h>
|
||||
|
||||
@@ -122,19 +123,27 @@ epicsEventWait(epicsEventId id)
|
||||
}
|
||||
|
||||
epicsEventStatus
|
||||
epicsEventWaitWithTimeout(epicsEventId id, double timeOut)
|
||||
epicsEventWaitWithTimeout(epicsEventId id, double timeout)
|
||||
{
|
||||
rtems_id sid = (rtems_id)id;
|
||||
rtems_status_code sc;
|
||||
rtems_interval delay;
|
||||
extern double rtemsTicksPerSecond_double;
|
||||
|
||||
if (timeOut <= 0.0)
|
||||
if (timeout <= 0.0)
|
||||
return epicsEventTryWait(id);
|
||||
SEMSTAT(1)
|
||||
delay = timeOut * rtemsTicksPerSecond_double;
|
||||
if (delay == 0)
|
||||
delay++;
|
||||
if (timeout < (double) UINT32_MAX / rtemsTicksPerSecond_double) {
|
||||
delay = timeout * rtemsTicksPerSecond_double;
|
||||
if (delay == 0) {
|
||||
/* 0 < timeout < 1/rtemsTicksPerSecond, round up */
|
||||
delay++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* timeout is NaN or too big to represent in ticks */
|
||||
delay = RTEMS_NO_TIMEOUT;
|
||||
}
|
||||
sc = rtems_semaphore_obtain (sid, RTEMS_WAIT, delay);
|
||||
if (sc == RTEMS_SUCCESSFUL)
|
||||
return epicsEventOK;
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include <string.h>
|
||||
#include <libtecla.h>
|
||||
|
||||
#include "epicsReadlinePvt.h"
|
||||
|
||||
struct osdContext {};
|
||||
|
||||
/*
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "epicsSignal.h"
|
||||
|
||||
/*
|
||||
* All NOOPs if the os isnt POSIX
|
||||
* All NOOPs if the os isn't POSIX
|
||||
*/
|
||||
LIBCOM_API void epicsStdCall epicsSignalInstallSigHupIgnore ( void ) {}
|
||||
LIBCOM_API void epicsStdCall epicsSignalInstallSigPipeIgnore ( void ) {}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* Andrew Johnson <anj@aps.anl.gov>
|
||||
* Michael Davidsaver <mdavidsaver@bnl.gov>
|
||||
*
|
||||
* Inspired by Linux UP spinlocks implemention
|
||||
* Inspired by Linux UP spinlocks implementation
|
||||
* include/linux/spinlock_api_up.h
|
||||
*/
|
||||
|
||||
|
||||
@@ -219,8 +219,7 @@ threadWrapper (rtems_task_argument arg)
|
||||
*/
|
||||
void epicsThreadExitMain (void)
|
||||
{
|
||||
cantProceed("epicsThreadExitMain() has been deprecated for lack of usage."
|
||||
" Please report if you see this message.");
|
||||
cantProceed("epicsThreadExitMain() must no longer be used.\n");
|
||||
}
|
||||
|
||||
static rtems_status_code
|
||||
@@ -386,7 +385,7 @@ void epicsThreadMustJoin(epicsThreadId id)
|
||||
errlogPrintf("Warning: %s thread self-join of unjoinable\n", v ? v->name : "non-EPICS thread");
|
||||
|
||||
} else {
|
||||
/* try to error nicely, however in all likelyhood de-ref of
|
||||
/* try to error nicely, however in all likelihood de-ref of
|
||||
* 'id' has already caused SIGSEGV as we are racing thread exit,
|
||||
* which free's 'id'.
|
||||
*/
|
||||
|
||||
@@ -49,7 +49,7 @@ EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta )
|
||||
{
|
||||
STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) );
|
||||
MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
|
||||
/* we dont use InterlockedAdd because only latest windows is supported */
|
||||
/* we don't use InterlockedAdd because only latest windows is supported */
|
||||
return delta + ( int ) MS_InterlockedExchangeAdd ( pTarg,
|
||||
( MS_LONG ) delta );
|
||||
}
|
||||
@@ -101,7 +101,7 @@ EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget,
|
||||
size_t delta )
|
||||
{
|
||||
MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
|
||||
/* we dont use InterlockedAdd because only latest windows is supported */
|
||||
/* we don't use InterlockedAdd because only latest windows is supported */
|
||||
return delta + ( size_t ) MS_InterlockedExchangeAdd ( pTarg,
|
||||
( MS_LONG ) delta );
|
||||
}
|
||||
@@ -113,7 +113,7 @@ EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta
|
||||
{
|
||||
MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
|
||||
MS_LONG ldelta = (MS_LONG) delta;
|
||||
/* we dont use InterlockedAdd because only latest windows is supported */
|
||||
/* we don't use InterlockedAdd because only latest windows is supported */
|
||||
return ( ( size_t ) MS_InterlockedExchangeAdd ( pTarg, -ldelta ) ) - delta;
|
||||
}
|
||||
#endif
|
||||
@@ -172,7 +172,7 @@ EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
|
||||
EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta )
|
||||
{
|
||||
MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget );
|
||||
/* we dont use InterlockedAdd64 because only latest windows is supported */
|
||||
/* we don't use InterlockedAdd64 because only latest windows is supported */
|
||||
return delta + ( size_t ) MS_InterlockedExchangeAdd64 ( pTarg,
|
||||
( MS_LONGLONG ) delta );
|
||||
}
|
||||
@@ -184,7 +184,7 @@ EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta
|
||||
{
|
||||
MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget );
|
||||
MS_LONGLONG ldelta = (MS_LONGLONG) delta;
|
||||
/* we dont use InterlockedAdd64 because only latest windows is supported */
|
||||
/* we don't use InterlockedAdd64 because only latest windows is supported */
|
||||
return (( size_t ) MS_InterlockedExchangeAdd64 ( pTarg, -ldelta )) - delta;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
LIBCOM_API extern float epicsNAN;
|
||||
LIBCOM_API extern float epicsINF;
|
||||
LIBCOM_API extern const float epicsNAN;
|
||||
LIBCOM_API extern const float epicsINF;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
/*
|
||||
* epicsTmpFile
|
||||
*
|
||||
* allow the teporary file directory to be set with the
|
||||
* TMP environment varianble
|
||||
* allow the temporary file directory to be set with the
|
||||
* TMP environment variable
|
||||
*/
|
||||
LIBCOM_API FILE * epicsStdCall epicsTempFile ()
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include <new>
|
||||
#include <new.h>
|
||||
|
||||
// instruct loader to call this gllobal object
|
||||
// instruct loader to call this global object
|
||||
// constructor before user global object constructors
|
||||
#pragma warning (disable: 4073)
|
||||
#pragma init_seg(lib)
|
||||
|
||||
@@ -90,7 +90,7 @@ LIBCOM_API epicsEventStatus epicsEventWait ( epicsEventId pSem )
|
||||
* epicsEventWaitWithTimeout ()
|
||||
*/
|
||||
LIBCOM_API epicsEventStatus epicsEventWaitWithTimeout (
|
||||
epicsEventId pSem, double timeOut )
|
||||
epicsEventId pSem, double timeout )
|
||||
{
|
||||
/* waitable timers use 100 nanosecond intervals, like FILETIME */
|
||||
static const unsigned ivalPerSec = 10000000u; /* number of 100ns intervals per second */
|
||||
@@ -101,17 +101,17 @@ LIBCOM_API epicsEventStatus epicsEventWaitWithTimeout (
|
||||
HANDLE timer;
|
||||
LONGLONG nIvals; /* number of intervals */
|
||||
|
||||
if ( timeOut <= 0.0 ) {
|
||||
if ( timeout <= 0.0 ) {
|
||||
tmo.QuadPart = 0u;
|
||||
}
|
||||
else if ( timeOut >= INFINITE / mSecPerSec ) {
|
||||
else if ( timeout >= INFINITE / mSecPerSec ) {
|
||||
/* we need to apply a maximum wait time to stop an overflow. We choose (INFINITE - 1) milliseconds,
|
||||
to be compatible with previous WaitForSingleObject() implementation */
|
||||
nIvals = (LONGLONG)(INFINITE - 1) * (ivalPerSec / mSecPerSec);
|
||||
tmo.QuadPart = -nIvals; /* negative value means a relative time offset for timer */
|
||||
}
|
||||
else {
|
||||
nIvals = (LONGLONG)(timeOut * ivalPerSec + 0.999999);
|
||||
nIvals = (LONGLONG)(timeout * ivalPerSec + 0.999999);
|
||||
tmo.QuadPart = -nIvals;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
static epicsUInt64 osdMonotonicResolution; /* timer resolution in nanoseconds */
|
||||
static epicsUInt64 perfCounterFrequency; /* performance counter tics per second */
|
||||
static LONGLONG perfCounterOffset; /* performance counter value at initialisation */
|
||||
static LONGLONG perfCounterOffset; /* performance counter value at initialization */
|
||||
static const epicsUInt64 sec2nsec = 1000000000; /* number of nanoseconds in a second */
|
||||
|
||||
void osdMonotonicInit(void)
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
* are used. The code does have run time switches so
|
||||
* that the more advanced calls are not called unless
|
||||
* they are available in the windows OS, but this feature
|
||||
* isnt going to be very useful unless we specify "delay
|
||||
* isn't going to be very useful unless we specify "delay
|
||||
* loading" when we link with the DLL.
|
||||
*
|
||||
* It appears that the only entry point used here that causes
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* WIN32 specific initialisation for bsd sockets,
|
||||
* WIN32 specific initialization for bsd sockets,
|
||||
* based on Chris Timossi's base/src/ca/windows_depend.c,
|
||||
* and also further additions by Kay Kasemir when this was in
|
||||
* dllmain.cc
|
||||
@@ -85,14 +85,14 @@ static void osiLocalAddrOnce ( void *raw )
|
||||
for (pIfinfo = pIfinfoList; pIfinfo < (pIfinfoList+numifs); pIfinfo++){
|
||||
|
||||
/*
|
||||
* dont use interfaces that have been disabled
|
||||
* don't use interfaces that have been disabled
|
||||
*/
|
||||
if (!(pIfinfo->iiFlags & IFF_UP)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* dont use the loop back interface
|
||||
* don't use the loop back interface
|
||||
*/
|
||||
if (pIfinfo->iiFlags & IFF_LOOPBACK) {
|
||||
continue;
|
||||
@@ -183,7 +183,7 @@ LIBCOM_API void epicsStdCall osiSockDiscoverBroadcastAddresses
|
||||
for (pIfinfo = pIfinfoList; pIfinfo < (pIfinfoList+numifs); pIfinfo++){
|
||||
|
||||
/*
|
||||
* dont bother with interfaces that have been disabled
|
||||
* don't bother with interfaces that have been disabled
|
||||
*/
|
||||
if (!(pIfinfo->iiFlags & IFF_UP)) {
|
||||
continue;
|
||||
@@ -203,7 +203,7 @@ LIBCOM_API void epicsStdCall osiSockDiscoverBroadcastAddresses
|
||||
}
|
||||
|
||||
/*
|
||||
* if it isnt a wildcarded interface then look for
|
||||
* if it isn't a wildcarded interface then look for
|
||||
* an exact match
|
||||
*/
|
||||
if (pMatchAddr->sa.sa_family != AF_UNSPEC) {
|
||||
|
||||
@@ -71,7 +71,7 @@ LIBCOM_API osiSpawnDetachedProcessReturn epicsStdCall osiSpawnDetachedProcess
|
||||
NULL, /* pointer to thread security attributes */
|
||||
FALSE, /* handle inheritance flag */
|
||||
CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS, /* creation flags */
|
||||
NULL, /* pointer to new environment block (defaults to caller's environement) */
|
||||
NULL, /* pointer to new environment block (defaults to caller's environment) */
|
||||
NULL, /* pointer to current directory name (defaults to caller's current directory) */
|
||||
&startupInfo, /* pointer to STARTUPINFO */
|
||||
&processInfo /* pointer to PROCESS_INFORMATION */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user