text:
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.
<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.
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:
osi directory are installed into
osi/os/<os> are installed into
The search order for locating the specific file to be installed is:
osi/os/posix -- if the target uses Posix APIs
osi/compiler/<cmplr> are installed into the directory
The search order for locating the specific file to be installed is:
The search order for locating OSD source files is:
When code is compiled, the search order for locating header files in
base/include is:
This is an enhanced version of ANSI C's
assert facility. To use this, replace:
#include <assert.h>
#include "epicsAssert.h"
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.
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:
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.
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
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
#include <epicsAtomic.h>
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
|Load target into cache.
|Push cache version of target into target.
|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.
|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.
|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.
|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.
|Set the cached version of target, and flush the cache to the target.
|Fetch the target into cache, and return the cached value.
|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.
|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.
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 */
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.
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: ... };
|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.
|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 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.
|A synonym for trigger, provided for backwards compatibility.
|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.
|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.
|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:
epicsEvent *pevent = new epicsEvent;
while(1) { pevent->wait(); while(/* more work */) { /* process work */ } }
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.
epicsEventSignal macro provides backwards compatibility.
The routines
epicsEventMustTrigger and
epicsEventMustWait do not return if they fail.
epicsFindSymbol.h contains the following definitions:
void * epicsFindSymbol(const char *name); void * epicsLoadLibrary(const char *name); const char *epicsLoadError(void);
|Return the address of the named variable
|Load named shared library
|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 can locate the symbol, it returns the associated address, otherwise it returns null.
On vxWorks
epicsFindSymbol calls
On Linux, Darwin and Solaris it calls
The default version just returns null, i.e. it always fails.
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.
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.
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.
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);
|Initialise the framework. This is called automatically by any function that requires the framework. It does not need to be called explicitly.
|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.
|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"
|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"
|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"
|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"
|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"
|Provide information about the installed providers and their current best times.
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);
|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.
|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.
|Add or replace an interrupt-safe provider routine for an already-registered current time provider with the given name and priority.
|Add or replace an interrupt-safe provider routine for an already-registered event time provider with the given name and priority.
|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.
The generalTime framework also now provides the implementations of the following routines that are declared in
int epicsTimeGetCurrent(epicsTimeStamp *pDest); int epicsTimeGetEvent(epicsTimeStamp *pDest, int eventNumber); int epicsTimeGetCurrentInt(epicsTimeStamp *pDest); int epicsTimeGetEventInt(epicsTimeStamp *pDest, int eventNumber);
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.
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") }
epicsInterrupt.h contains the following:
int epicsInterruptLock(); void epicsInterruptUnlock(int key); int epicsInterruptIsInterruptContext(); void epicsInterruptContextMessage(const char *message);
|Lock interrupts and return a key to be passed to epicsInterruptUnlock To lock the following is done. int key; ... key = epicsInterruptLock(); ... epicsInterruptUnlock(key);
|Unlock interrupts.
|Return (true, false) if current context is interrupt context.
|Generate a message while interrupt context is true.
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:
epicsMath.h includes math.h and also ensures that isnan and isinf are defined.
epicsMessageQueue.h describes a C++ and a C facility for interlocked communication between threads.
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
|Constructor. The capacity is the maximum number of messages, each containing 0 to maximumMessageSize bytes, that can be stored in the message queue.
|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 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.
|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.
|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.
|Displays some information about the message queue. The level argument controls the amount of information dispalyed.
|Returns the number of messages presently in the queue.
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.
epicsMutex.h contains both C++ and C descriptions for a mutual exclusion semaphore.
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: };
|Create a mutual exclusion semaphore.
|Remove the semaphore and any resources it uses. Any further use of the semaphore result in unknown (most certainly bad) results.
|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.
|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.
|Release the resource. If a thread issues recursive locks, there must be an unlock for each lock
|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.
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.
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();
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.
The implementation:
A posix version is implemented via pthreads.
epicsSpin.h contains definitions for a spin lock semaphore.
typedef struct epicsSpin *epicsSpinId; epicsSpinId epicsSpinCreate(); void epicsSpinDestroy(epicsSpinId); void epicsSpinLock(epicsSpinId); int epicsSpinTryLock(epicsSpinId); void epicsSpinUnlock(epicsSpinId);
|Create a spin lock, allocate required resources, and initialize it to an unlocked state.
|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.
|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.
|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.
|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.
The default implementation uses POSIX spin locks on POSIX compliant systems, and epicsMutex for non-POSIX environments.
epicsStdlib.h includes
stdlib.h and
epicsTypes.h and provides declarations for a series of string to number conversion functions and macros.
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.
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.
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
#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.
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
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
vsnprintf is a size-limited version of
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.
TF_ERROR if the file could not be truncated.
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
Stderr and
Putchar are not normally named directly in user code.
They are provided for the following macros that redefine the well-known C identifiers:
stdin becomes
stdout becomes
stderr becomes
printf becomes
puts becomes
putchar becomes
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
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.
epicsTempName function will probably be deprecated in a future release of Base.
epicsThread.h contains C++ and C descriptions for a thread.
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);
|Get a stack size value that can be given to epicsThreadCreate. The size argument should be one of the values epicsThreadStackSmall, epicsThreadStackMedium or epicsThreadStackBig.
|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.
|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.
|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.
|This causes the calling thread to suspend. The only way it can resume is for another thread to call epicsThreadResume.
|Resume a suspended thread. Only do this if you know that it is safe to resume a suspended thread.
|Get the priority of the specified thread.
|Get the priority of this thread.
|Set a new priority for the specified thread. The result is implementation dependent.
|Get a priority that is just lower than the specified priority.
|Get a priority that is just above the specified priority.
|Compares two threadIds and returns (0,1) if they (are not, are) the same.
|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.
|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.
|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.
|Get the threadId of the calling thread.
|Get the threadId of the specified thread. A return value of 0 means that no thread was found with the specified name.
|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.
|Get the name of the calling thread.
|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.
|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.
|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.
|Display info about all threads.
|Display info about the specified thread.
|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.
|Remove routine from the list of hooks run at thread creation time.
|Print the current list of hook function pointers.
|Call func once for every known thread.
|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.
|Delete a thread private variable.
|Set the value for a thread private pointer.
|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:
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
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
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() { // ... }
epicsTime.h contains C++ and C descriptions for time.
/* 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.
epicsTimeStamp - This is the structure used by the C interface for epics time stamps. The C++ interface stores
this information in private members. The two elements of the class are:
secPastEpoch - The number of seconds since January 1, 1990 (the epics epoch).
nsec - nanoseconds within a second
TS_STAMP is defined for compatibility with existing code.
timespec - This is defined by POSIX Real Time. It requires two mandatory fields:
time_t tv_sec - Number of seconds since 1970 (The POSIX epoch)
long tv_nsec - nanoseconds within a second
timeval - BSD and SRV5 Unix timestamp. It has two fields:
time_t tv_sec - Number of seconds since 1970 (The POSIX epoch)
time_t tv_nsec - nanoseconds within a second
struct l_fp - Network Time Protocol timestamp. The fields are:
lui - Number of seconds since 1900 (The NTP epoch)
luf - Fraction of a second. For example 0x800000000 represents 1/2 second.
local_tm_nano_sec and
gm_tm_nano_sec - Defined by epics. These just add a nanosecond field to
struct tm.
time_t_wrapper - This is for converting to/from the ANSI C
time_t. Since
time_t is usually an
elementary type providing a conversion operator from
time_t to/from
epicsTime could cause undesirable
implicit conversions. Providing a conversion operator to/from a
time_t_wrapper prevents implicit
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.
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: ... };
class epicsShareClass epicsTimeEvent { public: epicsTimeEvent (const int &number); operator int () const; private: int eventNumber; };
|Convert to/from integer
|Does not currently check that the range of the integer is valid, although it might one day.
|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) { ...
|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
|Shows the date/time.
/* 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
osiPoolStatus.h contains the following description:
int osiSufficentSpaceInPool(void);
|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.
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.
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.
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.
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:
be_, and
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.
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.
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.
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.
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.
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+size) for the given bus address type. It returns an error if any location responds or if any such
location cannot be mapped.
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" };
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.
long devAddressMap(void)
This routine displays the table of registered VME address ranges, including the owner of each registered address.
long devUnregisterAddress( epicsAddressType addrType, size_t logicalBaseAddress, const char *pOwnerName);
This routine releases address ranges previously registered by a call to
devRegisterAddress or
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.
long devConnectInterruptVME( unsigned vectorNumber, void (*pFunction)(void *), void *parameter);
Connect ISR
pFunction up to the VME interrupt
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
int devInterruptInUseVME( unsigned vectorNumber);
Determines if a VME interrupt vector is in use, returning a boolean value.
long devEnableInterruptLevelVME( unsigned level);
Enable the given VME interrupt level onto the CPU.
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.
#define devCreateMask(NBITS)((1<<(NBITS))-1) #define devDigToNml(DIGITAL,NBITS) \ (((double)(DIGITAL))/devCreateMask(NBITS))
#define devNmlToDig(NORMAL,NBITS) \ (((long)(NORMAL)) * devCreateMask(NBITS))
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.
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.
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.
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.
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.
The routines described in this section are included in a application by the Makfile command:
<appl>_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary
This routine shows the vxWorks interrupt vector table, but only works properly on 68K family CPUs.
This traps all calls to logMsg and sends them to errlogPrintf.
This was included with 3.13.
This provides the routines
symFindByNameEPICS and
It is only provided for modules that have not been converted to use
These routines are deprecated.
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
This is only provided for device/driver support that have not been converted to use OSI features of base. This header is deprecated.
This routine causes epicsDynLink, logMsgToErrlog and veclist to be loaded.


text:
Compare and contrast art history with art appreciation.
Comparing and contrasting Art History with Art Appreciation
Source: Citations: Image of Kells Public Domain http://en.wikipedia.org/wiki/File:KellsFol032vChristEnthroned.jpg; Image by Sesshu Public Domain http://en.wikipedia.org/wiki/File:SesshuShuutouTou.jpg
Hello. I'd like to welcome you to this episode of "Exploring Art History with Ian." My name is Ian McConnell. Today's lesson is about comparing and contrasting art history with art appreciation.
As you watch the video, feel free to pause, move forward, or rewind as many times as you feel is necessary. As soon as you're ready, we can begin
Today's objectives, or the things you're going to learn today, are listed below. By the end of the lesson today, you'll be able to identify and define today's key terms, and compare and contrast art history with art appreciation. Short listen today.
Today's key terms, as always, are listed in yellow throughout the lesson.
First key term-- art history is the academic study of the history and development of the visual arts.
And art appreciation, the application basic tools of visual literacy in order to understand and appreciate works of art.
The big idea, the common theme or thread that runs throughout this lesson, is that art history is more than just critique. Art history considers the meaning the works of art in a larger social context.
So what is art appreciation? Well, like it says here, it's applying basic tools of visual literacy to understand and appreciate work of art. I like to think of it as art history lite.
So why do we care? Well, there is an advantage to it, and that's a person art appreciator can understand something about the work of art while understanding very little, or maybe nothing at all, about its history. So an art appreciator could look at a picture like the one on the right. It's a piece of cover art from the Book of Kells. And being an art appreciator, they could use concepts like composition, knowledge of color, geometry, et cetera, and they could understand and appreciate this work of art.
The disadvantage is that you'd lose a broader sense of meaning associated with the work of art. I'll give you an example of what I mean by that. I'll show you on the next slide. What ends up happening is that the work of art sort of stands alone.
So context helps. This example is a simple demonstration of the importance of context to help illustrate why art history ultimately has the advantage over art appreciation when evaluating works of art.
If you were to judge these pictures of my son individually, you may be left with a very different interpretation. They can definitely be appreciated in their own right, but the story behind the photograph is lost unless you're able to expand upon what's represented by fitting it into a broader social context. Without knowing me, you would have a hard time interpreting where the story takes place, and, at least in the second picture, my abilities to safely parent.
Well, just like the works of art, they can be appreciated as they are, alone, with nothing else to associate them with. The meaning or story behind the work of art is completely lost. In the last photograph, the entire picture is revealed. You're likely left with a very different interpretation of the story than you were with the first two pictures.
I'm using the revealing of the entire photograph as an analogy to revealing context with respect to works of art. The more information you have, the better evaluation you can make.
So when evaluating a piece of art strictly through art appreciation, you get the sense that the work, while it can be appreciated, is really standing alone. It doesn't fit within a broader social context. So that's the art appreciation approach to evaluating a work of art.
So here's where art history differs from art appreciation in that it's part of something more. We're thinking about context. Think back to the photo example that I showed you, and how the more you saw, the more context you had, even though it's just visual context there. But take it in the spirit in which it was intended. The more context you had, the better you understood the story, the better you understood the story behind the work of art.
And so if we can take a look at art and if we can fit it within a broader social context, we can see how things like war, religion, politics, and changes in technology, we can see how those things had an effect on not only the artist but on the artwork that was produced.
So let's take a look at our objectives again and see how we did. Now that you've seen the lesson, can you identify and define today's key terms? Can you compare and contrast art history with art appreciation?
And the big idea, the common thread or theme that runs throughout this lesson, is that art history is more than just critique. And the way that it differs from art appreciation is that art history considers the meaning of works of art in a larger social context. It's the history part of art history.
I'd like to thank you for joining me today, and I'll see you next time. Bye bye.
The application of basic tools of visual literacy in order to understand and appreciate works of art.
The academic study of the history and development of the visual arts.

subset: commoncrawl


text:
|Collegiate »
|Professional »
NOTICE: Please use the internet browsers Google Chrome, Firefox or Safari when trying to login to our membership portal. Internet Explorer 8, 9 and 10 are no longer supported and IE 11 has limited compatibility.
Community of Support
SWE is an inclusive organization focused on issues of interest to women specializing in engineering and technical careers.
Education and Development
SWE's education and outreach activities are designed to enhance the quality of life for women of all backgrounds who pursue the profession of engineering.
Resources and Information
As a worldwide leader in engineering knowledge and support, SWE is a partner you can turn to for advanced, relevant information about women in technical careers.
Leadership Skills
Members are encouraged and supported in the development of skills necessary to be effective leaders in a global marketplace.
During the last couple years, SWE launched an initiative designed to foster inclusiveness and engage the diverse members of our organization – SWE Affinity Groups. Affinity Groups are small groups within the organization where individuals sharing a common element of diversity work collaboratively together! The program is growing, and we now have 5 active affinity groups with champions who want to connect with you and establish a network within SWE for you to ASPIRE, ADVANCE, and ACHIEVE within the organization.
Affinity Groups
Affinity Group Champions
With our Affinity Group program comes new leadership opportunities to build and grow the groups. We currently have 5 active Affinity Groups: African American, Latina, LGBT & Allies (Lesbian, Gay, Bisexual, Transgender), Internationals, and Native American. We have several other potential groups waiting for the right person to step forward and become a Champion.
Affinity Group Participation
Contact the Affinity Group Coordinator to join the conversation on creating diversity within the workplace. We look forward to hearing from you.
African American
LGBT & Allies
IRIS (Internationals Residing in the States)
Native American
Small Business
SWE membership offers numerous diverse benefits, including discounts on brand-name goods and services such as appliances, automobiles, insurance and education opportunities. And, every time you take advantage of these member discounts you suppport SWE through rebates that participating organizations give back to the Society.
See if you qualify for a discount on membership dues.
Up to $500 Savings on Auto Insurance
GM Supplier Discount
$30 Off Career Re-entry Program
15% Off UCLA Extension's Technical Mangement Program
A SWE collegiate membership is a great way to prepare for a successful engineering career. As a member, you are part of a community of peers with access to exceptional tools, scholarships, training, and role models. And with all the recreational activities, it's a lot of fun, too!
A SWE collegiate membership offers outstanding value! Your membership includes:
SWE Membership is available to college students pursuing a degree in engineering, engineering technology, or a field related to engineering and not employed full time in an engineering position. No application fee is required. View the available collegiate membership types below and join SWE. Already a SWE member? Click here to renew your membership!
|Collegiate to Career (C2C)
|For a one-time $50 payment, collegiate members can secure a SWE membership for their collegiate years through the first year they qualify for professional grade membership. C2C is beneficial to students with two or more years of schooling left or those pursuing an advanced degree. Renewal is required each year, at no charge, to confirm continued SWE Membership. Take advantage of this program to maximize your savings on membership dues. For more information, please read the Frequently Asked Questions.
|SWE Membership is available for $20 to college students majoring in engineering and must be renewed annually to obtain membership benefits.
|Take advantage of a reduced joint membership rate when you join both SWE and one of these three professional organizations: The American Indian Science and Engineering Society (AISES), the National Society of Black Engineers (NSBE), and the Society of Hispanic Professional Engineers (SHPE). (Only available April 15 - December 31)
|Country of Residence Discount
|Take advantage of a reduced membership rate based on your country of residence. Click here to learn more or go directly to the online application.
SWE members pursuing advanced degrees full-time have the option of continuing as a collegiate member or transferring their professional membership to a Professional Back to School. To be identified as a graduate student member, your SWE membership profile should be updated with your current academic status including discipline of study and an anticipated graduation date.
Graduate students in SWE are an active, growing group. To serve this diverse population, a group of Graduate Coordinators are appointed each year. These coordinators provide programming, networking, etc. for past, present and future graduate students.
For more information about SWE's graduate program, see the SWE Graduate Blog or e-mail the Graduate Member Coordinator.
SWE offers many different kinds of professional memberships, each tailored to our members' unique needs at different stages of their engineering careers.
View the available professional membership types below to determine which type meets your specific needs before you join SWE. Already a member? Click here to renew your membership!
NOTE: SWE membership is open to both women AND men.
|Recent Graduate
|Graduates with a graduation date within the past 24 months, receive a reduced rate for professional membership whether a new or renewing member. Current collegiate members receive an even greater reduced rate.
|More than 100 professional active sections in the U.S. for women and men. If no section is located nearby, you join as a Member-at-Large. Professional membership is $100* annually.
|Take advantage of a reduced joint membership rate when you join both SWE and one of these three professional organizations: The American Indian Science and Engineering Society (AISES), the National Society of Black Engineers (NSBE), and the Society of Hispanic Professional Engineers (SHPE). (Only available April 15 - December 31) Select Joint Membership with AISES, NSBE and SHPE below for more information.
|Life membership is available with a donation of $2,000 to the SWE Endowment Fund Inc. - Headquarters Account. For more information, Email Fund Development.
A reduced rate of $50* is offered to retired or unemployed professional members. Email Membership Services if you are retired or unemployed for additional information.
|SWE membership is available for $100* annually to those who support the goals of the Society but do not qualify for any other membership grade and whose work is related to the practice of, or training for engineering, or the membership application is sponsored by a professional member. The sponsor must be a member of the senate, a professional section president, member at large president, region governor, or corporate member. Email Membership Services for additional information.
|Country of Residence Discount
|Take advantage of a reduced membership rate depending on your country of residence. For more information, select International Membership below.
|K-12 Educator
|A special reduced membership rate of $20 is available to full-time K-12 educators. For more information, select K-12 Educator Membership below.
*New professional members pay a $20 application fee.
SWE membership provides the vehicle for you to give back to the community through outreach programs that encourage young girls to find and follow their dreams as future engineers. SWE's K-12 initiatives motivate students to believe in their math and science skills, and expose engineering as a meaningful and rewarding career choice for women.
The environment you face everyday is full of obstacles to your advancement including isolation, lack of role models and limited access to informal networks. SWE provides the programs and communities that address issues ranging from leadership training to management tools to networking events to work/life balance workshops. Whether you are just entering the workforce or a seasoned professional, SWE has programs targeted for each stage of your career path.
Complementing your professional advancement, SWE celebrates those who achieve personal and professional milestones. SWE's Awards Program recognizes professional members who have contributed significantly to the advancement of women in the engineering profession. SWE members celebrate the rich history and heritage of women in engineering and technology, and honor today's leaders and innovators.
Benefits of SWE Membership
The benefits of SWE membership come in many forms—from the empowerment of finding the right mentor to the satisfaction of seeing the look on the face of a 12-year-old girl successfully completing a science project and experiencing the thrill of applied engineering and creativity for the first time!
Professional Brochure PDF
Online Application
PDF Application
Life membership is available with a donation of $2,000 to the SWE Endowment Fund Inc. - Headquarters Account. Review the Life Member contract for more information and to join. If you have questions, please contact Fund Development.
SWE helps organizations support their leadership training, achieve their recruitment and retention goals and advance their women engineers and technologists. As a Corporate Member of SWE, you can fulfill your organization's objectives and access these resources.
Learn more about Corporate Membership
Contact: Jennifer Scott
Phone: 312.596.5220
SWE is proud to serve its international members and welcomes you to join. SWE recognizes the economic variances throughout the world and discounts dues based on the 2011 World Bank list of economies.
See below to determine if you qualify for a discount on membership dues depending on your country of residence. Membership benefits include:
Benefits will vary by country and other possible benefits include:
Please note: This discount applies to basic Professional and Collegiate grades of membership and cannot be combined with other offers.
*Full dues-paying members will continue to receive a printed copy of the SWE Magazine.
List of countries eligible for membership discounts (Low Income economies get the 66% discount and Low Middle economies get the 33% discount)
Joint Membership opportunities with AISES, NSBE and SHPE are available with online applications and renewals from April 15 through December 31.
SWE is proud to announce that:
Professional and Collegiate members can join SWE and either the American Indian Science and Engineering Society (AISES), the National Society of Black Engineers (NSBE), or the Society of Hispanic Professional Engineers (SHPE) at a single, discounted rate.
Joint membership with AISES, NSBE and SHPE further promotes an inclusive environment within SWE. The goals of this important partnership program are to improve networking opportunities and expand professional development programs for American Indian, African American and Hispanic women engineers.
This offer represents up to 30% savings over joining two organizations separately.
About AISES
The American Indian Science & Engineering Society (AISES) is a national, nonprofit organization that nurtures community building by bridging science and technology with traditional Native values. Through its educational programs, AISES provides opportunities for American Indians and Native Alaskans to pursue studies in science, engineering, and technology arenas. The AISES mission is to increase substantially the representation of American Indian and Alaskan Natives in engineering, science and other related technology disciplines. For more information, visit www.aises.org.
About NSBE
The National Society of Black Engineers is the premier organization serving African Americans in engineering and technology. With 15,000 members and more than 300 chapters, NSBE supports and promotes the aspirations of university and pre-college students and technical professionals. Our mission is to increase the number of culturally responsible black engineers who excel academically, succeed professionally and positively impact the community. For more information, visit www.nsbe.org.
About SHPE
The Society of Hispanic Professional Engineers (SHPE) is a non-profit, social-technical organization, and publisher of SHPE Magazine. Founded in 1974, it serves affiliated chapters across seven regions. SHPE fulfills its mission to promote "the development of Hispanics in engineering, science and other technical professions to achieve educational excellence, economic opportunity and social equity" through initiatives in technical education; business and government policy; programs; and more. For more information, visit www.shpe.org.
By working with SWE to offer the new Automation Affiliate Member grade, ISA can now provide you and other SWE members with an excellent selection of technical and professional-development benefits for only $50 per year – half off the regular member dues!
When you become an ISA Automation Affiliate Member, you will be able to access the most timely, useful information in the automation field. In addition, you will gain a worldwide network of technical and career resources that can help you excel in your career. Join today so you can begin using ISA's valuable resources—and watch yourself become a more knowledgeable and valuable automation professional!
SWE is pleased to offer membership to full-time K-12 educators. SWE's mission includes encouraging more women to become engineers, and you can support that mission by helping reach girls. A SWE membership provides valuable K-12 outreach tools and support for you including:
A special reduced membership rate of $20 is available to full-time K-12 educators. Take advantage of it today!


text:
Till I Can Make It On My Ow-crd Tammy Wynette
Subject: TILL I CAN MAKE IT ON MY OWN sung by: TAMMY WYNETTE submitted by: Michelle Sherman (email any corrections to: firstname.lastname@example.com) TILL I CAN MAKE IT ON MY OWN (G)I'll need (D)time (C)to get you off my (G)mind And I may (C)sometimes bother you Try to (G)be in touch with you Even (D)ask to much of you from time to (G)time (G)Now and (D)then (C)Lord you know I'll need a (G)friend Till I get (C)used to losing you Let me (G)keep on using you (D)Till I can make it on my (G)own (G)I'll get (D)by (C)But no matter how I (G)try There'll be (C)times you know I'll call Chances (G)are my tears will fall And I'll (D)have no pride at all, from time to (G)time (G)But they (D)say (C)Oh, there'll be a brighter (G)day But till (C)then I'll lean on you That's (G)all I mean to do (D)Till I can make it on my (G)own Bridge: (C)Surely someday I'll look up and (G)see the morning sun (C)Without another lonely night (D)behind me (C)Then I'll know I'm over you and (G)all my crying's done (D)No more hurtin memories can (C)find (G)me (G)But till (D)then (C)Lord you know I'm gonna need a (G)friend (C)Till I get used to losing you Let me (G)keep on using you, (D)till I can make it on my (G)own (D)Till I can make it (N.C.) on my own
Important: The song above is NOT stored on the Chordie server. The original song is hosted at www.roughstock.com. Chordie works as a search engine and provides on-the-fly formatting. Chordie does not index songs against artists'/composers' will. To remove this song please click here.
This song is displayed as text-only. Transposing and tuning is only available for chordpro-songs.