Merge branch '7.0' into PSI-7.0

This commit is contained in:
2023-02-15 16:54:36 +01:00
455 changed files with 8983 additions and 5260 deletions
+1 -1
View File
@@ -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"};
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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) {
+6 -1
View File
@@ -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
+1
View File
@@ -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},
+20 -13
View File
@@ -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
+1
View File
@@ -71,6 +71,7 @@ typedef enum {
/* Numeric */
CEIL,
FLOOR,
FMOD,
FINITE,
ISINF,
ISNAN,
+2 -2
View File
@@ -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--){
+81 -8
View File
@@ -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;
};
+79 -156
View File
@@ -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"
+1 -1
View File
@@ -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)
//
+1 -1
View File
@@ -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.
+1 -1
View File
@@ -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
*
*/
+1 -1
View File
@@ -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().
*
+2 -2
View File
@@ -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)
+3
View File
@@ -152,6 +152,9 @@ const char* errSymLookupInternal(long status)
ERRNUMNODE *pNextNode;
ERRNUMNODE **phashnode = NULL;
if (!status)
return "Ok";
if (!initialized)
errSymBld();
+160 -27
View File
@@ -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);
}
+97 -51
View File
@@ -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 le 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: Dont 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 buer. The default buer 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 buer and maximum message size.
* The default buer 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 ushed 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 dened as:
* `errPrintf(status, __FILE__, __LINE__, "<fmt>", ...); `
*
* Where status is defined as:
* - 0: Find latest vxWorks or Unix error.
* - -1: Dont 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 le 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
+3 -3
View File
@@ -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] );
}
+2 -2
View File
@@ -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)
+1 -1
View File
@@ -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(
+3 -3
View File
@@ -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
+1 -1
View File
@@ -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.
*/
+3
View File
@@ -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))
+115 -43
View File
@@ -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
File diff suppressed because it is too large Load Diff
+212 -17
View File
@@ -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
+1 -1
View File
@@ -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"};
+1 -1
View File
@@ -127,7 +127,7 @@ int epicsStdCall iocLogInit (void)
return iocLogSuccess;
}
/*
* dont init twice
* don't init twice
*/
if (iocLogClient!=NULL) {
return iocLogSuccess;
+2 -8
View File
@@ -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
*/
+5 -2
View File
@@ -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;
}
+63 -2
View File
@@ -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);
+2 -2
View File
@@ -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 ) {
+1 -1
View File
@@ -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"
+1 -1
View File
@@ -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 -1
View File
@@ -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.
+2 -2
View File
@@ -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()
*/
/**
+1 -1
View File
@@ -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
+129 -5
View File
@@ -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 librarys 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
+5 -5
View File
@@ -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,
+20 -1
View File
@@ -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);
+13 -8
View File
@@ -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;
+1 -1
View File
@@ -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.
*
+14 -3
View File
@@ -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)
+1 -1
View File
@@ -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)
+4
View File
@@ -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
+4 -4
View File
@@ -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.
*
*/
/******************************************************************************
+2 -2
View File
@@ -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.
+1 -1
View File
@@ -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.
*/
+1 -1
View File
@@ -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.
**/
+334 -26
View File
@@ -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 )
+156
View File
@@ -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 */
+3 -3
View File
@@ -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 -9
View File
@@ -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.
**/
+1 -1
View File
@@ -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.
+3 -3
View File
@@ -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
+22 -5
View File
@@ -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.
+4 -4
View File
@@ -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
+1 -25
View File
@@ -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 *);
+38
View File
@@ -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
+59 -5
View File
@@ -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
}
+21 -6
View File
@@ -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
+5
View File
@@ -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);
+20 -2
View File
@@ -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;
}
+1 -1
View File
@@ -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.
+1 -1
View File
@@ -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
View File
@@ -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 */
+2 -2
View File
@@ -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
}
+1 -1
View File
@@ -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';
}
}
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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)
+4 -4
View File
@@ -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)
+1 -1
View File
@@ -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
+5 -5
View File
@@ -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) {
+1 -1
View File
@@ -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