This chapter and the next describe the facilities provided in <base>/src/libCom. This chapter describes facilities which are platform independent. The next chapter describes facilities which have different implementations on different platforms.
bucketLib.h describes a hash facility for integers, pointers, and strings. It is used by the Channel Access Server. It is currently undocumented.
postfix.h defines several macros and the routines used by the calculation record type calcRecord, access security, and other code, to compile and evaluate mathematical expressions. The syntax of the infix expressions accepted is described below.
The postfix() routine converts an expression from infix to postfix notation. It is the callers’s responsibility to ensure that 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 (note that n must count the terminating nil byte too).
There is no maximum length to the input expression that can be accepted, although there are internal limits to the complexity of the expressions that can be converted and evaluated. If postfix() returns a non-zero value it will have placed an error code at the location pointed to by perror.
The error codes used are defined in postfix.h as a series of macros with names starting CALC_ERR_, but a string representation of the error code is more useful and can be obtained by passing the value to the calcErrorStr() routine, which returns a static error message string explaining the error.
Software using the calc subsystem may need to know what expression arguments are used and/or modified by a particular expression. It can discover this from the postfix string by calling calcArgUsage(), which takes two pointers pinputs and pstores to a pair of unsigned 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 *pinputs will be set if the expression depends on the argument A, and so on through bit 11 for the argument L. Similarly, bit 0 of the bitmap at *pstores will be set if the expression assigns a value to the argument A. 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 be used to determine whether a value needs to be supplied for their associated argument or not for the purposes of evaluating the expression. The return value from calcArgUsage() will be non-zero if the ppostfix expression was illegal, otherwise 0.
The postfix expression is evaluated by calling the calcPerform() routine, which returns the status values 0 for OK, or non-zero if an error is discovered during the evaluation process.
The arguments to calcPerform() are:
The infix expressions that can be used are very similar to the C expression syntax, but with some additions and subtle differences in operator meaning and precedence. The string may contain a series of expressions separated by a semi-colon character ‘;’ any one of which may actually provide the calculation result; however all of the other expressions included must assign their result to a variable. All alphabetic elements described below are case independent, so upper and lower case letters may be used and mixed in the variable and function names as desired. Spaces may be used anywhere within an expression except between the characters that make up a single expression element.
The simplest expression element is a numeric literal, any (positive) number expressed using the standard floating point syntax that can be stored as a double precision value. This now includes the values Infinity and NaN (not a number). Note that negative numbers will be encoded as a positive literal to which the unary negate operator is applied.
Examples:
There are three trigonometric constants available to any expression which return a value:
Variables are used to provide inputs to an expression, and are named using the single letters A through L inclusive or the keyword VAL which refers to the previous result of this calculation. The software that makes use of the expression evaluation code should document how the individual variables are given values; for the calc record type the input links INPA through INPL can be used to obtain these from other record fields, and VAL refers to the the VAL field (which can be overwritten from outside the record via Channel Access or a database link).
Recently added is the ability to assign the result of a sub-expression to any of the single letter variables, which can then be used in another sub-expression. The variable assignment operator is the character pair := and must immediately follow the name of the variable to receive the expression value. Since the infix string must return exactly one value, every expression string must have exactly one sub-expression that is not an assignment, which can appear anywhere in the string. Sub-expressions within the string are separated by a semi-colon character.
Examples:
The usual binary arithmetic operators are provided: + - ⋆ and / with their usual relative precedence and left-to-right associativity, and - may also be used as a unary negate operator where it has a higher precedence and associates from right to left. There is no unary plus operator, so numeric literals cannot begin with a + sign.
Examples:
Three other binary operators are also provided: % is the integer modulo operator, while the synonymous operators ⋆⋆ and ̂ raise their left operand to the power of the right operand. % has the same precedence and associativity as ⋆ and /, while the power operators associate left-to-right and have a precedence in between ⋆ and unary minus.
Examples:
Various algebraic functions are available which take parameters inside parentheses. The parameter seperator is a comma.
Standard circular trigonometric functions, with angles expressed in radians:
The basic hyperbolic functions are provided, but no inverse functions (which are not provided by the ANSI C math library either).
The numeric functions perform operations related to the floating point numeric representation and truncation or rounding.
These operators regard their arguments as true or false, where 0.0 is false and any other value is true.
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.
Standard numeric comparisons between two values:
Expressions can use the C conditional operator, which has a lower precedence than all of the other operators except for the assignment operator.
Example:
Sub-expressions can be placed within parentheses to override operator precence 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 requirea an expression at least 321 characters long to reach).
This subdirectory of libCom is intended for facilities such as class and function templates that implement parts of the ISO standard C++ library where such facilities are not available or not efficient on all the target platforms on which EPICS is supported. EPICS does not make use of the C++ container templates because the large number of memory allocation and deletion operations that these use causes memory pool fragmentation on some platforms, threatening the lifetime of an individual IOC.
epicsAlgorithm.h contains a few templates that are also available in the C++ standard header algorithm, but are provided here in a much smaller file. algorithm contains many templates for sorting and searching through C++ template containers which are not used in EPICS. If all you need from there is std::min(), std::max() and/or std::swap() your code may compile faster if you include epicsAlgorithm.h and use epicsMin(), epicsMax() and epicsSwap() instead.
Template Function |
Meaning |
epicsMin(a, b) |
Returns the smaller of a or b compared using a<b. Handles NaNs correctly. |
epicsMax(a, b) |
Returns the larger of a or b compared using a<b. Handles NaNa correctly. |
epicsSwap(a, b) |
Swaps the values of a and b; the data type must support both copy-construction and assignment. |
|
|
|
|
This is an extended replacement for the Posix exit and atexit routines, which also provides a pointer argument to pass to the exit handlers. This facility was created because of problems on vxWorks and windows with the implementation of atexit, i.e. neither of these systems implement exit and atexit according to the POSIX standard.
Method |
Meaning |
epicsExit |
This calls epicsExitCallAtExits and then passes status on to exit. |
epicsExitCallAtExits |
This calls each of the functions registered by prior calls to epicsAtExit, in reverse order of their registration. Most applications will not call this routine directly. |
epicsAtExit |
Register a function and an associated context parameter, to be called with the given parameter when epicsExitCallAtExits is invoked. |
epicsExitCallAtThreadExits |
This calls each of the functions that were registered by the current thread calling epicsAtThreadExit, in reverse order of the function registration. This routine is called automatically when an epicsThread’s main entry method returns, but will not be run if the thread is stopped by other means. |
epicsAtThreadExit |
Register a function and an associated context parameter. The function will be called with the given parameter when epicsExitCallAtThreadExits is invoked by the current thread ending normally, i.e. when the thread function returns. |
|
|
|
|
cvtFast.h provides routines for converting various numeric types into an ascii string. They offer a combination of speed and convenience not available with sprintf().
This directory contains various C++ template headers and APIs:
Currently these are only being used by Channel Access Clients and the portable Channel Access Server.
dbmf.h (Database Macro/Free) describes a facility that prevents memory fragmentation when memory is allocated and then freed a short time later.
Routines within iocCore like dbLoadDatabase() have the following attributes:
In some environments, e.g. vxWorks 5.x, this behavior causes severe memory fragmentation.
The dbmf facility stops the memory fragmentation. It should NOT be used by code that allocates storage and then keeps it for a considerable period of time before releasing. Such code can use the freeList library described below.
Routine |
Meaning |
dbmfInit() |
Initialize the facility. Each time malloc() must be called size*chunkItems bytes are allocated. size is the maximum size request from dbmfMalloc() that will be allocated from the dbmf pool. If dbmfInit() was not called before one of the other routines then it is automatically called with size=64 and chuckItems=10. |
dbmfMalloc() |
Allocate memory. If bytes is > size then malloc() is used to allocate the memory. |
dbmfFree() |
Free the memory allocated by dbmfMalloc(). |
dbmfFreeChunks() |
Free all chunks that have contain only free items. |
dbmfShow() |
Show the status of the dbmf memory pool. |
|
|
|
|
ellLib.h describes a double linked list library. It provides functionality similar to the vxWorks lstLib library. See the vxWorks documentation for details. There is an ellXXX() routine to replace most vxWorks lstXXX() routines.
epicsRingBytes.h describes a C facility for a commonly used type of ring buffer.
EpicsRingBytes provides methods for creating and using ring buffers (first in first out circular buffers) that store bytes. The unlocked variant is designed so that one writer thread and one reader thread can access the ring simultaneously without requiring mutual exclusion. The locked variant uses an epicsSpinLock, and works with any numbers of writer and reader threads.
Method |
Meaning |
epicsRingBytesCreate() |
Create a new ring buffer of size nbytes. The returned epicsRingBytesId is passed to the other ring methods. |
epicsRingBytesLockedCreate() |
Same as epicsRingBytesCreate, but create the spin lock secured variant of the ring buffer. |
epicsRingBytesDelete() |
Delete the ring buffer and free any associated memory. |
epicsRingBytesGet() |
Move up to nbytes from the ring buffer to value. The number of bytes actually moved is returned. |
epicsRingBytesPut() |
Move nbytes from value to the ring buffer if there is enough free space available to hold them. The number of bytes actually moved is returned, which will be zero if insufficient space exists. |
epicsRingBytesFlush() |
Make the ring buffer empty. |
epicsRingBytesFreeBytes() |
Return the number of free bytes in the ring buffer. |
epicsRingBytesUsedBytes() |
Return the number of bytes currently stored in the ring buffer. |
epicsRingBytesSize() |
Return the size of the ring buffer, i.e., nbytes specified in the call to epicsRingBytesCreate(). |
epicsRingBytesIsEmpty() |
Return (true, false) if the ring buffer is currently empty. |
epicsRingBytesIsFull() |
Return (true, false) if the ring buffer is currently empty. |
|
|
|
|
epicsRingBytes has the following properties:
epicsRingPointer.h describes a C++ and a C facility for a commonly used type of ring buffer.
EpicsRingPointer provides methods for creating and using ring buffers (first in first out circular buffers) that store pointers. The unlocked variant is designed so that one writer thread and one reader thread can access the ring simultaneously without requiring mutual exclusion. The locked variant uses an epicsSpinLock, and works with any numbers of writer and reader threads.
An epicsRingPointer cannot be assigned to, copy-constructed, or constructed without giving the size argument. The C++ compiler will object to some of the statements below:
Method |
Meaning |
epicsRingPointer() |
Constructor. The size is the maximum number of elements (pointers) that can be stored in the ring. If locked is true, the spin lock secured variant is created. |
~epicsRingPointer() |
Destructor. |
push() |
Push a new entry on the ring. It returns (false,true) is (failure, success). Failure means the ring was full. |
pop() |
Take a element off the ring. It returns 0 (null) if the ring was empty. |
flush() |
Remove all elements from the ring. If this operation is performed on a ring buffer of the unsecured variant, all access to the ring should be locked. |
getFree() |
Return the amount of empty space in the ring, i.e. how many additional elements it can hold. |
getUsed() |
Return the number of elements stored on the ring |
getSize() |
Return the size of the ring, i.e. the value of size specified when the ring was created. |
isEmpty() |
Returns true if the ring is empty, else false. |
isFull() |
Returns true if the ring is full, else false. |
|
|
|
|
Each C function corresponds to one of the C++ methods.
epicsRingPointerCreate() creates the unsecured variant, epicsRingPointerLockedCreate() creates the spin lock secured variant of the ring buffer.
epicsTimer.h describes a C++ and a C timer facility.
Method |
Meaning |
epicsTimerNotify:: expire() |
Code using an epicsTimer must include a class that inherits from epicsTimerNotify. The derived class must implement the method expire(), which is called by the epicsTimer when the associated timer expires. epicsTimerNotify defines a class expireStatus which makes it easy to implement both one shot and periodic timers. A one-shot expire() returns with the statement return(noRestart); A periodic timer returns with a statement like return(restart,10.0); where is second argument is the delay until the next callback. |
epicsTimer |
epicsTimer is an abstract base class. An epics timer can only be created by calling createTimer, which is a method of epicsTimerQueue. |
destroy |
This is provided instead of a destructor. This will automatically call cancel before freeing all resources used by the timer. |
start() |
Starts the timer to expire either at the specified time or the specified number of seconds in the future. If the timer is already active when start is called, it is first canceled. |
cancel() |
If the timer is scheduled, cancel it. If it is not scheduled do nothing. Note that if the expire() method is already running, this call delays until the expire() completes. |
getExpireInfo |
Get expireInfo, which says if timer is active and if so when it expires. |
getExpireDelay() |
Return the number of seconds until the timer will expire. If the timer is not active it returns DBL_MAX |
show() |
Display info about object. |
|
|
|
|
Method |
Meaning |
createTimer() |
This is a “factory” method to create timers which use this queue. |
show() |
Display info about object |
|
|
|
|
Method |
Meaning |
allocate() |
This is a “factory” method to create a timer queue. If okToShare is (true,false) then a (shared, separate) thread will manage the timer requests. If the okToShare constructor parameter is true and a timer queue is already running at the specified priority then it will be referenced for shared use by the application, and an independent timer queue will not be created. This method should not be called from within a C++ static constructor, since the queue thread requires that a current time provider be available and the last-resort time provider is not guaranteed to have been registered until all constructors have run. Editorial note: It is useful for two independent timer queues to run at the same priority if there are multiple processors, or if there is an application with well behaved timer expire functions that needs to be independent of applications with computationally intensive, mutex locking, or IO blocking timer expire functions. |
release() |
Release the queue, i.e. the calling facility will no longer use the queue. The caller MUST ensure that it does not own any active timers. When the last facility using the queue calls release, all resources used by the queue are freed. |
|
|
|
|
These two classes manage a timer queue for single threaded applications. Since it is single threaded, the application is responsible for requesting that the queue be processed.
The C interface provides most of the facilities as the C++ interface. It does not support the periodic timer features. The typedefs epicsTimerQueueNotifyReschedule and epicsTimerQueueNotifyQuantum are the “C” interface equivalents to epicsTimerQueueNotify:: reschedule() and epicsTimerQueueNotify::quantum().
This example allocates a timer queue and two objects which have a timer that uses the queue. Each object is requested to schedule itself. The expire() callback just prints the name of the object. After scheduling each object the main thread just sleeps long enough for each expire to occur and then just returns after releasing the queue.
This example shows how C programs can use EPICS timers.
File Descriptor Manager. fdManager.h describes a C++ implementation. fdmgr.h describes a C implementation. Neither is currently documented.
freeList.h describes routines to allocate and free fixed size memory elements. Free elements are maintained on a free list rather then being returned to the heap via calls to free. When it is necessary to call malloc(), memory is allocated in multiples of the element size.
where
gpHash.h describes a general purpose hash table for character strings. The hash table contains tableSize entries. Each entry is a list of members that hash to the same value. The user can maintain separate directories which share the same table by having a different pvt value for each directory.
where
Together with the program iocLogServer this provides generic support for logging text messages from an IOC or other program to a file on the log server host machine.
A log client runs on the IOC. It accepts string messages and forwards them over a TCP connection to its designated log server (normally running on a host machine).
A log server accepts connections from multiple clients and writes the messages it receives into a rotating file. A log server program (’iocLogServer’) is also part of EPICS base.
Configuration of the iocLogServer, as well as the standard iocLogClient that internally uses this library, are described in Section 10.7.
The header file logClient.h exports the following types and routines:
An abstract data type, representing a log client.
Create a new log client. Will block the calling task for a maximum of 2 seconds trying to connect to a server with the given ip address and port. 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 is done by a background task, that will also periodically (every 5 seconds) flush pending messages out to the server.
Send the given message to the given log client. Messages are not immediately sent to the log server. Instead they are sent whenever the cache overflows, or logClientFlush() is called.
Immediately send all outstanding messages to the server.
Print information about the log clients internal state to stdout.
For backward compatibility with older versions of the logClient library, the header file also includes iocLog.h, which exports the definitions for the standard iocLogClient for error logging. See Chapter 10.7.2.
Also for backward compatibility, the following deprecated routines are exported.
Create a log client using the environment variables EPICS_IOC_LOG_INET and EPICS_IOC_LOG_PORT as inputs to logClientCreate and also registers the client with the errlog task using errlogAddListener.
Check the global variable iocLogDisable before calling logClientSend.
macLib.h describes a general purpose macro substitution library. It is used for all macro substitution in base.
NOTE: The directory <base>/src/libCom/macLib contains two files macLibNOTES and macLibREADME that explain this library.
epicsThreadPool.h implements general purpose threaded work queue. Pieces of work (jobs) are submitted to a queue which is shared by a group of worker threads. After jobs are placed on the queue they may be executed in any order.
The thread pool library will never implicitly destroy pools or jobs. Such cleanup is always the responsibility of user code.
An epicsThreadPool instance can be obtained in two ways. The preferred method is the use an existing shared thread pool. Alternately, a new pool may be explicitly created. In both cases NULL may be passed to use the configuration, or a non-default configuration may be prepared in the following way.
Pool configuration should always be initialized with epicsThreadPoolConfigDefault() before modification by user code. This will initialize configuration parameters to sensible defaults, which can then be overwritten as needed by user code.
Note that no epicsThreadPool functions will ever retain a pointer to the user provided epicsThreadPoolConfig instance.
These defaults are choosen to be suitable for CPU intensive background work by drivers.
A shared thread pool is obtained by calling epicsThreadPoolGetShared(). A global list of shared pools is examined. If an existing pool matches the requested configuration, then it is returned. Otherwise a new pool is created, added to the global list, then returned. epicsThreadPoolGetShared() may return NULL in situations of memory exhaustion.
Note that NULL may be passed to use the default configuration.
As for example:
The user provided configuration may be altered to ensure that the maxThreads is greater than or equal to the number of threads the host system can run in parallel. In addition, when a existing shared pool is returned, the user supplied config is overwritten with the pool’s actual config.
If a thread pool will not be used further it must be released, which may cause it to be free’d when no other references exist. It is advisable to ensure that all queued jobs have completed as queued jobs may still run if the other references to the queue remain.
When matching a requested configuration against the configuration of a existing shared pool, the following conditions must be meet for an existing shared queue to be used.
Note that the initialThreads option is ignored when requesting a shared pool.
Unshared thread pools are created/destroyed in a similar fashion.
Note that NULL may be passed to use the default configuration.
When a pool is destroyed it will freeze the queue to prevent new jobs from being added, then block until any previously queued jobs complete.
The normal lifecycle of a job is for it to be created, queued some number of times, then destroyed. Like with an epicsThreadPool⋆, the lifecycle of an epicsJob⋆ is completely controlled by user code. Jobs will never be implicitly destroyed. When created, a pool, work function, and user argument are specified. The special user argument EPICSJOB_SELF may be passed to set the user argument to the epicsJob⋆ returned by epicsJobCreate().
A job may be queued at any time. The queuing process can fail (return non-zero) if:
A job may be unqueued with epicsJobUnqueue(). This function will return 0 if the job was successfully removed from the queue or non-zero if this is not possible. A job can not be unqueued if it was not queued to begin with, is running, or has completed.
A job may also be destroyed at any time, including while its job function is running. In this case destruction is deferred until the job function returns.
If a thread pool is destroyed before all of its jobs are destroyed, then each job function is called one final time with the mode epicsJobModeCleanup to provide an opportunity to call epicsJobDestroy. If this is not done, then the job is disassociated from the pool. It is always the responsibility of user code to explicitly call epicsJobDestroy.
Some restrictions apply to job functions. Only the following epicsThreadPool functions may be called from a job function. When using a shared pool, no modification should be made to the worker threads (eg. don’t change priority). If such modifications are needed, then an exclusively owned pool should be created.
No internal locks are held while a job function runs. So a job function may lock arbitrary mutexes without causing a deadlock. When in a job function, care must be taken to only call those function explicitly marked as safe to call from a running job function as these functions are written to avoid corrupting the internal state of the pool.
It may be desirable to move epicsJob instances between pools, or to have jobs not associated with any pool. This is supported with the caveat that the epicsJobMove() function must not run concurrently with any other epicsThreadPool functions operating on the same job. In addition to functions operating explicitly on this job, this also includes epicsThreadPoolDestroy()
A job may be created with no pool association by passing NULL to the epicsJobCreate() function instead of an explicit epicsThreadPool⋆ pointer. The association can be changed at runtime with the epicsJobMove() function.
It may be useful to manipulate the queue of a thread pool at runtime (eg. unittests). Currently defined options are:
These options may be combined with epicsThreadPoolWait() to block until the queue is empty.
epicsThreadPoolWait() accepts a timeout in seconds. A timeout value less than 0.0 never times out, a value of exactly 0.0 will not block, and values greater than 0.0 will block for the requested time at most.
This function returns 0 if the queue was emptied and no jobs are running at any moment during the timeout period, or non-zero if the timeout period ellapses and jobs remain in the queue or are running.
The function prototype for this routine appears in osiSock.h
aToIPAddr() fills in the structure pointed to by the pIP argument with the Internet address and port number specified by the pAddrString argument.
Three forms of pAddrString are accepted:
The Internet address of the host, specified as four (usually decimal) numbers separated by periods.
The Internet address number of the host, specified as a single (usually hexadecimal) number.
The Internet host name of the host.
In all cases the ‘:p’ may be omitted in which case the port number is set to the value of the defaultPort argument. The numbers are normally interpreted in base 16 if they begin with ‘0x’ or ‘0X’, in base 8 if they begin with ‘0’, and in base 10 otherwise. However the numeric forms are interpreted by the operating system’s gethostbyname() function, thus the acceptable bases may be OS-specific.
adjustment.h describes a single function:
adjustToWorstCaseAlignment() returns a value >= size that an exact multiple of the worst case alignment for the architecture on which the routine is executed.
cantProceed.h declares routines that are provided for code that can’t proceed when an error occurs.
cantProceed() accepts a printf format string and variable number of arguments; it displays the error message and suspends the current task. It will never return. callocMustSucceed() and mallocMustSucceed() can be used in place of calloc() and malloc(). If size or count are zero, or the memory allocation fails, they output a message and call cantProceed().
dbDefs.h includes the C header stddef.h and then defines several generally-useful macros if they have not already been defined:
epicsConvert.h currently describes:
epicsConvertDoubleToFloat converts a double to a float. If the double value is outside the range that can be represented as a float the value assigned will be FLT_MIN or FLT_MAX with the appropriate matching sign. A floating exception is never raised.
epicsString.h currently describes:
epicsStrnRawFromEscaped copies up to strlen characters from the string src into a buffer dst of size dstlen, converting C-style escape sequences into their binary form. A zero byte terminates the input string. The resulting string will be zero-terminated as long as dstlen is non-zero. The return value is the number of characters that were actually written into dst, not counting characters that would not fit or the zero terminator. Since the output string can never be longer than the source, it is legal for src and dst to point to the same buffer and strlen and dstlen to have the same value, thus performing the character translation in-place.
epicsStrnEscapedFromRaw does the opposite of epicsStrnRawFromEscaped: It tries to copy strlen characters from the string src into a buffer dst of size dstlen, converting non-printable characters into C-style escape sequences. A zero byte will not terminate the input string. The output string will be zero-terminated as long as dstlen is non-zero. No more than dstlen characters will actually be written into the output buffer, although all the characters in the input string will be read. The return value is the number of characters that would have been stored in the output buffer if it were large enough, or a negative value if dst == src. 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:
All other non-printable characters appear as octal escapes in form \ooo where ooo are three octal digits (0-7). Non-printable characters are determined by the C runtime library’s isprint() function.
epicsStrnEscapedFromRawSize scans up to strlen characters of the string src that may contain non-printable characters, and returns the size of the output buffer that would be needed to escape that string. The terminating zero-byte needed in the output buffer is not included in the count, so must be allowed for by the caller. This routine is faster than calling epicsStrnEscapedFromRaw with a zero length output buffer; both should return the same result.
epicsStrPrintEscaped prints the contents of its input buffer, substituting escape sequences for non-printable characters.
epicsStrCaseCmp and epicsStrnCaseCmp implement the strcasecmp and strncasecmp functions respectively, which are not available on all supported operating systems. They operate like strcmp and strncmp, but are case insensitive, using the C locale.
epicsStrDup implements strdup, which is not available on all supported operating systems. It allocates sufficient memory for the string, copies it and returns a pointer to the new copy. The pointer should eventually be passed to the function free(). If insufficient memory is available cantProceed() is called.
epicsStrGlobMatch returns non-zero if the str matches the shell wild-card pattern.
epicsStrtok_r implements strtok_r, which is not available on all operating systems.
epicsStrHash calculates a hash of a zero-terminated string str, while epicsMemHash uses the same algorithm on a fixed-length memory buffer that may contain zero bytes. In both cases an initial seed value may be provided which permits multiple strings or buffers to be combined into a single hash result. The final result should be masked to achieve the desired number of bits in the hash value.
epicsTypes.h provides typedefs for architecture independent data types.
So far the definitions provided in this header file have worked on all architectures. In addition to the above definitions epicsTypes.h has a number of definitions for displaying the types and other useful definitions. See the header file for details.
A C++ template for use as an exception object, used inside Channel Access. Not documented here.
This is the header file for the “decorated names” that appear in header files, e.g.
Thse are needed to properly create DLLs on windows. Read the comments in the shareLib.h file for a detailed description of where they should be used. Note that the epicsShareAPI decorator is deprecated for all new EPICS APIs and is being removed from APIs that are only used within the IOC.
where
truncateFile() truncates the file to the specified size. truncate() is not used because it is not portable. It returns TF_OK if the file is less than size bytes or if it was successfully truncated. It returns TF_ERROR if the file could not be truncated.
Defines macros OSI_PATH_LIST_SEPARATOR and OSI_PATH_SEPARATOR
The unit test routines make it easy for a test program to generate output that is compatible with the Test Anything Protocol and can thus be used with Perl’s automated Test::Harness as well as generating human-readable output. The routines detect whether they are being run automatically and print a summary of the results at the end if not.
A test program starts with a call to testPlan(), announcing how many tests are to be conducted. If this number is not known a value of zero can be used during development, but it is recommended that the correct value be substituted after the test program has been completed.
Individual test results are reported using any of testOk(), testOk1(), testOkV(), testPass() or testFail(). The testOk() call takes and also returns a logical pass/fail result (zero means failure, any other value is success) and a printf-like format string and arguments which describe the test. The convenience macro testOk1() is provided which stringifies its single condition argument, reducing the effort needed when writing test programs. The individual testPass() and testFail() routines can be used when the test program takes a different path on success than on failure, but one or other must always be called for any particular test. The testOkV() routine is a varargs form of testOk() included for internal purposes which may prove useful in some cases.
If some program condition or failure makes it impossible to run some tests, the testSkip() routine can be used to indicate how many tests are being omitted from the run, thus keeping the test counts correct; the constant string why is displayed as an explanation to the user (this string is not printf-like).
If some tests are expected to fail because functionality in the module under test has not yet been fully implemented, these tests may still be executed, wrapped between calls to testTodoBegin() and testTodoEnd(). testTodoBegin() takes a constant string indicating why these tests are not expected to succeed. This modifies the counting of the results so the wrapped tests will not 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 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 Test Anything Protocol. For multiple lines of diagnostic output, call testDiag() as many times as necessary.
If at any time the test program is unable to continue for some catastrophic reason, calling testAbort() with an appropriate message will ensure that the test harness understands this. testAbort() does not return, but calls the ANSI C routine abort() to cause the program to stop immediately.
After all of the tests have been completed, the return value from testDone() can be used as the return status code from the program’s main() routine.
On vxWorks and RTEMS, an alternative test harness can be used to run a series of tests in order and summarize the results from them all at the end just like the Perl harness does. The routine testHarness() is called once at the beginning of the test harness program. Each test program is run by passing its main routine name to the runTest() macro which expands into a call to the runTestFunc() routine. The last test program or the harness program itself must finish by calling epicsExit() which triggers the test summary mechanism to generate its result outputs (from an epicsAtExit callback routine).
Some tests require the context of an IOC to be run. This conflicts with the idea of running multiple tests within a test harness, as iocInit() is only allowed to be called once, and some parts of the full IOC (e.g. the rsrv CA 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 cleany using iocShutdown(). This feature is only intended to be used from test programs. Do not use it on productional 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:
The part from iocBuildIsolated() to iocShutdown() can be repeated to execute multiple tests within one executable or harness.
To make it easier to create a single test program that can be built for both the embedded and workstation operating system harnesses, the header file testMain.h provides a convenience macro MAIN() that adjusts the name of the test program according to the platform it is running on: main() on workstations and a regular function name on embedded systems.
The following is a simple example of a test program using the epicsUnitTest routines:
The output from running the above program looks like this: