next up previous contents index
Next: 21. Registry Up: AppDevGuide Previous: 19. libCom   Contents   Index

Subsections

20. libCom OSI libraries

20.1 Overview

Most code in base is operating system independent, i.e. the code is exactly the same for all supported operating systems. This is accomplished by providing epics-specific APIs for facilities that are different on the various systems. These APIs are called Operating System Independent, or OSI, and are part of libCom. The OSI APIs have multiple implementations, which are Operating System Dependent or OSD. Some APIs are implemented using the features of a particular compiler that is supported on multiple operating systems. For example the GNU Compiler Collection (GCC) is used for compiling many targets and provides a common GCC-specific API for some features. Base now makes it possible to use compiler-specific as well as OS-specific code to implement the OSI APIs.

20.1.1 OSI source directory

Directory <base>/src/libCom/osi contains the code for the operating system independent libraries. The structure of this directory is:

osi/
   *.h
   *.c
   *.cpp
   compiler/
       borland/
       clang/
       default/
       gcc/
       msvc/
       solStudio/
   os/
       Linux/
       Darwin/
       RTEMS/
       WIN32/
       default/
       posix/
       solaris/
       vxWorks/

Code for additional compilers and operating systems may also be present.

20.1.2 Rules for building OSI code

The src/libCom/osi directory contains source and header files that provide common definitions for the OSI APIs. The directories under osi/compiler contain compiler-specific files that implement some of the OSI APIs. The directories under osi/os contain operating-system-specific files that implement the remaining OSI APIs.

Header files residing under src/libCom/osi are installed into include as follows:

The search order for locating OSD source files is:

  1. osi/compiler/<cmplr>
  2. osi/compiler/default
  3. osi/os/<os>
  4. osi/os/posix
  5. osi/os/default

20.1.3 Locating OSI header files.

When code is compiled, the search order for locating header files in base/include is:

  1. include/compiler/<cmplr>
  2. include/os/<os>
  3. include

20.2 epicsAssert

This is an enhanced version of ANSI C's assert facility. To use this, replace:

#include <assert.h>

with

#include "epicsAssert.h"

20.2.1 Runtime Assertion Checks

The same assert(expression) macro is used as with the ANSI header to test a run-time assertion.

If a run-time assertion check finds the expression false, it calls errlog indicating the program's author, file name, and line number. Each OS provides specialized instructions assisting the user to diagnose the problem and generate a good bug report. For instance, under vxWorks there are instructions on how to generate a stack trace; on posix there are instructions about saving the core file. After printing the message, the calling thread is suspended.

To provide the author's name for the message, before including the epicsAssert.h file define a preprocessor macro named epicsAssertAuthor as a string containing the name and email address to be contacted.

20.2.2 Compile-time Assertion Checks

The C or C++ compiler can be used to evaluate and check a static expression at compile-time. Static assertions may only be placed where a variable declaration is valid, and can only test certain kinds of constant expressions. A static assertion looks like this:

STATIC_ASSERT(expression);

If the expression evaluates as false, the compiler will be presented with an illegal variable declaration using the name static_assert_failed_at_line_<n> and so should halt compilation at that point.


20.3 epicsAtomic

This is an operating system and compiler independent interface to an operating system and or compiler dependent implementation of several atomic primitives. Currently, only increment, decrement, add, subtract, compare-and-swap, and test-and-set primitives have been implemented as appropriate for the C primitive types of int, size_t, and void * pointer.

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 archetecture 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.

#include <epicsAtomic.h>

20.3.1 C Callable Interface

void epicsAtomicReadMemoryBarrier ();
void epicsAtomicWriteMemoryBarrier ();

size_t epicsAtomicIncrSizeT ( size_t * pTarget );
int epicsAtomicIncrIntT ( int * pTarget );

size_t epicsAtomicDecrSizeT ( size_t * pTarget );
int epicsAtomicDecrIntT ( int * pTarget );

size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta );
size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta );
int epicsAtomicAddIntT ( int * pTarget, int delta );

void epicsAtomicSetSizeT  ( size_t * pTarget, size_t newValue ); 
void epicsAtomicSetIntT ( int * pTarget, int newValue );
void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newValue );

size_t epicsAtomicGetSizeT ( const size_t * pTarget );
int epicsAtomicGetIntT ( const int * pTarget );
EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget );

size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget, 
                                            size_t oldVal, size_t newVal );
int epicsAtomicCmpAndSwapIntT ( int * pTarget, 
                                            int oldVal, int newVal );
EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( 
                                            EpicsAtomicPtrT * pTarget, 
                                            EpicsAtomicPtrT oldVal, 
                                            EpicsAtomicPtrT newVal );

int epicsAtomicTestAndSet ( int * pTarget );

C Function C++ Function Meaning
epicsAtomicReadMemoryBarrier readMemoryBarrier Load target into cache.
epicsAtomicWriteMemoryBarrier writeMemoryBarrier Push cache version of target into target.
epicsAtomicIncrXxxx increment Lock out other SMP processors from accessing the target, load the target into cache, add one to the target, flush cache to the target, allow other SMP processors to access the target, and return the new value of the target as modified by this operation.
epicsAtomicDecrXxxx decrement Lock out other smp processors from accessing the target, load the target into cache, subtract one from the target, flush cache to the target, allow other SMP processors to access the target, and return the new value of target as modified by this operation.
epicsAtomicAddXxxx add Lock out other SMP processors from accessing the target, load the target into cache, add delta to the target, flush the cache to the target, allow other SMP processors to access the target, return new value of target as modified by this operation.
epicsAtomicSubXxxx subtract Lock out other SMP processors from accessing the target, load the target into cache, subtract delta from the target, flush the cache to the target, allow other SMP processors to access the target, return new value of target as modified by this operation.
epicsAtomicSetXxxx set Set the cached version of target, and flush the cache to the target.
epicsAtomicGetXxxx get Fetch the target into cache, and return the cached value.
epicsAtomicCmpAndSwapXxxx compareAndSwap Lock out other SMP processors from accessing the target, load the target into cache, if the target is equal to oldVal set the target to newVal, flush cache to the target, allow other SMP processors to access the target, and return the original value stored in the target.
epicsAtomicTestAndSet testAndSet Lock out other SMP processors from accessing the target, load the target into cache, if the target value is logical false (zero) set the target to be logical true, flush cache to the target, allow other SMP processors to access the target, and return the original value stored in the target.

20.4 epicsEndian

epicsEndian.h provides an operating-system independent means of discovering the native byte order of the CPU which the compiler is targeting, and works in both C and C++ code. It defines the following preprocessor macros, the values of which are integers:

The latter two macros are defined to be one or other of the first two, and may be compared with them to determine conditional compilation or execution of code that performs byte or word swapping as necessary.

#if (EPICS_BYTE_ORDER == EPICS_ENDIAN_BIG)
    /* ... */
#else /* EPICS_ENDIAN_LITTLE */
    /* ... */
#endif /* EPICS_BYTE_ORDER */


20.5 epicsEvent

epicsEvent.h defines the C++ and C APIs 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.

20.5.1 C++ Interface

typedef enum {
    epicsEventOK = 0,
    epicsEventWaitTimeout,
    epicsEventError
} epicsEventStatus;

/* Backwards compatibility */
#define epicsEventWaitStatus epicsEventStatus
#define epicsEventWaitOK epicsEventOK
#define epicsEventWaitError epicsEventError

typedef enum {
    epicsEventEmpty,
    epicsEventFull
} epicsEventInitialState;

class epicsEvent {
public:
    epicsEvent ( epicsEventInitialState initial = epicsEventEmpty );
    ~epicsEvent ();
    void trigger ();
    void signal () { this->trigger(); }
    void wait ();                   /* blocks until full */
    bool wait ( double timeOut );   /* false if still empty at time out */
    bool tryWait ();                /* false if empty */
    void show ( unsigned level ) const;

    class invalidSemaphore;         /* exception payload */
private:
    ...
};

Method Meaning
epicsEvent An epicsEvent can be created empty or full. If it is created empty then a wait issued before a trigger will block. If created full then the first wait will always succeed. Multiple triggers may be issued between waits but have the same effect as a single trigger.
~epicsEvent Remove the event and any resources it uses. Any further use of the semaphore result in unknown (most certainly bad) behavior. No outstanding take can be active when this call is made.
trigger Trigger the event i.e. ensures that the next or current call to wait completes. This method may be called from a vxWorks or RTEMS interrupt handler.
signal A synonym for trigger, provided for backwards compatibility.
wait() Wait for the event to be triggered.
wait(double timeOut) Similar to wait except that if event does not happen the call completes after the specified time out. The return value is true) if the event was triggered, false if it timed out.
tryWait() Similar to wait except that if event has not already been triggered the call completes immediately. The return value is true if an unused event has already been signalled, false if not.
show Display information about the epicsEvent. The information displayed is architecture dependent.

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. For example:

20.5.2 C Interface

epicsEventId epicsEventCreate(epicsEventInitialState initialState);
epicsEventId epicsEventMustCreate(epicsEventInitialState initialState);
void epicsEventDestroy(epicsEventId id);

epicsEventStatus epicsEventTrigger(epicsEventId id);
void epicsEventMustTrigger(epicsEventId id);
#define epicsEventSignal(ID) epicsEventMustTrigger(ID)

epicsEventStatus epicsEventWait(epicsEventId id);
void epicsEventMustWait(epicsEventId id);
epicsEventStatus epicsEventWaitWithTimeout(epicsEventId id, double timeOut);
epicsEventStatus epicsEventTryWait(epicsEventId id);

void epicsEventShow(epicsEventId id, unsigned int level);

The C routines shown above generally correspond to one of the C++ methods. The epicsEventSignal macro provides backwards compatibility. The routines epicsEventMustCreate, epicsEventMustTrigger and epicsEventMustWait do not return if they fail.

20.6 epicsFindSymbol

epicsFindSymbol.h contains the following definitions:

void * epicsFindSymbol(const char *name);
void * epicsLoadLibrary(const char *name);
const char *epicsLoadError(void);

Function Meaning
epicsFindSymbol Return the address of the named variable
epicsLoadLibrary Load named shared library
epicsLoadError Returns an error string if a library load fails

The registry, described in another chapter, provides a way to find and return the address referred to by a registered symbol. Symbols that have not been explicitly registered may not be found. If the registry is asked for a name that has not been registered, it calls epicsFindSymbol. If epicsFindSymbol can locate the symbol, it returns the associated address, otherwise it returns null.

On vxWorks epicsFindSymbol calls symFindByName. On Linux, Darwin and Solaris it calls dlsym. The default version just returns null, i.e. it always fails.

The epicsLoadLibrary routine can be used to load a named library. Note that the library name may be different on different operating systems. This routine is implemented on vxWorks, Linux, Darwin, Windows and Solaris.

If epicsLoadLibrary fails, the routine epicsLoadError can be used to fetch a printable string that describes the reason for the failure. Note that this library loading API is not thread-safe and should not be used in circumstances where multiple threads might try to use it at the same time.

20.7 epicsGeneralTime

The generalTime framework provides a mechanism for several time providers to be present within the system. There are two types of provider, one type for the current time and one type for providing Time Event times. Each time provider has a priority, and installed providers are queried in priority order whenever a time is requested, until one returns successfully. Thus there is a fallback from higher priority providers (smaller value of priority) to lower priority providers (larger value of priority) if the higher priority ones fail. Each architecture has a ``last resort" provider, installed at priority 999, usually based on the system clock, which is used in the absence of any other provider.

Targets running vxWorks and RTEMS have an NTP provider installed at priority 100.

Registered providers may also add an interrupt-safe routine to be called from the epicsTimeGetCurrentInt() or epicsTimeGetEventInt() API routines. These interfaces do not check the priority queue, and will only succeed if the last-used provider has registered a suitable routine.

There are two interfaces to this framework, epicsGeneralTime.h for consumers that wish to get a time and query the framework, and generalTimeSup.h for providers that supply timestamps.

20.7.1 Consumer interface

The epicsGeneralTime.h header contains the following:

void generalTime_Init(void);
int installLastResortEventProvider(void);
void generalTimeResetErrorCounts(void);
int generalTimeGetErrorCounts(void);

const char * generalTimeHighestCurrentName(void);
const char * generalTimeCurrentProviderName(void);
const char * generalTimeEventProviderName(void);

/* Original names, for compatibility */
#define generalTimeCurrentTpName generalTimeCurrentProviderName
#define generalTimeEventTpName generalTimeEventProviderName

long generalTimeReport(int interest);

Function Meaning
generalTime_Init Initialise the framework. This is called automatically by any function that requires the framework. It does not need to be called explicitly.
installLastResortEventProvider Install a Time Event time provider that returns the current time for any Time Event number. This is optional as it is site policy whether the last resort for a Time Event time in the absence of any working provider should be a failure, or the current time.
generalTimeResetErrorCounts Reset the internal counter of the number of times the time returned was earlier than when previously requested. Used by device support for bo record with DTYP = ``General Time" and OUT = ``@RSTERRCNT"
generalTimeGetErrorCounts Return the internal counter of the number of times the time returned was earlier than when previously requested. Used by device support for longin record with DTYP = ``General Time" and INP = ``@GETERRCNT"
generalTimeCurrentProviderName Return the name of the provider that last returned a valid current time, or NULL if none. Used by stringin device support with DTYP = ``General Time" and INP = ``@BESTTCP"
generalTimeEventProviderName Return the name of the provider that last returned a valid Time Event time, or NULL if none. Used by stringin device support with DTYP = ``General Time" and INP = ``@BESTTEP"
generalTimeHighestCurrentName Return the name of the registered current time provider that has the highest priority. Used by stringin device support with DTYP = ``General Time" and INP = ``@TOPTCP"
generalTimeReport Provide information about the installed providers and their current best times.

20.7.2 Time Provider Interface

The generalTimeSup.h header for time providers contains the following:

typedef int (*TIMECURRENTFUN)(epicsTimeStamp *pDest);
typedef int (*TIMEEVENTFUN)(epicsTimeStamp *pDest, int event);

int generalTimeRegisterCurrentProvider(const char *name,
    int priority, TIMECURRENTFUN getTime);
int generalTimeRegisterEventProvider(const char *name,
    int priority, TIMEEVENTFUN getEvent);

/* Original names, for compatibility */
#define generalTimeCurrentTpRegister generalTimeRegisterCurrentProvider
#define generalTimeEventTpRegister generalTimeRegisterEventProvider

int generalTimeAddIntCurrentProvider(const char *name,
    int priority, TIMECURRENTFUN getTime);
int generalTimeAddIntEventProvider(const char *name,
    int priority, TIMEEVENTFUN getEvent);

int generalTimeGetExceptPriority(epicsTimeStamp *pDest, int *pPrio,
        int ignorePrio);

Function Meaning
generalTimeRegisterCurrentProvider Register a current time provider with the framework. The getTime routine must return epicsTimeOK if it provided a valid time, or epicsTimeERROR if it could not.
generalTimeRegisterEventProvider Register a provider of Time Event times with the framework. The getEvent routine must return epicsTimeOK if it provided a valid time for the requested Time Event, or epicsTimeERROR if it could not. It is an implemetation decision by the provider whether a request for an Event that has never happened should return an error and/or a valid timestamp.
generalTimeAddIntCurrentProvider Add or replace an interrupt-safe provider routine for an already-registered current time provider with the given name and priority.
generalTimeAddIntEventProvider Add or replace an interrupt-safe provider routine for an already-registered event time provider with the given name and priority.
generalTimeGetExceptProirity Request the current time from the framework, but exclude providers with priority ignorePrio. This allows a provider without an absolute time source to synchronise itself with other providers that do provide an absolute time. pPrio returns the priority of the provider that supplied the result, which may be higher or lower than ignorePrio.

If multiple providers are registered at the same priority, they will be queried in the order in which they were registered until one is able to provide the time when requested.

Some providers may start a task that periodically synchronizes themselves with a higher priority provider, using generalTimeGetExceptPriority() to ensure that they are themselves excluded from this time request.

Interrupt-safe providers are optional, but an IOC that needs to request the time from interrupt context must be using a current or event time source that supports the appropriate request because only the most recently successful provider will be used (the priority list cannot be traversed for requests made from interrupt context). The result returned by is not protected against backwards movement.

20.7.3 Internal Interface

The generalTime framework also now provides the implementations of the following routines that are declared in epicsTime.h:

int epicsTimeGetCurrent(epicsTimeStamp *pDest);
int epicsTimeGetEvent(epicsTimeStamp *pDest, int eventNumber);
int epicsTimeGetCurrentInt(epicsTimeStamp *pDest);
int epicsTimeGetEventInt(epicsTimeStamp *pDest, int eventNumber);

If epicsTimeGetEvent() is called with an event number of 0 (epicsTimeEventCurrentTime) it will return the time from the best available current time provider. Thus providers do not need to provide event times if they do not implement an event system.

20.7.4 Example

Soft device support is provided for ai, bo, longin and stringin records. A typical example is:

record(ai, "$(IOC):GTIM_CURTIME") {
  field(DESC, "Get Time")
  field(DTYP, "General Time")
  field(INP,  "@TIME")
}

record(bo, "$(IOC):GTIM_RSTERR") {
  field(DESC, "Reset ErrorCounts")
  field(DTYP, "General Time")
  field(OUT,  "@RSTERRCNT")
}

record(longin, "$(IOC):GTIM_ERRCNT") {
  field(DESC, "Get ErrorCounts")
  field(DTYP, "General Time")
  field(INP,  "@GETERRCNT")
}

record(stringin, "$(IOC):GTIM_BESTTCP") {
  field(DESC, "Best Time-Current-Provider")
  field(DTYP, "General Time")
  field(INP,  "@BESTTCP")
}

record(stringin, "$(IOC):GTIM_BESTTEP") {
  field(DESC, "Best Time-Event-Provider")
  field(DTYP, "General Time")
  field(INP,  "@BESTTEP")
}

20.8 epicsInterrupt

epicsInterrupt.h contains the following:

20.8.1 C Interface

int epicsInterruptLock();

void epicsInterruptUnlock(int key);

int epicsInterruptIsInterruptContext();
void epicsInterruptContextMessage(const char *message);

Method Meaning
epicsInterruptLock Lock interrupts and return a key to be passed to epicsInterruptUnlock To lock the following is done. int key; ... key = epicsInterruptLock(); ... epicsInterruptUnlock(key);
epicsInterruptUnlock Unlock interrupts.
epicsInterruptIsInterruptContext Return (true, false) if current context is interrupt context.
epicsInterruptContextMessage Generate a message while interrupt context is true.

20.8.2 Implementation notes

A vxWorks specific version is provided. It maps directly to intLib calls.

An RTEMS version is provided that maps to rtems_ calls.

A default version is provided that uses a global semaphore to lock. This version is intended for operating systems in which iocCore will run as a multi threaded process. The global semaphore is thus only global within the process. This version is intended for use on all except real time operating systems.

The vxWorks implementation will most likely not work on symmetric multiprocessing systems.

The reason epicsInterrupt is needed is:

20.9 epicsMath

epicsMath.h includes math.h and also ensures that isnan and isinf are defined.

20.10 epicsMessageQueue

epicsMessageQueue.h describes a C++ and a C facility for interlocked communication between threads.

20.10.1 C++ Interface

EpicsMessageQueue provides methods for sending messages between threads on a first in, first out basis. It is designed so that a single message queue can be used with multiple writer and reader threads.

class epicsMessageQueue {
public:
    epicsMessageQueue(unsigned int capacity, unsigned int maximumMessageSize);
    ~epicsMessageQueue();
    int trySend(void *message, unsigned int messageSize);
    int send(void *message, unsigned int messageSize);
    int send(void *message, unsigned int messageSize, double timeout);
    int tryReceive(void *message, unsigned int messageBufferSize);
    int receive(void *message, unsigned int messageBufferSize);
    int receive(void *message, unsigned int messageBufferSize, double timeout);
    void show(int level) const;
    int pending() const;

private: // Prevent compiler-generated member functions
    // default constructor, copy constructor, assignment operator
    epicsMessageQueue();
    epicsMessageQueue(const epicsMessageQueue &);
    epicsMessageQueue& operator=(const epicsMessageQueue &);

private: // Data
    ...
};

An epicsMessageQueue cannot be assigned to, copy-constructed, or constructed without giving the capacity and maximumMessageSize arguments. The C++ compiler will object to some of the statements below:

epicsMessageQueue mq0();   // Error: default constructor is private
epicsMessageQueue mq1(10, 20); // OK
epicsMessageQueue mq2(t1); // Error: copy constructor is private
epicsMessageQueue *pmq;    // OK, pointer
*pmq = mq1;               // Error: assignment operator is private
pmq = &mq1;               // OK, pointer assignment and address-of

Method Meaning
epicsMessageQueue() Constructor. The capacity is the maximum number of messages, each containing 0 to maximumMessageSize bytes, that can be stored in the message queue.
~epicsMessageQueue() Destructor.
trySend() Try to send a message. Return 0 if the message was sent to a receiver or queued for future delivery. Return -1 if no more messages can be queued or if the message is larger than the queue's maximum message size. This method may be called from a vxWorks or RTEMS interrupt handler.
send() Send a message. Return 0 if the message was sent to a receiver or queued for future delivery. Return -1 if the timeout, if any, was reached before the message could be sent or queued, or if the message is larger than the queue's maximum message size.
tryReceive() Try to receive a message. If the message queue is non-empty, the first message on the queue is copied to the specified location and the length of the message is returned. Returns -1 if the message queue is empty. If the pending message is larger than the specified messageBufferSize it 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.
receive() Wait until a message is sent and store it in the specified location. The number of bytes in the message is returned. Returns -1 if a message is not received within the timeout interval. If the received message is larger than the specified messageBufferSize it 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.
show() Displays some information about the message queue. The level argument controls the amount of information dispalyed.
pending() Returns the number of messages presently in the queue.

20.10.2 C interface

typedef struct epicsMessageQueueOSD *epicsMessageQueueId;

epicsMessageQueueId epicsMessageQueueCreate(unsigned int capacity,
    unsigned int maximumMessageSize);
void epicsMessageQueueDestroy(epicsMessageQueueId id);
int epicsMessageQueueTrySend(epicsMessageQueueId id,
    void *message, unsigned int size);
int epicsMessageQueueSend(epicsMessageQueueId id,
    void *message, unsigned int size);
int epicsMessageQueueSendWithTimeout(epicsMessageQueueId id,
    void *message, unsigned int size, double timeout);
int epicsMessageQueueTryReceive(epicsMessageQueueId id,
    void *message, unsigned int size);
int epicsMessageQueueReceive(epicsMessageQueueId id,
    void *message, unsigned int size);
int epicsMessageQueueReceiveWithTimeout(epicsMessageQueueId id,
    void *message, unsigned int size, double timeout);
void epicsMessageQueueShow(epicsMessageQueueId id);
int epicsMessageQueuePending(epicsMessageQueueId id);

Each C function corresponds to one of the C++ methods.

20.11 epicsMutex

epicsMutex.h contains both C++ and C descriptions for a mutual exclusion semaphore.

20.11.1 C++ Interface

typedef enum {
    epicsMutexLockOK, epicsMutexLockTimeout, epicsMutexLockError
} epicsMutexLockStatus;

#define newEpicsMutex new epicsMutex(__FILE__,__LINE__)

class epicsMutex {
public:
    epicsMutex ();
    epicsMutex ( const char *pFileName, int lineno );
    ~epicsMutex ();
    void lock (); /* blocks until success */
    bool tryLock (); /* true if successful */
    void unlock ();
    void show ( unsigned level ) const;

    class invalidSemaphore {}; /* exception */
private:
};

Method Meaning
epicsMutex Create a mutual exclusion semaphore.
~epicsMutex Remove the semaphore and any resources it uses. Any further use of the semaphore result in unknown (most certainly bad) results.
lock() Wait until the resource is free. After a successful lock additional, i.e. recursive, locks of any type can be issued but each must have an associated unlock.
tryLock() Similar to lock except that, if the resource is owned by another thread, the call completes immediately. The return value is (false,true) if the resource (is not, is) owned by the caller.
unlock Release the resource. If a thread issues recursive locks, there must be an unlock for each lock
show Display information about the semaphore. The results are architecture dependent.

Mutual exclusion semaphores are for situations requiring mutually exclusive access to resources. A mutual exclusion semaphore may be taken recursively, i.e. can be taken more than once by the owner thread before releasing it. Recursive takes are useful for a set of routines that call each other while working on a mutually exclusive resource.

The newEpicsMutex macro simplifies debugging by letting the mutex store the source filename and line-number where it was created, using the second form of the constructor. The C interface also stores this information. The epicsMutex::show() routine can display that source location.

The typical use of a mutual exclusion semaphore is:

    epicsMutex *plock = newEpicsMutex;
    ...
    ...
    plock->lock();
    /* process resource */
    plock->unlock();

20.11.2 C Interface

typedef struct epicsMutexOSD* epicsMutexId;

epicsMutexId epicsMutexCreate(void);
epicsMutexId epicsMutexMustCreate (void);
void epicsMutexDestroy(epicsMutexId id);
void epicsMutexUnlock(epicsMutexId id);
epicsMutexLockStatus epicsMutexLock(epicsMutexId id);

void epicsMutexMustLock(epicsMutexId id);
epicsMutexLockStatus epicsMutexTryLock(epicsMutexId id);
void epicsMutexShow(epicsMutexId id,unsigned  int level);
void epicsMutexShowAll(int onlyLocked,unsigned  int level);

Each C routine corresponds to one of the C++ methods. epicsMutexMustCreate and epicsMutexMustLock do not return if they fail.

20.11.3 Implementation Notes

The implementation:

A posix version is implemented via pthreads.

20.12 epicsSpin

epicsSpin.h contains definitions for a spin lock semaphore.

20.12.1 C Interface

typedef struct epicsSpin *epicsSpinId;

epicsSpinId epicsSpinCreate();
void epicsSpinDestroy(epicsSpinId);

void epicsSpinLock(epicsSpinId);
int epicsSpinTryLock(epicsSpinId);
void epicsSpinUnlock(epicsSpinId);

Method Meaning
epicsSpinCreate Create a spin lock, allocate required resources, and initialize it to an unlocked state.
epicsSpinDestroy() Remove the spin lock and any resources it uses. Any further use of the spin lock may result in unknown (most certainly bad) behavior. The results are also undefined if epicsSpinDestroy is used when a thread holds the lock.
epicsSpinLock() Wait (by spinning, i.e. busy waiting) until the resource is free. After a successful lock, no additional, i.e. recursive, locking attempts may be issued.
epicsSpinTryLock() Similar to lock except that, if the resource is owned by another thread, the call completes immediately. The return value is 0 if the resource is owned by the caller.
epicsSpinUnlock() Release the spin lock resource which was locked by epicsSpinLock or epicsSpinTryLock. The results are undefined if the lock is not held by the calling thread, or if epicsSpinUnlock is used on an uninitialized spin lock.

20.12.2 Implementation Notes

The default implementation uses POSIX spin locks on POSIX compliant systems, and epicsMutex for non-POSIX environments.

20.13 epicsStdlib

epicsStdlib.h includes stdlib.h and epicsTypes.h and provides declarations for a series of string to number conversion functions and macros.

20.13.1 Integer Parsing

These routines convert a string into an integer of the indicated type and number base. The units pointer argument may be NULL, but if not it will be left pointing to the first non-whitespace character following the numeric string, or to the terminating zero byte.

int epicsParseLong(const char *str, long *to, int base, char **units);
int epicsParseULong(const char *str, unsigned long *to, int base,
    char **units);
int epicsParseLLong(const char *str, long long *to, int base, char **units);
int epicsParseULLong(const char *str, unsigned long long *to, int base,
    char **units);

int epicsParseInt8(const char *str, epicsInt8 *to, int base, char **units);
int epicsParseUInt8(const char *str, epicsUInt8 *to, int base, char **units);

int epicsParseInt16(const char *str, epicsInt16 *to, int base, char **units);
int epicsParseUInt16(const char *str, epicsUInt16 *to, int base, char **units);

int epicsParseInt32(const char *str, epicsInt32 *to, int base, char **units);
int epicsParseUInt32(const char *str, epicsUInt32 *to, int base, char **units);

int epicsParseInt64(const char *str, epicsInt64 *to, int base, char **units);
int epicsParseUInt64(const char *str, epicsUInt64 *to, int base, char **units);

The return value from these routines is a status code, zero meaning OK.

20.13.2 Floating-point Parsing

These routines convert a string into a floating-point type.

double epicsStrtod(const char *str, char **endp);

int epicsParseDouble(const char *str, double *to, char **units);
int epicsParseFloat(const char *str, float *to, char **units);

#define epicsParseFloat32(str, to, units) epicsParseFloat(str, to, units)
#define epicsParseFloat64(str, to, units) epicsParseDouble(str, to, units)

epicsStrtod() has the same semantics as the C99 function strtod() and is provided because some architectures do not fully conform to the standard. It is implemented as a simple macro on those architectures that do conform.

epicsParseDouble and epicsParseFloat convert a string into a variable of the indicated type. The units pointer argument may be NULL, but if not it will be left pointing to the first non-whitespace character following the numeric string, or to the terminating zero byte.

The return value from these routines is a status code, zero meaning OK.

20.13.3 Replacements for scanf()

The following routines are implemented as macros that call routines described above. They return 1 for a successful conversion, 0 on failure, and can be used to replace equivalent calls to sscanf().

#define epicsScanLong(str, to, base) !epicsParseLong(str, to, base, NULL)
#define epicsScanULong(str, to, base) !epicsParseULong(str, to, base, NULL)
#define epicsScanLLong(str, to, base) !epicsParseLLong(str, to, base, NULL)
#define epicsScanULLong(str, to, base) !epicsParseULLong(str, to, base, NULL)
#define epicsScanFloat(str, to) !epicsParseFloat(str, to, NULL)
#define epicsScanDouble(str, to) !epicsParseDouble(str, to, NULL)

epicsScanFloat and epicsScanDouble behave like sscanf with a "%f" and "%lf" format string, respectively. They are provided because some architectures have implementations of scanf which do not accept NAN or INFINITY.

20.14 epicsStdio

The epicsStdio.h first includes the operating systems's stdio.h header, then provides definitions for the following functions:

int epicsSnprintf(char *str, size_t size,
    const char *format, ...);
int epicsVsnprintf(char *str, size_t size,
    const char *format, va_list ap);

enum TF_RETURN {TF_OK = 0, TF_ERROR = 1};
enum TF_RETURN truncateFile(const char *pFileName, unsigned size );

/* Stream redirection of standard streams */
#define stdin epicsGetStdin()
#define stdout epicsGetStdout()
#define stderr epicsGetStderr()

#define printf epicsStdoutPrintf
#define puts epicsStdoutPuts
#define putchar epicsStdoutPutchar

FILE * epicsGetStdin(void);
FILE * epicsGetStdout(void);
FILE * epicsGetStderr(void);
FILE * epicsGetThreadStdin(void);
FILE * epicsGetThreadStdout(void);
FILE * epicsGetThreadStderr(void);
void epicsSetThreadStdin(FILE *);
void epicsSetThreadStdout(FILE *);
void epicsSetThreadStderr(FILE *);

int epicsStdoutPrintf(const char *pformat, ...);
int epicsStdoutPuts(const char *str);
int epicsStdoutPutchar(int c);

epicsSnprintf and epicsVsnprintf are meant to have the same semantics as the C99 functions snprintf and vsnprintf. They are provided because some architectures do not implement these functions, while others implement them incorrectly. Standardized as a C99 function, snprintf acts like sprintf except that the size argument gives the maximum number of characters (including the trailing zero byte) that may be placed in str. Similarly vsnprintf is a size-limited version of vsprintf. In both cases the return values are supposed to be the number characters (not counting the terminating zero byte) that would be written to str if it was large enough to hold them all; the output has been truncated if the return value is size or more.

On some operating systems though the implementations of these functions do not always return the correct value. If the OS implementation does not correctly return the number of characters that would have been written when the output gets truncated, it is not worth trying to fix this as long as they return size-1 instead; the resulting string must always be correctly terminated with a zero byte.

On operating systems such as Solaris which follow the Single Unix Specification V2, the epicsSnprintf and epicsVsnprintf implementations may not provide correct C99 semantics for the return value when size is given as zero. On these systems epicsSnprintf and epicsVsnprintf can return an error (a value less than zero) when a buffer length of zero is passed in, so callers should not use that technique to calculate the length of the buffer required.

truncateFile returns TF_OK if the file is less than size bytes or if it was successfully truncated. Returns TF_ERROR if the file could not be truncated.

The epicsSetThreadStdin/Stdout/Stderr routines allow the standard file steams to be redirected on a per thread basis, e.g. calling epicsSetThreadStdout 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.

The routines epicsGetStdin/Stdout/Stderr and epicsStdoutPrintf/Puts/Putchar are not normally named directly in user code. They are provided for the following macros that redefine the well-known C identifiers:

This is done so that any I/O through these standard streams can be redirected, usually to or from a file. The primary use of this facility is iocsh, which allows redirection of the input and/or output streams when running commands. In order for the redirection to work, all modules involved in I/O must include epicsStdio.h instead of the system header stdio.h.

20.15 epicsTempFile

epicsTempFile.h provides definitions for the following functions:

void epicsTempName(char *pbuf, size_t buflen);
FILE * epicsTempFile(void);

epicsTempName and epicsTempFile can be called to get unique filenames and open FILE * pointers. Note that epicsTempName cannot guarantee that the filenames it returns will not be created by some other thread or process after it has returned, although it does check that the filename it generates does not already exist. This security hole is why POSIX.1-2008 marked tempnam() as obsolete. The epicsTempName function will probably be deprecated in a future release of Base.

20.16 epicsThread

epicsThread.h contains C++ and C descriptions for a thread.

20.16.1 C Interface

typedef void (*EPICSTHREADFUNC)(void *parm);

#define epicsThreadPriorityMax          99
#define epicsThreadPriorityMin           0

/* some generic values */
#define epicsThreadPriorityLow          10
#define epicsThreadPriorityMedium       50
#define epicsThreadPriorityHigh         90

/* some iocCore specific values */
#define epicsThreadPriorityCAServerLow  20
#define epicsThreadPriorityCAServerHigh 40
#define epicsThreadPriorityScanLow      60
#define epicsThreadPriorityScanHigh     70
#define epicsThreadPriorityIocsh        91
#define epicsThreadPriorityBaseMax      91

/* stack sizes for each stackSizeClass are implementation and CPU dependent */
typedef enum {
    epicsThreadStackSmall, epicsThreadStackMedium, epicsThreadStackBig
} epicsThreadStackSizeClass;

typedef enum {
    epicsThreadBooleanStatusFail, epicsThreadBooleanStatusSuccess
} epicsThreadBooleanStatus;

unsigned int epicsThreadGetStackSize(epicsThreadStackSizeClass size);

/* (epicsThreadId)0 is guaranteed to be an invalid thread id */
typedef struct epicsThreadOSD *epicsThreadId;

typedef int epicsThreadOnceId;
#define EPICS_THREAD_ONCE_INIT 0

void epicsThreadOnce(epicsThreadOnceId *id, EPICSTHREADFUNC, void *arg);

void epicsThreadExitMain(void);

epicsThreadId epicsThreadCreate(const char *name,
    unsigned int priority, unsigned int stackSize,
    EPICSTHREADFUNC funptr, void *parm);
void epicsThreadSuspendSelf(void);
void epicsThreadResume(epicsThreadId id);
unsigned int epicsThreadGetPriority(epicsThreadId id);
unsigned int epicsThreadGetPrioritySelf(void);
void epicsThreadSetPriority(epicsThreadId id, unsigned int priority);
epicsThreadBooleanStatus epicsThreadHighestPriorityLevelBelow (
        unsigned int priority, unsigned *pPriorityJustBelow);
epicsThreadBooleanStatus epicsThreadLowestPriorityLevelAbove (
        unsigned int priority, unsigned *pPriorityJustAbove);
int epicsThreadIsEqual(epicsThreadId id1, epicsThreadId id2);
int epicsThreadIsSuspended(epicsThreadId id);
void epicsThreadSleep(double seconds);
double epicsThreadSleepQuantum(void);
epicsThreadId epicsThreadGetIdSelf(void);
epicsThreadId epicsThreadGetId(const char *name);
int epicsThreadGetCPUs(void);

const char * epicsThreadGetNameSelf(void);
void epicsThreadGetName(epicsThreadId id, char *name, size_t size);
int epicsThreadIsOkToBlock(void);
void epicsThreadSetOkToBlock(int isOkToBlock);

void epicsThreadShowAll(unsigned int level);
void epicsThreadShow(epicsThreadId id, unsigned int level);

typedef void (*EPICS_THREAD_HOOK_ROUTINE)(epicsThreadId id);
int epicsThreadHookAdd(EPICS_THREAD_HOOK_ROUTINE hook);
int epicsThreadHookDelete(EPICS_THREAD_HOOK_ROUTINE hook);
void epicsThreadHooksShow(void);
void epicsThreadMap(EPICS_THREAD_HOOK_ROUTINE func);

typedef void * epicsThreadPrivateId;
epicsThreadPrivateId epicsThreadPrivateCreate(void);
void epicsThreadPrivateDelete(epicsThreadPrivateId id);
void epicsThreadPrivateSet(epicsThreadPrivateId,void *);
void * epicsThreadPrivateGet(epicsThreadPrivateId);

Routine Meaning
epicsThreadGetStackSize Get a stack size value that can be given to epicsThreadCreate. The size argument should be one of the values epicsThreadStackSmall, epicsThreadStackMedium or epicsThreadStackBig.
epicsThreadOnce This is used as follows:
void myInitFunc(void * arg) {
    ...
}
epicsThreadOnceId onceFlag =
    EPICS_THREAD_ONCE_INIT;
...
epicsThreadOnce(&onceFlag, myInitFunc,
    (void *)myParm);
For each unique epicsThreadOnceId, epicsThreadOnce guarantees that 1) myInitFunc will only be called only once. 2) myInitFunc will have returned before any other epicsThreadOnce call returns. Note that myInitFunc must not call epicsThreadOnce with the same onceId.
epicsThreadExitMain If the main routine is done but wants to let other threads run it can call this routine. This should be the last call in main, except the final return. On most systems epicsThreadExitMain never returns. This must only be called by the main thread.
epicsThreadCreate Create a new thread. The use made of the priority, and stackSize arguments is implementation dependent. Some implementations may ignore one or other of these, but for portability appropriate values should be given for both. The value passed as the stackSize parameter should be obtained by calling epicsThreadGetStackSize. The funptr argument specifies a function that implements the thread, and parm is the single argument passed to funptr. A thread terminates when funptr returns.
epicsThreadSuspendSelf This causes the calling thread to suspend. The only way it can resume is for another thread to call epicsThreadResume.
epicsThreadResume Resume a suspended thread. Only do this if you know that it is safe to resume a suspended thread.
epicsThreadGetPriority Get the priority of the specified thread.
epicsThreadGetPrioritySelf Get the priority of this thread.
epicsThreadSetPriority Set a new priority for the specified thread. The result is implementation dependent.
epicsThreadHighestPriorityLevelBelow Get a priority that is just lower than the specified priority.
epicsThreadLowestPriorityLevelAbove Get a priority that is just above the specified priority.
epicsThreadIsEqual Compares two threadIds and returns (0,1) if they (are not, are) the same.
epicsThreadIsSuspended How and why a thread can be suspended is implementation dependent. A thread calling epicsThreadSuspendSelf should result in this routine returning true for that thread, but a thread may also be suspended for other reasons.
epicsThreadSleep Sleep for the specified period of time, i.e. sleep without using the cpu. If delay is >0 then the thread will sleep at least until the next clock tick. The exact time is determined by the underlying architecture. If delay is <= 0 then a delay of 0 is requested of the underlying architecture. What happens is architecture dependent but often it allows other threads of the same priority to run.
epicsThreadSleepQuantum This function returns the minimum slumber interval obtainable with epicsThreadSleep() in seconds. On most OS there is a system scheduler interrupt interval which determines the value of this parameter. Knowledge of this parameter is used by the various components of EPICS to improve scheduling of software tasks intime when the reduction of average time scheduling errors is important. If this parameter is unknown or is unpredictable for a particular OS then it is safe to return zero.
epicsThreadGetIdSelf Get the threadId of the calling thread.
epicsThreadGetId Get the threadId of the specified thread. A return value of 0 means that no thread was found with the specified name.
epicsThreadGetCPUs Get the number of CPUs (logical cores) available to the IOC. On systems that provide Hyper-Threading, this may be more the number of physical CPU cores.
epicsThreadGetNameSelf Get the name of the calling thread.
epicsThreadGetName Get the name of the specified thread. The value is copied to a caller specified buffer so that if the thread terminates the caller is not left with a pointer to something that may no longer exist.
epicsThreadIsOkToBlock Is it OK for a thread to block? This can be called by support code that does not know if it is called in a thread that should not block. For example the errlog system calls this to decide when messages should be displayed on the console.
epicsThreadSetOkToBlock When a thread is started the default is that it is not allowed to block. This method can be called to change the state. For example iocsh calls this to specify that it is OK to block.
epicsThreadShowAll Display info about all threads.
epicsThreadShow Display info about the specified thread.
epicsThreadHookAdd Register a routine to be called by every new thread before the thread function gets run. Hook routines will often register a thread exit routine with epicsAtThreadExit to release thread-specific resources they have allocated.
epicsThreadHookDelete Remove routine from the list of hooks run at thread creation time.
epicsThreadHooksShow Print the current list of hook function pointers.
epicsThreadMap Call func once for every known thread.
epicsThreadPrivateCreate Thread private variables are intended for use by legacy libraries written for a single threaded environment and which used a global variable to store private data. The only code in base that currently needs this facility is channel access. A library that needs a private variable should make exactly one call to epicsThreadPrivateCreate and store the index returned. Each thread can later call epicsThreadPrivateGet and epicsThreadPrivateSet with that index to access a thread-specific pointer store.
epicsThreadPrivateDelete Delete a thread private variable.
epicsThreadPrivateSet Set the value for a thread private pointer.
epicsThreadPrivateGet Get the value of a thread private pointer. The value returned is the last value given to epicsThreadPrivateSet by the same thread. If called before epicsThreadPrivateSet the pointer's value is NULL.

The epicsThread API is meant as a somewhat minimal interface for 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.

The interface provides the following thread facilities, with restrictions as noted:

20.16.2 C++ Interface

class epicsThreadRunable {
public:
    virtual void run() = 0;
    virtual void stop();
    virtual void show(unsigned int level) const;
};

class epicsShareClass epicsThread {
public:
    epicsThread (epicsThreadRunable &,const char *name, unsigned int stackSize,
        unsigned int priority=epicsThreadPriorityLow);
    virtual ~epicsThread ();
    void start();
    void exitWait ();
    bool exitWait (const double delay );
    void exitWaitRelease (); // noop if not called by managed thread
    static void exit ();
    void resume ();
    void getName (char *name, size_t size) const;
    epicsThreadId getId () const;
    unsigned int getPriority () const;
    void setPriority (unsigned int);
    bool priorityIsEqual (const epicsThread &otherThread) const;
    bool isSuspended () const;
    bool isCurrentThread () const;
    bool operator == (const epicsThread &rhs) const;
    /* these operate on the current thread */
    static void suspendSelf ();
    static void sleep (double seconds);
    static epicsThread & getSelf ();
    static const char * getNameSelf ();
    static bool isOkToBlock ();
    static void setOkToBlock(bool isOkToBlock) ;
private:
    ...
};
template <class T>
class epicsThreadPrivate {
public:
    epicsThreadPrivate ();
    ~epicsThreadPrivate ();
    T *get () const;
    void set (T *);
    class unableToCreateThreadPrivate {}; // exception
private:
    ...
};

The C++ interface is a wrapper around the C interface. Two differences are the method start and the class epicsThreadRunable.

The start method must not be called until after the epicsThread constructor has returned. Calling the start method allows the run method of the epicsThreadRunable object to be executed in the context of the new thread.

Code using the C++ API must provide a class that derives from epicsThreadRunable. For example:

class myThread: public epicsThreadRunable {
public:
    myThread(int arg,const char *name);
    virtual ~myThread();
    virtual void run();
    epicsThread thread;
}

myThread::myThread(int arg,const char *name) :
    thread(*this,name,epicsThreadGetStackSize(epicsThreadStackSmall),50)
{
    thread.start();
}

myThread::~myThread() {}

void myThread::run()
{
    // ...
}

20.17 epicsTime

epicsTime.h contains C++ and C descriptions for time.

20.17.1 Time Related Structures

/* epics time stamp for C interface*/
typedef struct epicsTimeStamp {
    epicsUInt32    secPastEpoch;   /* seconds since 0000 Jan 1, 1990 */
    epicsUInt32    nsec;           /* nanoseconds within second */
} epicsTimeStamp;

/*TS_STAMP is deprecated */
#define TS_STAMP epicsTimeStamp

struct timespec; /* POSIX real time */
struct timeval; /* BSD */
struct l_fp; /* NTP timestamp */

// extend ANSI C RTL "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; /* ANSI C time details */
    unsigned long nSec; /* nano seconds extension */
};

// extend ANSI C RTL "struct tm" to includes nano seconds within a second
// and a struct tm that is adjusted for GMT (UTC)
struct gm_tm_nano_sec {
    struct tm ansi_tm; /* ANSI C time details */
    unsigned long nSec; /* nano seconds extension */
};

// wrapping this in a struct allows conversion to and
// from ANSI time_t but does not allow unexpected
// conversions to occur
struct time_t_wrapper {
    time_t ts;
};

The above structures are for the various time formats.

NOTE on conversion. The epics 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.

20.17.2 C++ Interface

class epicsTime;

class epicsTimeEvent {
public:
    epicsTimeEvent (const int &number);
    operator int () const;
private:
    int eventNumber;
};

class epicsTime {
public:
    // exceptions
    class unableToFetchCurrentTime {};
    class formatProblemWithStructTM {};

    epicsTime ();
    epicsTime (const epicsTime &t);

    static epicsTime getEvent (const epicsTimeEvent &event);
    static epicsTime getCurrent ();

    // convert to and from EPICS epicsTimeStamp format
    operator epicsTimeStamp () const;
    epicsTime (const epicsTimeStamp &ts);
    epicsTime operator = (const epicsTimeStamp &rhs);

    // convert to and from ANSI time_t 
    operator time_t_wrapper () const;
    epicsTime (const time_t_wrapper &tv);
    epicsTime operator = (const time_t_wrapper &rhs);

    // convert to and from ANSI Cs "struct tm" (with nano seconds)
    // adjusted for the local time zone
    operator local_tm_nano_sec () const;
    epicsTime (const local_tm_nano_sec &ts);
    epicsTime operator = (const local_tm_nano_sec &rhs);

    // convert to ANSI Cs "struct tm" (with nano seconds)
    // adjusted for GM time (UTC)
    operator gm_tm_nano_sec () const;

    // convert to and from POSIX RT's "struct timespec"
    operator struct timespec () const;
    epicsTime (const struct timespec &ts);
    epicsTime operator = (const struct timespec &rhs);

    // convert to and from BSD's "struct timeval"
    operator struct timeval () const;
    epicsTime (const struct timeval &ts);
    epicsTime operator = (const struct timeval &rhs);

    // convert to and from NTP timestamp format
    operator l_fp () const;
    epicsTime (const l_fp &);
    epicsTime operator = (const l_fp &rhs);

    // convert to and from WIN32s FILETIME (implemented only on WIN32)
    operator struct _FILETIME () const;
    epicsTime ( const struct _FILETIME & );
    epicsTime & operator = ( const struct _FILETIME & );

    // arithmetic operators
    double operator- (const epicsTime &rhs) const; // returns seconds
    epicsTime operator+ (const double &rhs) const; // add rhs seconds
    epicsTime operator- (const double &rhs) const; // subtract rhs seconds
    epicsTime operator+= (const double &rhs); // add rhs seconds
    epicsTime operator-= (const double &rhs); // subtract rhs seconds

    // comparison operators
    bool operator == (const epicsTime &rhs) const;
    bool operator != (const epicsTime &rhs) const;
    bool operator <= (const epicsTime &rhs) const;
    bool operator < (const epicsTime &rhs) const;
    bool operator >= (const epicsTime &rhs) const;
    bool operator > (const epicsTime &rhs) const;

    // convert current state to user-specified string
    size_t strftime (char *pBuff, size_t bufLength, const char *pFormat) const;

    // dump current state to standard out
    void show (unsigned interestLevel) const;

private:
    ...
};

20.17.3 class epicsTimeEvent

class epicsShareClass epicsTimeEvent
{
public:
    epicsTimeEvent (const int &number);
    operator int () const;
private:
    int eventNumber;
};
Method Meaning
Convert to/from integer Does not currently check that the range of the integer is valid, although it might one day.

20.17.4 class epicsTime

Method Meaning
epicsTime() The default constructor sets the time to the beginning of the epics epoch.
epicsTime(const epicsTime& t); The default constructor sets the time to the beginning of the epics epoch.
static getEvent Returns an epicsTime indicating when the associated event last occurred. See the description of the C routine epicsTimeGetEvent below for details.
static getCurrent Returns an epicsTime containing the current time. An example is: epicsTime time = epicsTime::getCurrent();
convert to/fromepicsTimeStamp Three methods are provided for epicsTimeStamp. A copy constructor, an assignment operator, and a conversion to epicsTimeStamp. Assume the following definitions: epicsTime time; epicsTimeStamp ts;An example of the copy constructor is: epicsTime time1(ts);An example of the assignment operator is: time = ts;An example of the epicsTimeStamp operator is: ts = time;
Convert to/fromANSI time_t Three methods are provided for ANSI time_t. A copy constructor, an assignment operator, and a conversion to time_t_wrapper. The structure time_t_wrapper must be used instead of time_t because undesired conversions could occur: Assume the following definitions: time_t tt; time_t_wrapper ttw; epicsTime time;An example of the copy constructor is: ttw.tt = tt; epicsTime time1(ttw);An example of the assignment operator is: time = ttw;An example of the time_t_wrapper operator is: ttw = time; tt = ttw.tt;
convert to and fromtm_nano_sec Three methods are provided for tm_nano_sec A copy constructor, an assignment operator, and a conversion to tm_nano_sec. Assume the following definitions: local_tm_nano_sec ttn; epicsTime time;An example of the copy constructor is: epicsTime time1(ttn);An example of the assignment operator is: time = ttn;An example of the tm_nano_sec operator is: ttn = time;
convert to and fromPOSIX RT's ``struct timespec" Three methods are provided for struct timespec. A copy constructor, an assignment operator, and a conversion to struct timespec. Assume the following definitions: struct timespec tts; epicsTime time;An example of the copy constructor is: epicsTime time1(tts);An example of the assignment operator is: time = tts;An example of the struct timespec operator is: tts = time;
convert to and from BSD's ``struct timeval" Three methods are provided for struct timeval. A copy constructor, an assignment operator, and a conversion to struct timeval. Assume the following definitions: struct timeval ttv; epicsTime time;An example of the copy constructor is: epicsTime time1(ttv);An example of the assignment operator is: time = ttv;An example of the struct timeval operator is: ttv = time;
convert to and from NTP timestamp format Three methods are provided for ntpTimeStamp. A copy constructor, an assignment operator, and a conversion to ntpTimeStamp. Assume the following definitions: l_fp ntp; epicsTime time;An example of the copy constructor is: epicsTime time1(ntp);An example of the assignment operator is: time = ntp;An example of the ntpTimeStamp operator is: ntp = time;
arithmetic operators- ++=-= The arithmetic operators allow the difference of two epicsTimes, with the result in seconds. It also allows -, +, +=, and -= where the left hand argument is an epicsTime and the right hand argument is a double. Examples are: epicsTime time, time1, time2; double t1,t2,t3; ... t1 = time2 - time1; time = time1 + 4.5; time = time2 - t3; time2 += 6.0;
Comparison operators==, |=, <=, <, >=, > Two epics times can be compared: epicsTime time1, time2; ... if(time1<=time2) { ...
strftime This is a facility similar to the ANSI C library routine strftime. See K&R for details about strftime. The epicsTime method also provides support for the printing the nanoseconds portion of the time. It looks in the format string for the sequence ``%0nf" where n is the desired precision. It uses this format to convert the nanoseconds value to the requested precision. For example: epicsTime time = epicsTime::getCurrent(); char buf[30]; time.strftime(buf,30,"%Y/%m/%d %H:%M:%S.%06f"); printf("%s\n",buf);Will print the time in the format: 2001/01/26 20:50:29.813505
show Shows the date/time.

20.17.5 C Interface

/* All epicsTime routines return (-1,0) for (failure,success) */
#define epicsTimeOK 0
#define epicsTimeERROR (-1)
/*Some special values for eventNumber*/
#define epicsTimeEventCurrentTime 0
#define epicsTimeEventBestTime -1
#define epicsTimeEventDeviceTime -2

/* These are implemented in the "generalTime" framework */
int epicsTimeGetCurrent (epicsTimeStamp *pDest);
int epicsTimeGetEvent (epicsTimeStamp *pDest, int eventNumber);

/* These are callable from an Interrupt Service Routine */
int epicsTimeGetCurrentInt(epicsTimeStamp *pDest);
int epicsTimeGetEventInt(epicsTimeStamp *pDest, int eventNumber);

/* convert to and from ANSI C's "time_t" */
int epicsTimeToTime_t (time_t *pDest, const epicsTimeStamp *pSrc);
int epicsTimeFromTime_t (epicsTimeStamp *pDest, time_t src);

/*convert to and from ANSI C's "struct tm" with nano seconds */
int epicsTimeToTM (struct tm *pDest, unsigned long *pNSecDest,
    const epicsTimeStamp *pSrc);
int epicsTimeToGMTM (struct tm *pDest, unsigned long *pNSecDest,
    const epicsTimeStamp *pSrc);
int epicsTimeFromTM (epicsTimeStamp *pDest, const struct tm *pSrc,
    unsigned long nSecSrc);

/* convert to and from POSIX RT's "struct timespec" */
int epicsTimeToTimespec (struct timespec *pDest, const epicsTimeStamp *pSrc);
int epicsTimeFromTimespec (epicsTimeStamp *pDest, const struct timespec *pSrc);

/* convert to and from BSD's "struct timeval" */
int epicsTimeToTimeval (struct timeval *pDest, const epicsTimeStamp *pSrc);
int epicsTimeFromTimeval (epicsTimeStamp *pDest, const struct timeval *pSrc);
/*arithmetic operations */
double epicsTimeDiffInSeconds (
    const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight);
void epicsTimeAddSeconds (
    epicsTimeStamp *pDest, double secondsToAdd); /* adds seconds to *pDest */

/*comparison operations: returns (0,1) if (false,true) */
int epicsTimeEqual(const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight);
int epicsTimeNotEqual(const epicsTimeStamp *pLeft,const epicsTimeStamp *pRight);
int epicsTimeLessThan(const epicsTimeStamp *pLeft,const epicsTimeStamp *pRight);
int epicsTimeLessThanEqual(
    const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight);
int epicsTimeGreaterThan (
    const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight);
int epicsTimeGreaterThanEqual (
    const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight);
/*convert to ASCII string */
size_t epicsTimeToStrftime (
    char *pBuff, size_t bufLength, const char *pFormat, const epicsTimeStamp 
*pTS);

/* dump current state to standard out */
void epicsTimeShow (const epicsTimeStamp *, unsigned interestLevel);
/* OS dependent reentrant versions of the ANSI C interface because */
/* vxWorks gmtime_r interface does not match POSIX standards */
int epicsTime_localtime ( const time_t *clock, struct tm *result );
int epicsTime_gmtime ( const time_t *clock, struct tm *result );

The C interface provides most of the features as the C++ interface. The features of the C++ operators are provided as functions.

Note that the epicsTimeGetCurrent() and epicsTimeGetEvent() routines and their ISR-callable equivalents epicsTimeGetCurrentInt() and epicsTimeGetEventInt() are now implemented in epicsGeneralTime.c

20.18 osiPoolStatus

osiPoolStatus.h contains the following description:

int osiSufficentSpaceInPool(void);

Method Meaning
osiSufficentSpaceInPool Return (true,false) if there is sufficient free memory.

This determines if enough free memory exists to continue.

A vxWorks version returns (true,false) if memFindMax returns (>100000, <=100000) bytes.

The default version always returns true.

20.19 osiProcess

osiProcess.h contains the following:

typedef enum osiGetUserNameReturn {
    osiGetUserNameFail,
    osiGetUserNameSuccess
}osiGetUserNameReturn;

osiGetUserNameReturn osiGetUserName (char *pBuf, unsigned bufSize);

/*
 * Spawn detached process with named executable, but return
 * osiSpawnDetachedProcessNoSupport if the local OS does not
 * support heavy weight processes.
 */
typedef enum osiSpawnDetachedProcessReturn {
    osiSpawnDetachedProcessFail,
    osiSpawnDetachedProcessSuccess,
    osiSpawnDetachedProcessNoSupport
}osiSpawnDetachedProcessReturn;

osiSpawnDetachedProcessReturn osiSpawnDetachedProcess(
    const char *pProcessName, const char *pBaseExecutableName);

Not otherwise documented.

20.20 Ignoring Posix Signals

epicsSignal.h contains the following commented declarations:

/*
 * Required to avoid problems with soft IOCs getting SIGHUPs
 * when a Channel Access client disconnects:
 */
void epicsSignalInstallSigHupIgnore ( void );

/*
 * Required to avoid terminating a process which is blocking
 * in a socket send() call when a SIGPIPE signal is generated
 * by the OS:
 */
void epicsSignalInstallSigPipeIgnore ( void );

/*
 * Required only if shutdown() and close() do not interrupt
 * a thread blocking in a socket system call:
 */
void epicsSignalInstallSigAlarmIgnore ( void );
void epicsSignalRaiseSigAlarm ( struct epicsThreadOSD * );

Not otherwise documented.

20.21 OS-Independent Socket API

The header file osiSock.h provides wrappers around the different socket APIs provided by the supported operating systems. This API was designed to make it possible to write network applications that will compile and run on any OS. See the comments and declarations in the header file for details.

20.22 epicsMMIO

epicsMMIO.h provides a set of calls to perform safe access to Memory Mapped I/O regions. This is the typical means to access VME or PCI bus devices.

The following are the equivalant signatures of the MMIO read and write calls. The actual implementations may use macros.

epicsUInt8      ioread8 (void* addr);
epicsUInt16 nat_ioread16(void* addr);
epicsUInt16  be_ioread16(void* addr);
epicsUInt16  le_ioread16(void* addr);
epicsUInt32 nat_ioread32(void* addr);
epicsUInt32  be_ioread32(void* addr);
epicsUInt32  le_ioread32(void* addr);

void     iowrite8 (void* addr, epicsUInt8  val);
void nat_iowrite16(void* addr, epicsUInt16 val);
void  be_iowrite16(void* addr, epicsUInt16 val);
void  le_iowrite16(void* addr, epicsUInt16 val);
void nat_iowrite32(void* addr, epicsUInt32 val);
void  be_iowrite32(void* addr, epicsUInt32 val);
void  le_iowrite32(void* addr, epicsUInt32 val);

The 16 and 32-bit calls have three variants: nat_, be_, and le_ which specify the byte ordering of the MMIO register being access as having: CPU Native, Big Endian, or Little Endian byte order. The specification will be used to re-order the bytes read/written into the CPU native integer format.

Determining which of these variants to use in a specific case requires knowledge of the underlying hardware (bus and/or device). This document can present only a general rule, which is that the nat_ variant will be used for VME devices as the common bus bridges do automatic byte lane swapping. PCI devices will generally use of one be_ or le_, although some devices have been known to have a mix of BE and LE registers.

These calls do not perform any checking of address alignment.

All of these calls have CPU, OS, and/or compiler specific definitions which try to preserve all MMIO operations by defeating instruction reordering and operation splitting/combining optimizations by the compiler and CPU.

20.23 Device Support Library

NOTE: EPICS Base only provides vxWorks and RTEMS back-end implementations of these routines. Versions of the back-end routines for other operating systems can be added in a support or IOC application.

20.23.1 Overview

devLib.h provides definitions for a library of routines useful for device and driver modules, which are primarily indended for accessing VME devices. If all VME drivers register with these routines then addressing conflicts caused by multiple device/drivers trying to use the same VME addresses will be detected.

20.23.2 Location Probing

20.23.2.1 Read Probe

long  devReadProbe(
    unsigned wordSize,
    volatile const void *ptr,
    void *pValueRead);

Performs a bus-error-safe atomic read operation width wordSize bytes from the ptr location, placing the value read (if successful) at pValueRead. The routine returns a failure status (non-zero) if a bus error occurred during the read cycle.

20.23.2.2 Write Probe

long  devWriteProbe(
    unsigned wordSize,
    volatile void *ptr,
    const void *pValueWritten);

Performs a bus-error-safe atomic write operation width wordSize which copies the value from pValueWritten to the ptr location. The routine returns a failure status (non-zero) if a bus error occurred during the write cycle.

20.23.2.3 No Response Probe

long devNoResponseProbe(
    epicsAddressType addrType,
    size_t base,
    size_t size);

This routine performs a series of read probes for all word sizes from char to long at every naturally aligned location in the range [base, base+size) for the given bus address type. It returns an error if any location responds or if any such location cannot be mapped.

20.23.3 Registering VME Addresses

20.23.3.1 Definitions of Address Types

typedef enum {
    atVMEA16, atVMEA24, atVMEA32,
    atISA,
    atVMECSR,
    atLast /* atLast is the last enum in this list */
} epicsAddressType;

char  *epicsAddressTypeName[] = {
    "VME A16", "VME A24", "VME A32",
    "ISA", "VME CSR"
};

20.23.3.2 Register Address

long  devRegisterAddress(
    const char *pOwnerName,
    epicsAddressType addrType,
    size_t logicalBaseAddress,
    size_t size, /* bytes */
    volatile void **pLocalAddress);

This routine is called to register a VME address. The routine keeps a list of all VME address ranges requested and returns an error message if an attempt is made to register any addresses that overlap a range that is already being used. *pLocalAddress is set equal to the address as seen by the caller.

20.23.3.3 Print Address Map

long  devAddressMap(void)

This routine displays the table of registered VME address ranges, including the owner of each registered address.

20.23.3.4 Unregister Address

long  devUnregisterAddress(
    epicsAddressType addrType,
    size_t logicalBaseAddress,
    const char *pOwnerName);

This routine releases address ranges previously registered by a call to devRegisterAddress or devAllocAddress.

20.23.3.5 Allocate Address

long  devAllocAddress(
    const char *pOwnerName,
    epicsAddressType addrType,
    size_t size,
    unsigned alignment, /*number of low zero bits needed in addr*/
    volatile void **pLocalAddress);

This routine is called to request the library to allocate an address block of a particular address type. This is useful for devices that appear in more than one address space and can program the base address of one window using registers found in another window.

20.23.4 Interrupt Connection Routines

20.23.4.1 Connect

long  devConnectInterruptVME(
    unsigned vectorNumber,
    void (*pFunction)(void *),
    void  *parameter);

Connect ISR pFunction up to the VME interrupt vectorNumber.

20.23.4.2 Disconnect

long  devDisconnectInterruptVME(
    unsigned vectorNumber,
    void (*pFunction)(void *));

Disconnects an ISR from its VME interrupt vector. The parameter pFunction should be set to the C function pointer that was connected. It is used as a key to prevent a driver from inadvertently removing an interrupt handler that it didn't install.

20.23.4.3 Check If Used

int devInterruptInUseVME(
    unsigned vectorNumber);

Determines if a VME interrupt vector is in use, returning a boolean value.

20.23.4.4 Enable

long devEnableInterruptLevelVME(
    unsigned level);

Enable the given VME interrupt level onto the CPU.

20.23.4.5 Disable

long devDisableInterruptLevelVME(
    unsigned level);

Disable VME interrupt level. This routine should generally never be used, since it is impossible for a driver to know whether any other active drivers are still making use of a particular interrupt level.

20.23.5 Macros for Normalized Analog Values

20.23.5.1 Convert Digital Value to a Normalized Double Value

#define devCreateMask(NBITS)((1<<(NBITS))-1)
#define devDigToNml(DIGITAL,NBITS) \
    (((double)(DIGITAL))/devCreateMask(NBITS))

20.23.5.2 Convert Normalized Double Value to a Digital Value

#define devNmlToDig(NORMAL,NBITS) \
    (((long)(NORMAL)) * devCreateMask(NBITS))

20.23.6 Deprecated Interrupt Routines

20.23.6.1 Definitions of Interrupt Types (deprecated)

typedef enum {intCPU, intVME, intVXI} epicsInterruptType;

The routines that use this typedef have all been deprecated, and currently only exist for backwards compatibility purposes. The typedef will be removed in a future release, along with those routines.

20.23.6.2 Connect (deprecated)

long  devConnectInterrupt(
    epicsInterruptType  intType,
    unsigned  vectorNumber,
    void  (*pFunction)(),
    void  *parameter);

This routine has been deprecated, and currently only exists for backwards compatibility purposes. Uses of this routine should be converted to call devConnectInterruptVME or related routines instead. This routine will be removed in a future release.

20.23.6.3 Disconnect (deprecated)

long  devDisconnectInterrupt(
    epicsInterruptType intType,
    unsigned  vectorNumber);

This routine has been deprecated, and currently only exists for backwards compatibility purposes. Uses of this routine should be converted to call devDisconnectInterruptVME or related routines instead. This routine will be removed in a future release.

20.23.6.4 Enable Level (deprecated)

long  devEnableInterruptLevel(
    epicsInterruptType  intType,
    unsigned  level);

This routine has been deprecated, and currently only exists for backwards compatibility purposes. Uses of this routine should be converted to call devEnableInterruptLevelVME or related routines instead. This routine will be removed in a future release.

20.23.6.5 Disable Level (deprecated)

long  devDisableInterruptLevel(
    epicsInterruptType  intType,
    unsigned  level);

This routine has been deprecated, and currently only exists for backwards compatibility purposes. Uses of this routine should be converted to call devDisableInterruptLevelVME or related routines instead. This routine will be removed in a future release.

20.24 vxWorks Specific routines and Headers

The routines described in this section are included in a application by the Makfile command:

    <appl>_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary

20.24.1 veclist

This routine shows the vxWorks interrupt vector table, but only works properly on 68K family CPUs.

20.24.2 logMsgToErrlog

This traps all calls to logMsg and sends them to errlogPrintf.

20.24.3 camacLib.h

This was included with 3.13.

20.24.4 epicsDynLink

This provides the routines symFindByNameEPICS and symFindByNameAndTypeEPICS. It is only provided for modules that have not been converted to use epicsFindSymbol. These routines are deprecated.

20.24.5 module_types.h

This is only provided for device/driver support that have not been converted to use OSI features of base. This header is deprecated. Instead of using this, drivers should register a configuration command to obtain the information originally provided by module_types.h

20.24.6 task_params.h

This is only provided for device/driver support that have not been converted to use OSI features of base. This header is deprecated.

20.24.7 vxComLibrary

This routine causes epicsDynLink, logMsgToErrlog and veclist to be loaded.


next up previous contents index
Next: 21. Registry Up: AppDevGuide Previous: 19. libCom   Contents   Index
Andrew Johnson 2016-09-08