Copyright (C) Kevin Larke 2009-2020

This file is part of libcm.

libcm is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

libcm is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

See the GNU General Public License distributed with the libcm package or look here: .


cmThread : Threads and thread safe containers.

typedef cmHandle_t cmThreadH_t;
typedef unsigned   cmThRC_t;

enum
{
  kOkThRC = cmOkRC,          // 0
  kCreateFailThRC,      // 1
  kDestroyFailThRC,     // 2
  kTimeOutThRC,         // 3
  kInvalidHandleThRC,   // 4
  kLockFailThRC,        // 5
  kUnlockFailThRC,      // 6
  kCVarWaitFailThRC,    // 7
  kCVarSignalFailThRC,  // 8
  kBufFullThRC,         // 9
  kBufEmptyThRC,        // 10
  kBufTooSmallThRC      // 11
  
};

typedef enum 
{
  kNotInitThId,
  kPausedThId,
  kRunningThId,
  kExitedThId   
} cmThStateId_t;


// Return 'false' to indicate that the thread should terminate 
// otherwise return 'true'
typedef bool (*cmThreadFunc_t)(void* param);

extern cmThreadH_t cmThreadNullHandle;

// Create a thread. The thread is automatically set to the 'paused' state.
cmThRC_t      cmThreadCreate(  cmThreadH_t* hPtr, cmThreadFunc_t cmThreadFuncPtr,  void* funcParam, cmRpt_t* rpt );

// Release the resources associated with a thread previously created with cmThreadCreate().
cmThRC_t      cmThreadDestroy( cmThreadH_t* hPtr );

enum 
{ 
  kPauseThFl = 0x01,   // set to pause, clear to unpause
  kWaitThFl  = 0x02    // set to wait for thread to pause/unpause prior to returning.
};

// Pause or unpause a thread.  Set kWaitThFl to wait for the thread to be
// paused or unpaused prior to returning. 
cmThRC_t      cmThreadPause(   cmThreadH_t h, unsigned cmdFlags );

// Return the current thread state.
cmThStateId_t cmThreadState(   cmThreadH_t h );
bool          cmThreadIsValid( cmThreadH_t h);

// The Pause time out gives the period in microseconds which the thread will
// sleep while it is paused.  In other words the thread will wake up
// every 'pause time out micro-seconds' to check to see if it has been
// requested to leave the paused state. Default:50000.
unsigned      cmThreadPauseTimeOutMicros( cmThreadH_t h );
void          cmThreadSetPauseTimeOutMicros( cmThreadH_t h, unsigned usecs );

// The wait time out gives the length of time the thread should expect to 
// wait in order change states.  This value should always be greater than
// or equal to the pause time out and the expected length of time the 
// client callback function will run. 
// This timeout comes into play in two situations:
// 1) This is the maximum length of time that cmThreadPause() will wait for
// the thread to enter/leave the pause state when the kWaitThFl has been set.
// If the thread does not enter/leave the pause state in this amount of time
// then cmThreadPause() returns the error code kTimeOutThRC.
// 2) This is the maximum length of time the cmThreadDestroy() wll wait for
// the thread to enter the 'exited' state after being requested to destroy 
// itself. If this time period expires then cmThreadDestroy() returns
// kTimeOutThRC.
// Default:1000000.
unsigned      cmThreadWaitTimeOutMicros(  cmThreadH_t h );
void          cmThreadSetWaitTimeOutMicros( cmThreadH_t h, unsigned usecs );

void          cmThreadTest( cmRpt_t* rpt );
cmThreadMutex : Thread mutex object.

typedef struct { void* h; } cmThreadMutexH_t; extern cmThreadMutexH_t kCmThreadMutexNULL; cmThRC_t cmThreadMutexCreate( cmThreadMutexH_t* hPtr, cmRpt_t* rpt ); cmThRC_t cmThreadMutexDestroy( cmThreadMutexH_t* hPtr ); cmThRC_t cmThreadMutexTryLock( cmThreadMutexH_t h, bool* lockFlPtr ); cmThRC_t cmThreadMutexLock( cmThreadMutexH_t h ); cmThRC_t cmThreadMutexUnlock( cmThreadMutexH_t h ); bool cmThreadMutexIsValid( cmThreadMutexH_t h ); // Set 'lockFl' if the function should lock the mutex prior to waiting. // If 'lockFl' is false then the function assumes the mutex is already locked // and directly waits. If 'lockFl' is set and the mutex is not already locked // then the result is undefined. cmThRC_t cmThreadMutexWaitOnCondVar( cmThreadMutexH_t h, bool lockFl ); cmThRC_t cmThreadMutexSignalCondVar( cmThreadMutexH_t h );
cmTsQueue : Thread safe message queue.

// cmThread safe message queue. // // This object is intended as a way to serialize one-way // communication between multiple sender threads and one // receiver thread. The object is implemented as // a double buffer. One buffer acts as // an input queue the the other buffer acts as an // output queue. When the output queue is empty the buffers // are swapped. Any pending messages in the input queue // then become available to the receiver in the output queue. // // An internal mutex prevents the queue logic from becoming // corrupted. The mutex is locked during the entire enqueue // operation. The enqueue operation may therefore block its // thread while waiting for mutex access. The dequeue operation // only locks the mutex when the current output buffer is // empty, the input buffer contains messages, and the mutex // is not already locked. The mutex only remains locked for the // period of time necessary to switch the input and output // buffer pointers. The mutex is not locked during the actual // dequeue copy or transmit. // // Given this logic the dequeue thread should never // block because it only locks the mutex when it is not already // locked. The enqueue thread will only block when it happens to collide // with the dequeue buffer switch operation or an enqueue operation // from another thread. If it happens that there is only a single // sender thread then the sender will virtually never block because // the dequeue lock is only maintained for a very short period of time. // typedef cmHandle_t cmTsQueueH_t; extern cmTsQueueH_t cmTsQueueNullHandle; typedef cmRC_t (*cmTsQueueCb_t)(void* userCbPtr, unsigned msgByteCnt, const void* msgDataPtr ); // Set 'cbFunc' to NULL if the dequeue callback option will not be used. cmThRC_t cmTsQueueCreate( cmTsQueueH_t* hPtr, unsigned bufByteCnt, cmTsQueueCb_t cbFunc, void* cbArg, cmRpt_t* rpt ); cmThRC_t cmTsQueueDestroy( cmTsQueueH_t* hPtr ); // Set or clear the dequeue callback option after the queue was created. cmThRC_t cmTsQueueSetCallback( cmTsQueueH_t h, cmTsQueueCb_t cbFunc, void* cbArg ); // Copy a msg into the queue. This function return kBufFullThRC if the buffer is full. // This interface allows the message to be formed from a concatenation of 'arrayCnt' segments. cmThRC_t cmTsQueueEnqueueSegMsg( cmTsQueueH_t h, const void* msgPtrArray[], unsigned msgByteCntArray[], unsigned arrayCnt ); // Copy a msg onto the queue. This function is written in terms of cmTsQueueEnqueueSegMsg(). cmThRC_t cmTsQueueEnqueueMsg( cmTsQueueH_t h, const void* dataPtr, unsigned byteCnt ); // Prepend 'id' to the bytes contained in 'dataPtr[byteCnt]' and enqueue the resulting msg. // This function is written in terms of cmTesQueueEnqueueSegMsg(). cmThRC_t cmTsQueueEnqueueIdMsg( cmTsQueueH_t h, unsigned id, const void* dataPtr, unsigned byteCnt ); // Total size of the queue buffer. unsigned cmTsQueueAllocByteCount( cmTsQueueH_t h ); // Bytes available to enqueue the next message. unsigned cmTsQueueAvailByteCount( cmTsQueueH_t h ); // Remove one msg from the queue. // If 'dataPtr' is not NULL the msg is copied into the buffer it points to. // If 'cbFunc' in the earlier call to cmTsQueueCreate() was not NULL then // the msg is transmitted via the callback. // This function should only be called from the deque thread. cmThRC_t cmTsQueueDequeueMsg( cmTsQueueH_t h, void* dataPtr, unsigned byteCnt ); // thQueueMsgWaiting() returns true if there is a msg available // to dequeue. This function should only be called from the // deque thread. bool cmTsQueueMsgWaiting( cmTsQueueH_t h ); // Return the size in bytes of the next msg to dequeue or zero // if no msgs are waiting. The function should only be called from the // deque thread. unsigned cmTsQueueDequeueMsgByteCount( cmTsQueueH_t h ); bool cmTsQueueIsValid( cmTsQueueH_t h);
cmTs1p1c : Single producer/Single consumer non-blocking thread safe queue.

// Single producer / Single consumer thread-safe queue. // These functions have identical semantics and return values // to the same named cmTsQueueXXXX() calls above. typedef cmHandle_t cmTs1p1cH_t; extern cmTs1p1cH_t cmTs1p1cNullHandle; cmThRC_t cmTs1p1cCreate( cmTs1p1cH_t* hPtr, unsigned bufByteCnt, cmTsQueueCb_t cbFunc, void* cbArg, cmRpt_t* rpt ); cmThRC_t cmTs1p1cDestroy( cmTs1p1cH_t* hPtr ); cmThRC_t cmTs1p1cSetCallback( cmTs1p1cH_t h, cmTsQueueCb_t cbFunc, void* cbArg ); cmThRC_t cmTs1p1cEnqueueSegMsg( cmTs1p1cH_t h, const void* msgPtrArray[], unsigned msgByteCntArray[], unsigned arrayCnt ); cmThRC_t cmTs1p1cEnqueueMsg( cmTs1p1cH_t h, const void* dataPtr, unsigned byteCnt ); unsigned cmTs1p1cAllocByteCount( cmTs1p1cH_t h ); unsigned cmTs1p1cAvailByteCount( cmTs1p1cH_t h ); cmThRC_t cmTs1p1cDequeueMsg( cmTs1p1cH_t h, void* dataPtr, unsigned byteCnt ); bool cmTs1p1cMsgWaiting( cmTs1p1cH_t h ); unsigned cmTs1p1cDequeueMsgByteCount( cmTs1p1cH_t h ); bool cmTs1p1cIsValid( cmTs1p1cH_t h );
cmThCAS : Non-blocking primitive operations.

// Thread safe compare-and-swap (actualy compare-and-test). // Returns true if the *addr==new when the function returns // otherwise returns false. bool cmThIntCAS( int* addr, int old, int neww ); bool cmThUIntCAS( unsigned* addr, unsigned old, unsigned neww ); bool cmThFloatCAS( float* addr, float old, float neww ); // Note: voidPtrPtr is must really be a pointer to a pointer. bool cmThPtrCAS( void* voidPtrPtr, void* old, void* neww ); // Thread safe increment and decrement implemented in terms of // cmThXXXCAS(). void cmThIntIncr( int* addr, int incr ); void cmThUIntIncr( unsigned* addr, unsigned incr ); void cmThFloatIncr(float* addr, float incr ); void cmThIntDecr( int* addr, int decr ); void cmThUIntDecr( unsigned* addr, unsigned decr ); void cmThFloatDecr(float* addr, float decr );
cmMp1c : Multiple producer, single consumer non-blocking thread-safe queue.

// Multiple producer / Single consumer thread-safe queue. // These functions have identical semantics and return values // to the same named cmTsQueueXXXX() calls above.
typedef cmHandle_t cmTsMp1cH_t; extern cmTsMp1cH_t cmTsMp1cNullHandle; cmThRC_t cmTsMp1cCreate( cmTsMp1cH_t* hPtr, unsigned bufByteCnt, cmTsQueueCb_t cbFunc, void* cbArg, cmRpt_t* rpt ); cmThRC_t cmTsMp1cDestroy( cmTsMp1cH_t* hPtr ); void cmTsMp1cSetCbFunc( cmTsMp1cH_t h, cmTsQueueCb_t cbFunc, void* cbArg ); cmTsQueueCb_t cmTsMp1cCbFunc( cmTsMp1cH_t h ); void* cmTsMp1cCbArg( cmTsMp1cH_t h ); cmThRC_t cmTsMp1cEnqueueSegMsg( cmTsMp1cH_t h, const void* msgPtrArray[], unsigned msgByteCntArray[], unsigned arrayCnt ); cmThRC_t cmTsMp1cEnqueueMsg( cmTsMp1cH_t h, const void* dataPtr, unsigned byteCnt ); unsigned cmTsMp1cAllocByteCount( cmTsMp1cH_t h ); unsigned cmTsMp1cAvailByteCount( cmTsMp1cH_t h ); cmThRC_t cmTsMp1cDequeueMsg( cmTsMp1cH_t h, void* dataPtr, unsigned byteCnt ); bool cmTsMp1cMsgWaiting( cmTsMp1cH_t h ); unsigned cmTsMp1cDequeueMsgByteCount( cmTsMp1cH_t h ); bool cmTsMp1cIsValid( cmTsMp1cH_t h ); void cmTsQueueTest( cmRpt_t* rpt ); void cmTs1p1cTest( cmRpt_t* rpt ); void cmTsMp1cTest( cmRpt_t* rpt );
cmSleep : Sleep related functions.
// Sleep functions
void cmSleepUs( unsigned microseconds );
void cmSleepMs( unsigned milliseconds );