QP/C  6.0.0
qxthread.h File Reference

QXK/C eXtended (blocking) thread. More...

Go to the source code of this file.

Data Structures

struct  QXThread
 eXtended (blocking) thread of the QXK preemptive kernel More...
 
struct  QXSemaphore
 Counting Semaphore of the QXK preemptive kernel. More...
 
struct  QXMutex
 Blocking Mutex the QXK preemptive kernel. More...
 

Macros

#define QXTHREAD_START(me_, prio_, qSto_, qLen_, stkSto_, stkLen_, param_)
 Polymorphically start an extended thread. More...
 
#define QXTHREAD_POST_X(me_, e_, margin_, sender_)   QACTIVE_POST_X(&(me_)->super, (e_), (margin_), (sender_))
 
#define QXTHREAD_NO_TIMEOUT   ((uint_fast16_t)0)
 no-timeout special timeout value when blocking on queues or semaphores
 
#define Q_XTHREAD_CAST(handler_)   ((QXThreadHandler)(handler_))
 Perform cast to QXThreadHandler. More...
 

Typedefs

typedef QActiveVtbl QXThreadVtbl
 Virtual Table for the QXThread class (inherited from QActiveVtbl) More...
 
typedef void(* QXThreadHandler) (QXThread *const me)
 Thread handler pointer-to-function.
 

Functions

void QXThread_ctor (QXThread *const me, QXThreadHandler handler, uint_fast8_t tickRate)
 constructor of an extended-thread More...
 
bool QXThread_delay (uint_fast16_t const nTicks)
 delay (block) the current extended thread for a specified # ticks More...
 
bool QXThread_delayCancel (QXThread *const me)
 cancel the delay
 
QEvt const * QXThread_queueGet (uint_fast16_t const nTicks)
 obtain a message from the private message queue (block if no messages) More...
 
void QXSemaphore_init (QXSemaphore *const me, uint_fast16_t count, uint_fast16_t max_count)
 initialize the counting semaphore More...
 
bool QXSemaphore_wait (QXSemaphore *const me, uint_fast16_t const nTicks)
 wait (block) on the semaphore More...
 
bool QXSemaphore_tryWait (QXSemaphore *const me)
 try wait on the semaphore (non-blocking) More...
 
bool QXSemaphore_signal (QXSemaphore *const me)
 signal (unblock) the semaphore More...
 
void QXMutex_init (QXMutex *const me, uint_fast8_t ceiling)
 initialize the QXK priority-ceiling mutex QXMutex More...
 
bool QXMutex_lock (QXMutex *const me, uint_fast16_t const nTicks)
 lock the QXK priority-ceiling mutex QXMutex More...
 
bool QXMutex_tryLock (QXMutex *const me)
 try to lock the QXK priority-ceiling mutex QXMutex More...
 
void QXMutex_unlock (QXMutex *const me)
 unlock the QXK priority-ceiling mutex QXMutex More...
 

Detailed Description

QXK/C eXtended (blocking) thread.

Definition in file qxthread.h.


Data Structure Documentation

◆ QXThread

struct QXThread

eXtended (blocking) thread of the QXK preemptive kernel

Description
QXThread represents the eXtended (blocking) thread of the QXK preemptive kernel. Each extended thread in the application must be represented by the corresponding QXThread instance
Note
Typically, QXThread is instantiated directly in the application code. The customization of the thread occurs in the QXThread_ctor(), where you provide the thred-handler function as the parameter.
See also
Usage
The following example illustrates how to instantiate an extended thread in your application.

Definition at line 71 of file qxthread.h.

Data Fields
QActive super
QTimeEvt timeEvt

◆ QXSemaphore

struct QXSemaphore

Counting Semaphore of the QXK preemptive kernel.

Description
QXSemaphore is a blocking mechanism intended primarily for signaling extended threads. The semaphore is initialized with the maximum count (see QXSemaphore_init()), which allows you to create a binary semaphore (when the maximum count is 1) and counting semaphore when the maximum count is > 1.
See also
Usage
The following example illustrates how to instantiate the semaphore in your application.

Definition at line 186 of file qxthread.h.

Data Fields
QPSet waitSet set of extended-threads waiting on this semaphore
uint16_t count
uint16_t max_count

◆ QXMutex

struct QXMutex

Blocking Mutex the QXK preemptive kernel.

Description
QXMutex is a blocking mutual exclusion mechanism that can also apply the priority ceiling protocol to avoid unbounded priority inversion (if initialized with a non-zero ceiling priority, see QXMutex_init()). In that case, QXMutex requires its own uinque QP priority level, which cannot be used by any thread or any other QXMutex. If initialzied with zero ceiling priority, QXMutex does not use the priority ceiling protocol and does not require a unique QP priority (see QXMutex_init()). QXMutex is recursive (reentrant), which means that it can be locked mutiliple times (up to 255 levels) by the same thread without causing deadlock. QXMutex is primarily intended for the extened (blocking) threads, but can also be used by the basic threads through the non-blocking QXMutex_tryLock() API.
Note
QXMutex should be used in situations when at least one of the extended threads contending for the mutex blocks while holding the mutex (between the QXMutex_lock() and QXMutex_unlock() operations). If no blocking is needed while holding the mutex, the more efficient non-blocking mechanism of selective QXK scheduler locking should be used instead. Selective scheduler locking is available for both basic threads and extendedthreads", so it is applicable to situations where resources are shared among all these threads.
See also
Usage
The following example illustrates how to instantiate the mutex in your application.

Definition at line 248 of file qxthread.h.

Data Fields
QPSet waitSet set of extended-threads waiting on this mutex
uint8_t ceiling
uint8_t lockNest
uint8_t holderPrio

Macro Definition Documentation

◆ QXTHREAD_START

#define QXTHREAD_START (   me_,
  prio_,
  qSto_,
  qLen_,
  stkSto_,
  stkLen_,
  param_ 
)
Value:
((*((QActiveVtbl const *)((me_)->super.super.vptr))->start)( \
&(me_)->super, (prio_), (QEvt const **)(qSto_), (qLen_), \
(stkSto_), (stkLen_), (param_)))
Virtual table for the QActive class.
Definition: qf.h:166
Event structure.
Definition: qep.h:153

Polymorphically start an extended thread.

Description
Starts execution of the thread and registers the thread with the framework.
Parameters
[in,out]me_pointer (see Object Orientation)
[in]prio_priority of the extended-thread
[in]qSto_pointer to the storage for the ring buffer of the message queue (possibly NULL)
[in]qLen_length of the message queue [events] (possibly 0)
[in]stkSto_pointer to the stack storage (required)
[in]stkSize_stack size [bytes]
[in]param_pointer to the additional port-specific parameter(s) (might be NULL).
Usage
int main() {
. . .
/* stack for the QXK's idle thread */
static uint64_t idleStackSto[32];
Test_ctor(); /* instantiate the Test "naked" thread */
QF_init(); /* initialize the framework */
BSP_init(); /* initialize the Board Support Package */
/* initialize QXK... */
QXK_init(idleStackSto, sizeof(idleStackSto));
/* initialize publish-subscribe... */
QF_psInit(subscrSto, Q_DIM(subscrSto));
/* initialize event pools... */
QF_poolInit(smlPoolSto, sizeof(smlPoolSto), sizeof(smlPoolSto[0]));
/* start the active objects... */
QACTIVE_START(AO_Table, /* AO to start */
(uint_fast8_t)(N_PHILO + 2), /* QP priority of the AO */
tableQueueSto, /* event queue storage */
Q_DIM(tableQueueSto), /* queue length [events] */
tableStackSto, /* stack storage */
sizeof(tableStackSto), /* stack size [bytes] */
(QEvt *)0); /* initialization event */
. . .
/* start the "naked" thread */
QXTHREAD_START(XT_Test, /* Thread to start */
(uint_fast8_t)10U, /* QP priority of the thread */
testQueueSto, /* message queue storage */
Q_DIM(testQueueSto), /* message length [events] */
testStackSto, /* stack storage */
sizeof(testStackSto), /* stack size [bytes] */
(QEvt *)0); /* initialization event */
return QF_run(); /* run the QF application */
}

Definition at line 101 of file qxthread.h.

◆ QXTHREAD_POST_X

#define QXTHREAD_POST_X (   me_,
  e_,
  margin_,
  sender_ 
)    QACTIVE_POST_X(&(me_)->super, (e_), (margin_), (sender_))
Description
This macro does not assert if the queue overflows and cannot accept the event with the specified margin of free slots remaining.
Parameters
[in,out]me_pointer (see Object Orientation)
[in]e_pointer to the event to post
[in]margin_the minimum free slots in the queue, which must still be available after posting the event
[in]sender_pointer to the sender object.
Returns
'true' if the posting succeeded, and 'false' if the posting failed due to insufficient margin of free slots available in the queue.
Note
The sender_ parameter is actually only used when QS tracing is enabled (macro Q_SPY is defined). When QS software tracing is disabled, the QACTIVE_POST() macro does not pass the sender_ argument, so the overhead of passing this extra argument is entirely avoided.
the pointer to the sender object is not necessarily a pointer to an active object. In fact, if QACTIVE_POST() is called from an interrupt or other context, you can create a unique object just to unambiguously identify the sender of the event.
Usage
extern QActive *AO_Table;
. . .
/* typically inside a state machine action */
TableEvt *pe;
Q_NEW_X(pe, TableEvt, 5U, HUNGRY_SIG); /* dynamic alloc, margin==5 */
if (pe != (TableEvt *)0) {
pe->philNum = me->num;
QACTIVE_POST_X(AO_Table, &pe->super, 3U, me); /* margin==3 */
}
. . .

Definition at line 141 of file qxthread.h.

◆ Q_XTHREAD_CAST

#define Q_XTHREAD_CAST (   handler_)    ((QXThreadHandler)(handler_))

Perform cast to QXThreadHandler.

Description
This macro encapsulates the cast of a specific thread handler function pointer to QXThreadHandler, which violates MISRA-C 2004 rule 11.4(adv). This macro helps to localize this deviation.

Definition at line 163 of file qxthread.h.

Typedef Documentation

◆ QXThreadVtbl

Virtual Table for the QXThread class (inherited from QActiveVtbl)

Note
QXThread inherits QActive without adding any new virtual functions and therefore, QXThreadVtbl is typedef'ed as QActiveVtbl.

Definition at line 82 of file qxthread.h.

Function Documentation

◆ QXThread_ctor()

void QXThread_ctor ( QXThread *const  me,
QXThreadHandler  handler,
uint_fast8_t  tickRate 
)

constructor of an extended-thread

Description
Performs the first step of QXThread initialization by assigning the thread-handler function and the tick rate at which it will handle the timeouts.
Parameters
[in,out]mepointer (see Object Orientation)
[in]handlerthe thread-handler function
Note
Must be called only ONCE before QXTHREAD_START().
Usage
The following example illustrates how to invoke QXThread_ctor() in the main() function

Definition at line 94 of file qxk_xthr.c.

◆ QXThread_delay()

bool QXThread_delay ( uint_fast16_t const  nTicks)

delay (block) the current extended thread for a specified # ticks

delay (block) the current extended thread for a specified # ticks

Precondition
this function must:
  • NOT be called from an ISR;
  • be called from an extended thread;
  • the thread must NOT be holding a scheduler lock and;
  • the thread must NOT be already blocked on any object.

Definition at line 580 of file qxk_xthr.c.

◆ QXThread_queueGet()

QEvt const* QXThread_queueGet ( uint_fast16_t const  nTicks)

obtain a message from the private message queue (block if no messages)

Description
The QXThread_queueGet() operation allows the calling extended thread to receive QP events directly into its own built-in event queue from an ISR, basic thread (AO), or another extended thread.

If QXThread_queueGet() is called when no events are present in the thread's event queue, the operation blocks the current extended thread until either an event is received, or a user-specified timeout expires.

Parameters
[in]nTicksnumber of clock ticks (at the associated rate) to wait for the event to arrive. The value of QXTHREAD_NO_TIMEOUT indicates that no timeout will occur and the queue will block indefinitely.
Returns
A pointer to the event. If the pointer is not NULL, the event was delivered. Otherwise the event pointer of NULL indicates that the queue has timed out.
Precondition
this function must:
  • NOT be called from an ISR;
  • be called from an extended thread;
  • the thread must NOT be holding a scheduler lock;
  • the thread must NOT be already blocked on any object.

Definition at line 392 of file qxk_xthr.c.

◆ QXSemaphore_init()

void QXSemaphore_init ( QXSemaphore *const  me,
uint_fast16_t  count,
uint_fast16_t  max_count 
)

initialize the counting semaphore

Description
Initializes a semaphore with the specified count and maximum count. If the semaphore is used for resource sharing, both the initial count and maximum count should be set to the number of identical resources guarded by the semaphore. If the semaphore is used as a signaling mechanism, the initial count should set to 0 and maximum count to 1 (binary semaphore).
Parameters
[in,out]mepointer (see Object Orientation)
[in]countinitial value of the semaphore counter
[in]max_countmaximum value of the semaphore counter. The purpose of the max_count is to limit the counter so that the semaphore cannot unblock more times than the maximum.
Note
QXSemaphore_init() must be called before the semaphore can be used (signaled or waited on).
Precondition
max_count must be greater than zero

Definition at line 78 of file qxk_sema.c.

◆ QXSemaphore_wait()

bool QXSemaphore_wait ( QXSemaphore *const  me,
uint_fast16_t const  nTicks 
)

wait (block) on the semaphore

Description
When an extended thread calls QXSemaphore_wait() and the value of the semaphore counter is greater than 0, QXSemaphore_wait() decrements the semaphore counter and returns (true) to its caller. However, if the value of the semaphore counter is 0, the function places the calling thread in the waiting list for the semaphore. The thread waits until the semaphore is signaled by calling QXSemaphore_signal(), or the specified timeout expires. If the semaphore is signaled before the timeout expires, QXK resumes the highest-priority extended thread waiting for the semaphore.
Parameters
[in,out]mepointer (see Object Orientation)
[in]nTicksnumber of clock ticks (at the associated rate) to wait for the semaphore. The value of QXTHREAD_NO_TIMEOUT indicates that no timeout will occur and the semaphore will wait indefinitely.
[in]tickRatesystem clock tick rate serviced in this call.
Returns
'true' if the semaphore has been signaled and 'false' if a timeout occured.
Note
Multiple extended threads can wait for a given semahpre.
Precondition
this function must:
  • NOT be called from an ISR;
  • the semaphore must be initialized
  • be called from an extended thread;
  • the thread must NOT be holding a scheduler lock;
  • the thread must NOT be already blocked on any object.

Definition at line 113 of file qxk_sema.c.

◆ QXSemaphore_tryWait()

bool QXSemaphore_tryWait ( QXSemaphore *const  me)

try wait on the semaphore (non-blocking)

Description
This function checks if the semaphore counter is greater than 0, in which case the counter is decremented.
Parameters
[in,out]mepointer (see Object Orientation)
Returns
'true' if the semaphore has count available and 'false' NOT available.
Note
This function can be called from any context, including ISRs and basic threds (active objects).
Precondition
the semaphore must be initialized

Definition at line 173 of file qxk_sema.c.

◆ QXSemaphore_signal()

bool QXSemaphore_signal ( QXSemaphore *const  me)

signal (unblock) the semaphore

Description
If the semaphore counter value is 0 or more, it is incremented, and this function returns to its caller. If the extended threads are waiting for the semaphore to be signaled, QXSemaphore_signal() removes the highest- priority thread waiting for the semaphore from the waiting list and makes this thread ready-to-run. The QXK scheduler is then called to determine if the awakened thread is now the highest-priority thread that is ready-to-run.
Parameters
[in,out]mepointer (see Object Orientation)
Returns
'true' when the semaphore signaled and 'false' when the semaphore count exceeded the maximum.
Note
A semaphore can be signaled from many places, including from ISRs, basic threads (AOs), and extended threads.
Precondition
the semaphore must be initialized

Definition at line 214 of file qxk_sema.c.

◆ QXMutex_init()

void QXMutex_init ( QXMutex *const  me,
uint_fast8_t  ceiling 
)

initialize the QXK priority-ceiling mutex QXMutex

Description
Initialize the QXK priority ceiling mutex.
Parameters
[in,out]mepointer (see Object Orientation)
[in]ceilingthe ceiling-priotity of this mutex or zero
Note
ceiling == 0 means that the priority-ceiling protocol shall not be used by this mutex. Such mutex will not change (boost) the priority of the holding thread.
ceiling > 0 means that the priority-ceiling protocol shall be used by this mutex. Such mutex will boost the priority of the holding thread to the ceiling level for as long as the thread holds this mutex.
Attention
When the priority-ceiling protocol is used (ceiling > 0), the ceiling priority must be unused by any other thread or mutex. Also, the ceiling priority must be higher than priority of any thread that uses this mutex.
Usage
QXMutex l_rndMutex; /* mutex to protect the random number generator */
void BSP_randomSeed(uint32_t seed) {
QXMutex_init(&l_rndMutex, N_PHILO); /* <== initialize the mutex */
l_rnd = seed;
}
uint32_t BSP_random(void) { /* a very cheap pseudo-random-number generator */
uint32_t rnd;
QXMutex_lock(&l_rndMutex); /* <== lock the shared random seed */
/* "Super-Duper" Linear Congruential Generator (LCG) */
rnd = l_rnd * (3U*7U*11U*13U*23U);
l_rnd = rnd; /* set for the next time */
QXMutex_unlock(&l_rndMutex); /* <== unlock the shared random seed */
return rnd;
}
Precondition
the celiling priority of the mutex must:
  • cannot exceed the maximum QF_MAX_ACTIVE;
  • the ceiling priority of the mutex must not be already in use; (QF requires priority to be unique).

Definition at line 85 of file qxk_mutex.c.

◆ QXMutex_lock()

bool QXMutex_lock ( QXMutex *const  me,
uint_fast16_t const  nTicks 
)

lock the QXK priority-ceiling mutex QXMutex

Description
Lock the QXK priority ceiling mutex QXMutex.
Parameters
[in,out]mepointer (see Object Orientation)
[in]nTicksnumber of clock ticks (at the associated rate) to wait for the semaphore. The value of QXTHREAD_NO_TIMEOUT indicates that no timeout will occur and the semaphore will wait indefinitely.
Returns
'true' if the mutex has been acquired and 'false' if a timeout occured.
Note
The mutex locks are allowed to nest, meaning that the same extended thread can lock the same mutex multiple times (< 255). However, each call to QXMutex_lock() must be ballanced by the matching call to QXMutex_unlock().
Usage
QXMutex l_rndMutex; /* mutex to protect the random number generator */
void BSP_randomSeed(uint32_t seed) {
QXMutex_init(&l_rndMutex, N_PHILO); /* <== initialize the mutex */
l_rnd = seed;
}
uint32_t BSP_random(void) { /* a very cheap pseudo-random-number generator */
uint32_t rnd;
QXMutex_lock(&l_rndMutex); /* <== lock the shared random seed */
/* "Super-Duper" Linear Congruential Generator (LCG) */
rnd = l_rnd * (3U*7U*11U*13U*23U);
l_rnd = rnd; /* set for the next time */
QXMutex_unlock(&l_rndMutex); /* <== unlock the shared random seed */
return rnd;
}
Precondition
this function must:
  • NOT be called from an ISR;
  • be called from an extended thread;
  • the ceiling priority must not be used; or if used
    • the thread priority must be below the ceiling of the mutex;
  • the thread must NOT be holding a scheduler lock;
  • the thread must NOT be already blocked on any object.

Definition at line 131 of file qxk_mutex.c.

◆ QXMutex_tryLock()

bool QXMutex_tryLock ( QXMutex *const  me)

try to lock the QXK priority-ceiling mutex QXMutex

Description
Try to lock the QXK priority ceiling mutex QXMutex.
Parameters
[in,out]mepointer (see Object Orientation)
Returns
'true' if the mutex was successfully locked and 'false' if the mutex was unavailable and was NOT locked.
Note
This function can be called from both basic threads (active objects) and extended threads.
The mutex locks are allowed to nest, meaning that the same extended thread can lock the same mutex multiple times (<= 225). However, each successful call to QXMutex_tryLock() must be ballanced by the matching call to QXMutex_unlock().
Precondition
this function must:
  • NOT be called from an ISR;
  • the QXK kernel must be running;
  • the calling thread must be valid;
  • the ceiling must be not used; or
    • the thread priority must be below the ceiling of the mutex;
  • the thread must NOT be holding a scheduler lock;

Definition at line 241 of file qxk_mutex.c.

◆ QXMutex_unlock()

void QXMutex_unlock ( QXMutex *const  me)

unlock the QXK priority-ceiling mutex QXMutex

Description
Unlock the QXK priority ceiling mutex.
Parameters
[in,out]mepointer (see Object Orientation)
Note
This function can be called from both basic threads (active objects) and extended threads.
The mutex locks are allowed to nest, meaning that the same extended thread can lock the same mutex multiple times (<= 225). However, each call to QXMutex_lock() or a successfull call to QXMutex_tryLock() must be ballanced by the matching call to QXMutex_unlock().
Usage
QXMutex l_rndMutex; /* mutex to protect the random number generator */
void BSP_randomSeed(uint32_t seed) {
QXMutex_init(&l_rndMutex, N_PHILO); /* <== initialize the mutex */
l_rnd = seed;
}
uint32_t BSP_random(void) { /* a very cheap pseudo-random-number generator */
uint32_t rnd;
QXMutex_lock(&l_rndMutex); /* <== lock the shared random seed */
/* "Super-Duper" Linear Congruential Generator (LCG) */
rnd = l_rnd * (3U*7U*11U*13U*23U);
l_rnd = rnd; /* set for the next time */
QXMutex_unlock(&l_rndMutex); /* <== unlock the shared random seed */
return rnd;
}
Precondition
this function must:
  • NOT be called from an ISR;
  • the calling thread must be valid;
  • the mutex must be held by this thread;
  • the ceiling must not be used or
    • the current thread must have priority equal to the mutex ceiling;
  • the mutex must be already locked at least once.

Definition at line 331 of file qxk_mutex.c.