/** * @file * @brief QXK/C eXtended (blocking) thread. * @ingroup qxk * @cond ****************************************************************************** * Last updated for version 5.9.7 * Last updated on 2017-08-20 * * Q u a n t u m L e a P s * --------------------------- * innovating embedded systems * * Copyright (C) Quantum Leaps, LLC. All rights reserved. * * This program is open source 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. * * Alternatively, this program may be distributed and modified under the * terms of Quantum Leaps commercial licenses, which expressly supersede * the GNU General Public License and are specifically designed for * licensees interested in retaining the proprietary status of their code. * * This program 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Contact information: * https://state-machine.com * mailto:info@state-machine.com ****************************************************************************** * @endcond */ #ifndef qxthread_h #define qxthread_h /****************************************************************************/ /*! 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. * * @sa * - QXThread_ctor() * - QXTHREAD_START() * - QXTHREAD_POST_X() * - Q_XTHREAD_CAST() * - QXThread_delay() * - QXThread_delayCancel() * - QXThread_queueGet() * - ::QActive * * @usage * The following example illustrates how to instantiate an extended thread * in your application. * @include qf_qxthread.c */ typedef struct { QActive super; /* inherit QActive */ QTimeEvt timeEvt; /* time event to handle timeouts */ } QXThread; /*! 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. */ typedef QActiveVtbl QXThreadVtbl; /*! Polymorphically start an extended thread. */ /** * @description * Starts execution of the thread and registers the thread with the framework. * * @param[in,out] me_ pointer (see @ref oop) * @param[in] prio_ priority of the extended-thread * @param[in] qSto_ pointer to the storage for the ring buffer of the * message queue (possibly NULL) * @param[in] qLen_ length of the message queue [events] (possibly 0) * @param[in] stkSto_ pointer to the stack storage (required) * @param[in] stkSize_ stack size [bytes] * @param[in] param_ pointer to the additional port-specific parameter(s) * (might be NULL). * @usage * @include qxk_start.c */ #define QXTHREAD_START(me_, prio_, qSto_, qLen_, stkSto_, stkLen_, param_) \ ((*((QActiveVtbl const *)((me_)->super.super.vptr))->start)( \ &(me_)->super, (prio_), (QEvt const **)(qSto_), (qLen_), \ (stkSto_), (stkLen_), (param_))) /*! Thread handler pointer-to-function */ typedef void (*QXThreadHandler)(QXThread * const me); /*! constructor of an extended-thread */ void QXThread_ctor(QXThread * const me, QXThreadHandler handler, uint_fast8_t tickRate); /** * @description * This macro does not assert if the queue overflows and cannot accept * the event with the specified margin of free slots remaining. * * @param[in,out] me_ pointer (see @ref oop) * @param[in] e_ pointer to the event to post * @param[in] margin_ the minimum free slots in the queue, which * must still be available after posting the event * @param[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 @p 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 @p sender_ * argument, so the overhead of passing this extra argument is entirely * avoided. * * @note 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 * @include qf_postx.c */ #define QXTHREAD_POST_X(me_, e_, margin_, sender_) \ QACTIVE_POST_X(&(me_)->super, (e_), (margin_), (sender_)) /*! delay (block) the current extended thread for a specified # ticks */ bool QXThread_delay(uint_fast16_t const nTicks); /*! cancel the delay */ bool QXThread_delayCancel(QXThread * const me); /*! obtain a message from the private message queue (block if no messages) */ QEvt const *QXThread_queueGet(uint_fast16_t const nTicks); /*! no-timeout special timeout value when blocking on queues or semaphores */ #define QXTHREAD_NO_TIMEOUT ((uint_fast16_t)0) /*! 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. */ #define Q_XTHREAD_CAST(handler_) ((QXThreadHandler)(handler_)) /****************************************************************************/ /*! Counting Semaphore of the QXK preemptive kernel */ /** * @description * QXSemaphore is a blocking mechanism applicable only to the extended threads * ::QXThread. The semaphore is initialized with the maximum count, which * allows you to create a binary semaphore (when the maximum count is 1) and * counting semaphore when the maximum count is > 1. * * @sa * - QXSemaphore_init() * - QXSemaphore_signal() * - QXSemaphore_wait() * - QXSemaphore_tryWait() * * @usage * The following example illustrates how to instantiate the semaphore * in your application. * @include qf_qxsema.c */ typedef struct { QPSet waitSet; /*!< set of extended-threads waiting on this semaphore */ uint_fast16_t count; uint_fast16_t max_count; } QXSemaphore; /*! initialize the counting semaphore */ void QXSemaphore_init(QXSemaphore * const me, uint_fast16_t count, uint_fast16_t max_count); /*! wait (block) on the semaphore */ bool QXSemaphore_wait(QXSemaphore * const me, uint_fast16_t const nTicks); /*! try wait on the semaphore (non-blocking) */ bool QXSemaphore_tryWait(QXSemaphore * const me); /*! signal (unblock) the semaphore */ bool QXSemaphore_signal(QXSemaphore * const me); /****************************************************************************/ /*! Priority Ceiling Mutex the QXK preemptive kernel */ /** * @description * ::QXMutex is a blocking mutual exclusion mechanism. The mutex is * initialized with the ceiling QP priority, which must be bigger than any * extended thread competing for this mutex. The QP priority level used a the * ceiling must be not used for any other active object or thread in the * application. * * @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 @ref QXK_schedLock() "selective QXK scheduler locking" should be used * instead. @ref QXK_schedLock() "Selective scheduler locking" is available * for both @ref ::QActive "basic threads" and @ref ::QXThread extended * threads, so it is applicable to situations where resources are shared * among all these threads. * * @sa * - QXMutex_init() * - QXMutex_lock() * - QXMutex_tryLock() * - QXMutex_unlock() * * @usage * The following example illustrates how to instantiate the mutex in your * application. * @include qf_qxmux.c */ typedef struct { QPSet waitSet; /*!< set of extended-threads waiting on this mutex */ uint_fast8_t ceiling; uint_fast8_t lockNest; } QXMutex; /*! initialize the QXK priority-ceiling mutex ::QXMutex */ void QXMutex_init(QXMutex * const me, uint_fast8_t ceiling); /*! lock the QXK priority-ceiling mutex ::QXMutex */ bool QXMutex_lock(QXMutex * const me, uint_fast16_t const nTicks); /*! try to lock the QXK priority-ceiling mutex ::QXMutex */ bool QXMutex_tryLock(QXMutex * const me); /*! unlock the QXK priority-ceiling mutex ::QXMutex */ void QXMutex_unlock(QXMutex * const me); #endif /* qxthread_h */