diff --git a/modules/libcom/src/osi/epicsThread.h b/modules/libcom/src/osi/epicsThread.h index 61ab323b1..694ac94c7 100644 --- a/modules/libcom/src/osi/epicsThread.h +++ b/modules/libcom/src/osi/epicsThread.h @@ -45,6 +45,7 @@ typedef enum { epicsThreadBooleanStatusFail, epicsThreadBooleanStatusSuccess } epicsThreadBooleanStatus; +/** Lookup target specific default stack size */ epicsShareFunc unsigned int epicsShareAPI epicsThreadGetStackSize( epicsThreadStackSizeClass size); @@ -54,6 +55,20 @@ typedef struct epicsThreadOSD *epicsThreadId; typedef epicsThreadId epicsThreadOnceId; #define EPICS_THREAD_ONCE_INIT 0 +/** Perform one-time initialization. + * + * Run the provided function if it has not run, and is not running. + * + * @post The provided function has been run. + * + * @code + * static epicsThreadOnceId onceId = EPICS_THREAD_ONCE_INIT; + * static void myInitFunc(void *arg) { ... } + * static void some Function(void) { + * epicsThreadOnce(&onceId, &myInitFunc, NULL); + * } + * @endcode + */ epicsShareFunc void epicsShareAPI epicsThreadOnce( epicsThreadOnceId *id, EPICSTHREADFUNC, void *arg); @@ -65,6 +80,7 @@ epicsShareFunc void epicsThreadRealtimeLock(void); epicsShareFunc void epicsShareAPI epicsThreadExitMain(void); +/** For use with epicsThreadCreateOpt() */ typedef struct epicsThreadOpts { /** Thread priority in OSI range (cf. epicsThreadPriority*) */ unsigned int priority; @@ -73,57 +89,123 @@ typedef struct epicsThreadOpts { * @warning Do not pass enum epicsThreadStackSizeClass directly! */ unsigned int stackSize; - /** Should thread be joinable? (default (0) is not joinable). */ + /** Should thread be joinable? (default (0) is not joinable). + * If joinable=1, then epicsThreadMustJoin() must be called for cleanup thread resources. + */ unsigned int joinable; } epicsThreadOpts; +/** Fill in target specific default values. */ epicsShareFunc void epicsThreadOptsDefaults(epicsThreadOpts *opts); +/** @brief Allocate and start a new OS thread. + * @param name A name describing this thread. Appears in various log and error message. + * @param funptr The thread main function. + * @param parm Passed to thread main function. + * @param opts Modifiers for the new thread, or NULL to use target specific defaults. + * @return NULL on error + */ epicsShareFunc epicsThreadId epicsThreadCreateOpt ( const char * name, EPICSTHREADFUNC funptr, void * parm, const epicsThreadOpts *opts ); +/** Short-hand for epicsThreadCreateOpt() to create an un-joinable thread. */ epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate ( const char * name, unsigned int priority, unsigned int stackSize, EPICSTHREADFUNC funptr,void * parm ); +/** Short-hand for epicsThreadCreateOpt() to create an un-joinable thread. + * On error calls cantProceed() + */ epicsShareFunc epicsThreadId epicsShareAPI epicsThreadMustCreate ( const char * name, unsigned int priority, unsigned int stackSize, EPICSTHREADFUNC funptr,void * parm ); +/** Wait for a joinable thread to exit (return from its main function */ epicsShareFunc void epicsThreadMustJoin(epicsThreadId id); +/** Block the current thread until epicsThreadResume(). */ epicsShareFunc void epicsShareAPI epicsThreadSuspendSelf(void); +/** Resume a thread suspended with epicsThreadSuspendSelf() */ epicsShareFunc void epicsShareAPI epicsThreadResume(epicsThreadId id); +/** Return thread OSI priority */ epicsShareFunc unsigned int epicsShareAPI epicsThreadGetPriority( epicsThreadId id); +/** Return thread OSI priority */ epicsShareFunc unsigned int epicsShareAPI epicsThreadGetPrioritySelf(void); +/** Change OSI priority of target thread. */ epicsShareFunc void epicsShareAPI epicsThreadSetPriority( epicsThreadId id,unsigned int priority); +/** Lookup the next usage OSI priority such that priority > *pPriorityJustBelow + * if this is possible with the current target configuration and privlages. + */ epicsShareFunc epicsThreadBooleanStatus epicsShareAPI epicsThreadHighestPriorityLevelBelow ( unsigned int priority, unsigned *pPriorityJustBelow); +/** Lookup the next usage OSI priority such that priority < *pPriorityJustBelow + * if this is possible with the current target configuration and privlages. + */ epicsShareFunc epicsThreadBooleanStatus epicsShareAPI epicsThreadLowestPriorityLevelAbove ( unsigned int priority, unsigned *pPriorityJustAbove); +/** Test if two thread IDs actually refer to the same OS thread */ epicsShareFunc int epicsShareAPI epicsThreadIsEqual( epicsThreadId id1, epicsThreadId id2); +/** Test if thread has been suspended with epicsThreadSuspendSelf() */ epicsShareFunc int epicsShareAPI epicsThreadIsSuspended(epicsThreadId id); +/** @brief Block the calling thread for at least the specified time. + * @param seconds Time to wait in seconds. Values <=0 blocks for the shortest possible time. + */ epicsShareFunc void epicsShareAPI epicsThreadSleep(double seconds); +/** @brief Query a value approximating the OS timer/scheduler resolution. + * @return A value in seconds >=0 + * + * @warning On targets other than vxWorks and RTEMS, the quantum value often isn't + * meaningful. Use of this function is discouraged in portable code. + */ epicsShareFunc double epicsShareAPI epicsThreadSleepQuantum(void); +/** Find an epicsThreadId associated with the current thread. + * For non-EPICS threads, a new epicsThreadId may be allocated. + */ epicsShareFunc epicsThreadId epicsShareAPI epicsThreadGetIdSelf(void); +/** Attempt to find the first instance of a thread by name. + * @return An epicsThreadId, or NULL if no such thread is currently running. + * Note that a non-NULL ID may still be invalid if this call races + * with thread exit. + * + * @warning Safe use of this function requires external knowledge that this + * thread will not return. + */ epicsShareFunc epicsThreadId epicsShareAPI epicsThreadGetId(const char *name); +/** Return a value approximating the number of threads which this target + * can run in parallel. This value is advisory. + * @return >=1 + */ epicsShareFunc int epicsThreadGetCPUs(void); +/** Return the name of the current thread. + * + * @return Never NULL. Storage lifetime tied to epicsThreadId. + * + * This is either a copy of the string passed to epicsThread*Create*(), + * or an arbitrary unique string for non-EPICS threads. + */ epicsShareFunc const char * epicsShareAPI epicsThreadGetNameSelf(void); -/* For epicsThreadGetName name is guaranteed to be null terminated */ -/* size is size of buffer to hold name (including terminator) */ -/* Failure results in an empty string stored in name */ +/** Copy out the thread name into the provided buffer. + * + * Guaranteed to be null terminated. + * size is number of bytes in buffer to hold name (including terminator). + * Failure results in an empty string stored in name. + */ epicsShareFunc void epicsShareAPI epicsThreadGetName( epicsThreadId id, char *name, size_t size); epicsShareFunc int epicsShareAPI epicsThreadIsOkToBlock(void); epicsShareFunc void epicsShareAPI epicsThreadSetOkToBlock(int isOkToBlock); +/** Print to stdout information about all running EPICS threads. + * @param level 0 prints minimal output. Higher values print more details. + */ epicsShareFunc void epicsShareAPI epicsThreadShowAll(unsigned int level); +/** Print info about a single EPICS thread. */ epicsShareFunc void epicsShareAPI epicsThreadShow( epicsThreadId id,unsigned int level); @@ -134,10 +216,17 @@ epicsShareFunc int epicsThreadHookDelete(EPICS_THREAD_HOOK_ROUTINE hook); epicsShareFunc void epicsThreadHooksShow(void); epicsShareFunc void epicsThreadMap(EPICS_THREAD_HOOK_ROUTINE func); +/** Thread local storage */ typedef struct epicsThreadPrivateOSD * epicsThreadPrivateId; +/** Allocate a new thread local variable. + * This variable will initially hold NULL for each thread. + */ epicsShareFunc epicsThreadPrivateId epicsShareAPI epicsThreadPrivateCreate(void); +/** Free a thread local variable */ epicsShareFunc void epicsShareAPI epicsThreadPrivateDelete(epicsThreadPrivateId id); +/** Update thread local variable */ epicsShareFunc void epicsShareAPI epicsThreadPrivateSet(epicsThreadPrivateId,void *); +/** Fetch the current value of a thread local variable */ epicsShareFunc void * epicsShareAPI epicsThreadPrivateGet(epicsThreadPrivateId); #ifdef __cplusplus @@ -149,33 +238,64 @@ epicsShareFunc void * epicsShareAPI epicsThreadPrivateGet(epicsThreadPrivateId); #include "epicsEvent.h" #include "epicsMutex.h" +//! Interface used with class epicsThread class epicsShareClass epicsThreadRunable { public: virtual ~epicsThreadRunable () = 0; + //! Thread main function. + //! C++ exceptions which propagate from this method will be caught and a warning printed. + //! No other action is taken. virtual void run () = 0; + //! Optional. Called via epicsThread::show() virtual void show ( unsigned int level ) const; }; extern "C" void epicsThreadCallEntryPoint ( void * ); +/** @brief An OS thread + * + * A wrapper around the epicsThread* C API. + * + * @note Threads must be start() ed. + */ class epicsShareClass epicsThread { public: + /** Create a new thread with the provided information. + * + * cf. epicsThreadOpts + * @note Threads must be start() ed. + * @throws epicsThread::unableToCreateThread on error. + */ epicsThread ( epicsThreadRunable &,const char *name, unsigned int stackSize, unsigned int priority=epicsThreadPriorityLow ); ~epicsThread () throw (); + //! Actually start the thread. void start () throw (); + //! Wait for the thread epicsRunnable::run() to return. void exitWait () throw (); + //! Wait for the thread epicsRunnable::run() to return. + //! @param delay Wait up to this many seconds. + //! @returns true if run() returned. false on timeout. bool exitWait ( const double delay ) throw (); + //! @throws A special exitException which will be caught and ignored. + //! @note This exitException doesn't not derive from std::exception static void exit (); + //! cf. epicsThreadResume() void resume () throw (); + //! cf. epicsThreadGetName(); void getName ( char * name, size_t size ) const throw (); + //! cf. epicsThreadGetIdSelf()() epicsThreadId getId () const throw (); + //! cf. epicsThreadGetPriority() unsigned int getPriority () const throw (); + //! cf. epicsThreadSetPriority() void setPriority ( unsigned int ) throw (); bool priorityIsEqual ( const epicsThread & ) const throw (); bool isSuspended () const throw (); + //! @return true if call through this thread's epicsRunnable::run() bool isCurrentThread () const throw (); bool operator == ( const epicsThread & ) const throw (); + //! Say something interesting about this thread to stdout. void show ( unsigned level ) const throw (); /* these operate on the current thread */