diff --git a/demos/STM32/NIL-STM32F303-DISCOVERY/debug/NIL-STM32F303-DISCOVERY (OpenOCD, Flash and Run).launch b/demos/STM32/NIL-STM32F303-DISCOVERY/debug/NIL-STM32F303-DISCOVERY (OpenOCD, Flash and Run).launch index 335ac55b7..9df8eea30 100644 --- a/demos/STM32/NIL-STM32F303-DISCOVERY/debug/NIL-STM32F303-DISCOVERY (OpenOCD, Flash and Run).launch +++ b/demos/STM32/NIL-STM32F303-DISCOVERY/debug/NIL-STM32F303-DISCOVERY (OpenOCD, Flash and Run).launch @@ -1,52 +1,52 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/os/hal/osal/nil/osal.c b/os/hal/osal/nil/osal.c index e486641c5..863be6a75 100644 --- a/os/hal/osal/nil/osal.c +++ b/os/hal/osal/nil/osal.c @@ -48,68 +48,4 @@ /* Module exported functions. */ /*===========================================================================*/ -/** - * @brief Dequeues and wakes up one thread from the queue, if any. - * - * @param[in] tqp pointer to the threads queue object - * @param[in] msg the message code - * - * @iclass - */ -void osalThreadDequeueNextI(threads_queue_t *tqp, msg_t msg) { - semaphore_t *sp = &tqp->sem; - - if (chSemGetCounterI(&tqp->sem) < (cnt_t)0) { - thread_t *tp = nil.threads; - while (true) { - /* Is this thread waiting on this semaphore?*/ - if (tp->u1.semp == sp) { - sp->cnt++; - - chDbgAssert(NIL_THD_IS_WTSEM(tp), "not waiting"); - - (void) chSchReadyI(tp, msg); - return; - } - tp++; - - chDbgAssert(tp < &nil.threads[CH_CFG_NUM_THREADS], - "pointer out of range"); - } - } -} - -/** - * @brief Dequeues and wakes up all threads from the queue. - * - * @param[in] tqp pointer to the threads queue object - * @param[in] msg the message code - * - * @iclass - */ -void osalThreadDequeueAllI(threads_queue_t *tqp, msg_t msg) { - semaphore_t *sp = &tqp->sem; - thread_t *tp; - cnt_t cnt; - - cnt = sp->cnt; - sp->cnt = (cnt_t)0; - tp = nil.threads; - while (cnt < (cnt_t)0) { - - chDbgAssert(tp < &nil.threads[CH_CFG_NUM_THREADS], - "pointer out of range"); - - /* Is this thread waiting on this semaphore?*/ - if (tp->u1.semp == sp) { - - chDbgAssert(NIL_THD_IS_WTSEM(tp), "not waiting"); - - cnt++; - (void) chSchReadyI(tp, msg); - } - tp++; - } -} - /** @} */ diff --git a/os/hal/osal/nil/osal.h b/os/hal/osal/nil/osal.h index 4f81bd53a..807b660c2 100644 --- a/os/hal/osal/nil/osal.h +++ b/os/hal/osal/nil/osal.h @@ -219,6 +219,8 @@ struct event_source { */ typedef semaphore_t mutex_t; + +#if 0 /** * @brief Type of a thread queue. * @details A thread queue is a queue of sleeping threads, queued threads @@ -227,8 +229,9 @@ typedef semaphore_t mutex_t; * because there are no real threads. */ typedef struct { - semaphore_t sem; + thread_reference_t tr; } threads_queue_t; +#endif /*===========================================================================*/ /* Module macros. */ @@ -444,8 +447,7 @@ typedef struct { #ifdef __cplusplus extern "C" { #endif - void osalThreadDequeueNextI(threads_queue_t *tqp, msg_t msg); - void osalThreadDequeueAllI(threads_queue_t *tqp, msg_t msg); + #ifdef __cplusplus } #endif @@ -766,7 +768,7 @@ static inline void osalThreadResumeS(thread_reference_t *trp, msg_t msg) { */ static inline void osalThreadQueueObjectInit(threads_queue_t *tqp) { - chSemObjectInit(&tqp->sem, (cnt_t)0); + chThdQueueObjectInit(tqp); } /** @@ -795,7 +797,33 @@ static inline void osalThreadQueueObjectInit(threads_queue_t *tqp) { static inline msg_t osalThreadEnqueueTimeoutS(threads_queue_t *tqp, systime_t time) { - return chSemWaitTimeoutS(&tqp->sem, time); + return chThdEnqueueTimeoutS(tqp, time); +} + +/** + * @brief Dequeues and wakes up one thread from the queue, if any. + * + * @param[in] tqp pointer to the threads queue object + * @param[in] msg the message code + * + * @iclass + */ +static inline void osalThreadDequeueNextI(threads_queue_t *tqp, msg_t msg) { + + chThdDequeueNextI(tqp, msg); +} + +/** + * @brief Dequeues and wakes up all threads from the queue. + * + * @param[in] tqp pointer to the threads queue object + * @param[in] msg the message code + * + * @iclass + */ +static inline void osalThreadDequeueAllI(threads_queue_t *tqp, msg_t msg) { + + chThdDequeueAllI(tqp, msg); } /** diff --git a/os/nil/include/ch.h b/os/nil/include/ch.h index f21527c2d..8fc480776 100644 --- a/os/nil/include/ch.h +++ b/os/nil/include/ch.h @@ -534,6 +534,9 @@ struct nil_thread { void *p; /**< @brief Generic pointer. */ thread_reference_t *trp; /**< @brief Pointer to thread reference.*/ threads_queue_t *tqp; /**< @brief Pointer to thread queue. */ +#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__) + semaphore_t *semp; /**< @brief Pointer to semaphore. */ +#endif #if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__) eventmask_t ewmask; /**< @brief Enabled events mask. */ #endif @@ -911,6 +914,29 @@ struct nil_system { #define US2RTC(freq, usec) (rtcnt_t)((((freq) + 999999UL) / 1000000UL) * (usec)) /** @} */ +/** + * @name Threads queues + */ +/** + * @brief Data part of a static threads queue object initializer. + * @details This macro should be used when statically initializing a threads + * queue that is part of a bigger structure. + * + * @param[in] name the name of the threads queue variable + */ +#define _THREADS_QUEUE_DATA(name) {(cnt_t)0} + +/** + * @brief Static threads queue object initializer. + * @details Statically initialized threads queues require no explicit + * initialization using @p queue_init(). + * + * @param[in] name the name of the threads queue variable + */ +#define _THREADS_QUEUE_DECL(name) \ + threads_queue_t name = _THREADS_QUEUE_DATA(name) +/** @} */ + /** * @name Semaphores macros * @{ @@ -1367,6 +1393,7 @@ extern "C" { void chThdResumeI(thread_reference_t *trp, msg_t msg); void chThdSleep(systime_t timeout); void chThdSleepUntil(systime_t abstime); + msg_t chThdEnqueueTimeoutS(threads_queue_t *tqp, systime_t timeout); void chThdDoDequeueNextI(threads_queue_t *tqp, msg_t msg); void chThdDequeueNextI(threads_queue_t *tqp, msg_t msg); void chThdDequeueAllI(threads_queue_t *tqp, msg_t msg); diff --git a/os/nil/src/ch.c b/os/nil/src/ch.c index faf725164..db811f7b2 100644 --- a/os/nil/src/ch.c +++ b/os/nil/src/ch.c @@ -757,6 +757,45 @@ void chThdSleepUntil(systime_t abstime) { chSysUnlock(); } +/** + * @brief Enqueues the caller thread on a threads queue object. + * @details The caller thread is enqueued and put to sleep until it is + * dequeued or the specified timeouts expires. + * + * @param[in] tqp pointer to the threads queue object + * @param[in] timeout the timeout in system ticks, the special values are + * handled as follow: + * - @a TIME_INFINITE the thread enters an infinite sleep + * state. + * - @a TIME_IMMEDIATE the thread is not enqueued and + * the function returns @p MSG_TIMEOUT as if a timeout + * occurred. + * . + * @return The message from @p osalQueueWakeupOneI() or + * @p osalQueueWakeupAllI() functions. + * @retval MSG_TIMEOUT if the thread has not been dequeued within the + * specified timeout or if the function has been + * invoked with @p TIME_IMMEDIATE as timeout + * specification. + * + * @sclass + */ +msg_t chThdEnqueueTimeoutS(threads_queue_t *tqp, systime_t timeout) { + + chDbgCheckClassS(); + chDbgCheck(tqp != NULL); + + chDbgAssert(tqp->cnt <= (cnt_t)0, "invalid counter"); + + if (TIME_IMMEDIATE == timeout) { + return MSG_TIMEOUT; + } + + tqp->cnt--; + nil.current->u1.tqp = tqp; + return chSchGoSleepTimeoutS(NIL_STATE_WTQUEUE, timeout); +} + /** * @brief Dequeues and wakes up one thread from the threads queue object. * @details Dequeues one thread from the queue without checking if the queue @@ -769,23 +808,23 @@ void chThdSleepUntil(systime_t abstime) { * @iclass */ void chThdDoDequeueNextI(threads_queue_t *tqp, msg_t msg) { - thread_reference_t tr = nil.threads; + thread_t *tp = nil.threads; - chDbgAssert(tqp->cnt > (cnt_t)0, "empty queue"); + chDbgAssert(tqp->cnt < (cnt_t)0, "empty queue"); while (true) { /* Is this thread waiting on this queue?*/ - if (tr->u1.tqp == tqp) { + if (tp->u1.tqp == tqp) { tqp->cnt++; - chDbgAssert(NIL_THD_IS_WTQUEUE(tr), "not waiting"); + chDbgAssert(NIL_THD_IS_WTQUEUE(tp), "not waiting"); - (void) chSchReadyI(tr, msg); + (void) chSchReadyI(tp, msg); return; } - tr++; + tp++; - chDbgAssert(tr < &nil.threads[CH_CFG_NUM_THREADS], + chDbgAssert(tp < &nil.threads[CH_CFG_NUM_THREADS], "pointer out of range"); } } @@ -804,7 +843,7 @@ void chThdDequeueNextI(threads_queue_t *tqp, msg_t msg) { chDbgCheckClassI(); chDbgCheck(tqp != NULL); - if (tqp->cnt <= (cnt_t)0) { + if (tqp->cnt < (cnt_t)0) { chThdDoDequeueNextI(tqp, msg); } } @@ -903,7 +942,7 @@ msg_t chSemWaitTimeoutS(semaphore_t *sp, systime_t timeout) { return MSG_TIMEOUT; } sp->cnt = cnt - (cnt_t)1; - nil.current->u1.tqp = (threads_queue_t *)sp; + nil.current->u1.semp = sp; return chSchGoSleepTimeoutS(NIL_STATE_WTQUEUE, timeout); } sp->cnt = cnt - (cnt_t)1; @@ -942,7 +981,21 @@ void chSemSignalI(semaphore_t *sp) { chDbgCheck(sp != NULL); if (++sp->cnt <= (cnt_t)0) { - chThdDoDequeueNextI((threads_queue_t *)sp, MSG_OK); + thread_t *tp = nil.threads; + while (true) { + /* Is this thread waiting on this semaphore?*/ + if (tp->u1.semp == sp) { + + chDbgAssert(NIL_THD_IS_WTQUEUE(tp), "not waiting"); + + (void) chSchReadyI(tp, MSG_OK); + return; + } + tp++; + + chDbgAssert(tp < &nil.threads[CH_CFG_NUM_THREADS], + "pointer out of range"); + } } } @@ -998,7 +1051,7 @@ void chSemResetI(semaphore_t *sp, cnt_t n) { "pointer out of range"); /* Is this thread waiting on this semaphore?*/ - if (tp->u1.tqp == (threads_queue_t *)sp) { + if (tp->u1.semp == sp) { chDbgAssert(NIL_THD_IS_WTQUEUE(tp), "not waiting"); diff --git a/release_note_next.txt b/release_note_next.txt index 78a5905d2..aee19b04a 100644 --- a/release_note_next.txt +++ b/release_note_next.txt @@ -65,6 +65,8 @@ a series of important improvements, new features have been added. - Now uses the common ports architecture. - Now uses the new shared RTOS components. +- Added implementation of thread queues directly in the kernel, removed it + from NIL OSAL. - All new features are optional so there is no code size increase. - Enhanced source-level compatibility with RT. - Enhanced debug features.