diff --git a/os/rt/include/chdynamic.h b/os/rt/include/chdynamic.h index 9b653cc5c..b42a6d34e 100644 --- a/os/rt/include/chdynamic.h +++ b/os/rt/include/chdynamic.h @@ -49,6 +49,10 @@ #error "CH_CFG_USE_DYNAMIC requires CH_CFG_USE_WAITEXIT" #endif +#if CH_CFG_USE_REGISTRY == FALSE +#error "CH_CFG_USE_DYNAMIC requires CH_CFG_USE_REGISTRY" +#endif + #if (CH_CFG_USE_HEAP == FALSE) && (CH_CFG_USE_MEMPOOLS == FALSE) #error "CH_CFG_USE_DYNAMIC requires CH_CFG_USE_HEAP and/or CH_CFG_USE_MEMPOOLS" #endif @@ -71,8 +75,6 @@ #ifdef __cplusplus extern "C" { #endif - thread_t *chThdAddRef(thread_t *tp); - void chThdRelease(thread_t *tp); #if CH_CFG_USE_HEAP == TRUE thread_t *chThdCreateFromHeap(memory_heap_t *heapp, size_t size, const char *name, tprio_t prio, diff --git a/os/rt/include/chschd.h b/os/rt/include/chschd.h index ca48afe75..6af0cdedb 100644 --- a/os/rt/include/chschd.h +++ b/os/rt/include/chschd.h @@ -235,7 +235,7 @@ struct ch_thread { * @brief Various thread flags. */ tmode_t flags; -#if (CH_CFG_USE_DYNAMIC == TRUE) || defined(__DOXYGEN__) +#if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__) /** * @brief References to this thread. */ diff --git a/os/rt/include/chthreads.h b/os/rt/include/chthreads.h index d4f2a68d0..2832051e9 100644 --- a/os/rt/include/chthreads.h +++ b/os/rt/include/chthreads.h @@ -181,6 +181,13 @@ extern "C" { thread_t *chThdCreateStatic(void *wsp, size_t size, tprio_t prio, tfunc_t pf, void *arg); thread_t *chThdStart(thread_t *tp); + thread_t *chThdAddRef(thread_t *tp); + void chThdRelease(thread_t *tp); + void chThdExit(msg_t msg); + void chThdExitS(msg_t msg); +#if CH_CFG_USE_WAITEXIT == TRUE + msg_t chThdWait(thread_t *tp); +#endif tprio_t chThdSetPriority(tprio_t newprio); void chThdTerminate(thread_t *tp); msg_t chThdSuspendS(thread_reference_t *trp); @@ -195,11 +202,6 @@ extern "C" { void chThdSleepUntil(systime_t time); systime_t chThdSleepUntilWindowed(systime_t prev, systime_t next); void chThdYield(void); - void chThdExit(msg_t msg); - void chThdExitS(msg_t msg); -#if CH_CFG_USE_WAITEXIT == TRUE - msg_t chThdWait(thread_t *tp); -#endif #ifdef __cplusplus } #endif diff --git a/os/rt/src/chdynamic.c b/os/rt/src/chdynamic.c index 60b0cbe19..28cebe9c8 100644 --- a/os/rt/src/chdynamic.c +++ b/os/rt/src/chdynamic.c @@ -54,78 +54,6 @@ /* Module exported functions. */ /*===========================================================================*/ -/** - * @brief Adds a reference to a thread object. - * @pre The configuration option @p CH_CFG_USE_DYNAMIC must be enabled in - * order to use this function. - * - * @param[in] tp pointer to the thread - * @return The same thread pointer passed as parameter - * representing the new reference. - * - * @api - */ -thread_t *chThdAddRef(thread_t *tp) { - - chSysLock(); - chDbgAssert(tp->refs < (trefs_t)255, "too many references"); - tp->refs++; - chSysUnlock(); - - return tp; -} - -/** - * @brief Releases a reference to a thread object. - * @details If the references counter reaches zero and the thread - * is in the @p CH_STATE_FINAL state then the thread's memory is - * returned to the proper allocator. - * @pre The configuration option @p CH_CFG_USE_DYNAMIC must be enabled in - * order to use this function. - * @note Static threads are not affected. - * - * @param[in] tp pointer to the thread - * - * @api - */ -void chThdRelease(thread_t *tp) { - trefs_t refs; - - chSysLock(); - chDbgAssert(tp->refs > (trefs_t)0, "not referenced"); - tp->refs--; - refs = tp->refs; - chSysUnlock(); - - /* If the references counter reaches zero and the thread is in its - terminated state then the memory can be returned to the proper - allocator. Of course static threads are not affected.*/ - if ((refs == (trefs_t)0) && (tp->state == CH_STATE_FINAL)) { - switch (tp->flags & CH_FLAG_MODE_MASK) { -#if CH_CFG_USE_HEAP == TRUE - case CH_FLAG_MODE_HEAP: -#if CH_CFG_USE_REGISTRY == TRUE - REG_REMOVE(tp); -#endif - chHeapFree(chthdGetStackLimitX(tp)); - break; -#endif -#if CH_CFG_USE_MEMPOOLS == TRUE - case CH_FLAG_MODE_MPOOL: -#if CH_CFG_USE_REGISTRY == TRUE - REG_REMOVE(tp); -#endif - chPoolFree(tp->mpool, chthdGetStackLimitX(tp)); - break; -#endif - default: - /* Nothing to do for static threads, those are removed from the - registry on exit.*/ - break; - } - } -} - #if (CH_CFG_USE_HEAP == TRUE) || defined(__DOXYGEN__) /** * @brief Creates a new thread allocating the memory from the heap. diff --git a/os/rt/src/chthreads.c b/os/rt/src/chthreads.c index ed5b19e15..e809fbb13 100644 --- a/os/rt/src/chthreads.c +++ b/os/rt/src/chthreads.c @@ -103,10 +103,8 @@ thread_t *_thread_init(thread_t *tp, const char *name, tprio_t prio) { #if CH_DBG_THREADS_PROFILING == TRUE tp->time = (systime_t)0; #endif -#if CH_CFG_USE_DYNAMIC == TRUE - tp->refs = (trefs_t)1; -#endif #if CH_CFG_USE_REGISTRY == TRUE + tp->refs = (trefs_t)1; tp->name = name; REG_INSERT(tp); #endif @@ -145,6 +143,10 @@ void _thread_memfill(uint8_t *startp, uint8_t *endp, uint8_t v) { * @brief Creates a new thread into a static memory area. * @details The new thread is initialized but not inserted in the ready list, * the initial state is @p CH_STATE_WTSTART. + * @post The created thread has a reference counter set to one, it is + * caller responsibility to call @p chThdRelease() or @p chthdWait() + * in order to release the reference. The thread persists in the + * registry until its reference counter reaches zero. * @post The initialized thread can be subsequently started by invoking * @p chThdStart(), @p chThdStartI() or @p chSchWakeupS() * depending on the execution context. @@ -193,6 +195,10 @@ thread_t *chThdCreateSuspendedI(const thread_descriptor_t *tdp) { * @brief Creates a new thread into a static memory area. * @details The new thread is initialized but not inserted in the ready list, * the initial state is @p CH_STATE_WTSTART. + * @post The created thread has a reference counter set to one, it is + * caller responsibility to call @p chThdRelease() or @p chthdWait() + * in order to release the reference. The thread persists in the + * registry until its reference counter reaches zero. * @post The initialized thread can be subsequently started by invoking * @p chThdStart(), @p chThdStartI() or @p chSchWakeupS() * depending on the execution context. @@ -224,6 +230,10 @@ thread_t *chThdCreateSuspended(const thread_descriptor_t *tdp) { /** * @brief Creates a new thread into a static memory area. * @details The new thread is initialized and make ready to execute. + * @post The created thread has a reference counter set to one, it is + * caller responsibility to call @p chThdRelease() or @p chthdWait() + * in order to release the reference. The thread persists in the + * registry until its reference counter reaches zero. * @post The initialized thread can be subsequently started by invoking * @p chThdStart(), @p chThdStartI() or @p chSchWakeupS() * depending on the execution context. @@ -247,6 +257,10 @@ thread_t *chThdCreateI(const thread_descriptor_t *tdp) { /** * @brief Creates a new thread into a static memory area. * @details The new thread is initialized and make ready to execute. + * @post The created thread has a reference counter set to one, it is + * caller responsibility to call @p chThdRelease() or @p chthdWait() + * in order to release the reference. The thread persists in the + * registry until its reference counter reaches zero. * @note A thread can terminate by calling @p chThdExit() or by simply * returning from its main function. * @@ -275,6 +289,10 @@ thread_t *chThdCreate(const thread_descriptor_t *tdp) { /** * @brief Creates a new thread into a static memory area. + * @post The created thread has a reference counter set to one, it is + * caller responsibility to call @p chThdRelease() or @p chthdWait() + * in order to release the reference. The thread persists in the + * registry until its reference counter reaches zero. * @note A thread can terminate by calling @p chThdExit() or by simply * returning from its main function. * @@ -346,6 +364,186 @@ thread_t *chThdStart(thread_t *tp) { return tp; } +/** + * @brief Adds a reference to a thread object. + * @pre The configuration option @p CH_CFG_USE_DYNAMIC must be enabled in + * order to use this function. + * + * @param[in] tp pointer to the thread + * @return The same thread pointer passed as parameter + * representing the new reference. + * + * @api + */ +thread_t *chThdAddRef(thread_t *tp) { + + chSysLock(); + chDbgAssert(tp->refs < (trefs_t)255, "too many references"); + tp->refs++; + chSysUnlock(); + + return tp; +} + +/** + * @brief Releases a reference to a thread object. + * @details If the references counter reaches zero and the thread + * is in the @p CH_STATE_FINAL state then the thread's memory is + * returned to the proper allocator and the thread is removed + * from the registry.
+ * Threads whose counter reaches zero and are still active become + * "detached" and will be removed from registry on termination. + * @pre The configuration option @p CH_CFG_USE_DYNAMIC must be enabled in + * order to use this function. + * @note Static threads are not affected. + * + * @param[in] tp pointer to the thread + * + * @api + */ +void chThdRelease(thread_t *tp) { + + chSysLock(); + chDbgAssert(tp->refs > (trefs_t)0, "not referenced"); + tp->refs--; + + /* If the references counter reaches zero and the thread is in its + terminated state then the memory can be returned to the proper + allocator.*/ + if ((tp->refs == (trefs_t)0) && (tp->state == CH_STATE_FINAL)) { + REG_REMOVE(tp); + chSysUnlock(); + +#if CH_CFG_USE_DYNAMIC == TRUE + switch (tp->flags & CH_FLAG_MODE_MASK) { +#if CH_CFG_USE_HEAP == TRUE + case CH_FLAG_MODE_HEAP: + chHeapFree(chthdGetStackLimitX(tp)); + break; +#endif +#if CH_CFG_USE_MEMPOOLS == TRUE + case CH_FLAG_MODE_MPOOL: + chPoolFree(tp->mpool, chthdGetStackLimitX(tp)); + break; +#endif + default: + /* Nothing else to do for static threads.*/ + break; + } + return; +#endif /* CH_CFG_USE_DYNAMIC == TRUE */ + } + chSysUnlock(); +} + +/** + * @brief Terminates the current thread. + * @details The thread goes in the @p CH_STATE_FINAL state holding the + * specified exit status code, other threads can retrieve the + * exit status code by invoking the function @p chThdWait(). + * @post Eventual code after this function will never be executed, + * this function never returns. The compiler has no way to + * know this so do not assume that the compiler would remove + * the dead code. + * + * @param[in] msg thread exit code + * + * @api + */ +void chThdExit(msg_t msg) { + + chSysLock(); + chThdExitS(msg); + /* The thread never returns here.*/ +} + +/** + * @brief Terminates the current thread. + * @details The thread goes in the @p CH_STATE_FINAL state holding the + * specified exit status code, other threads can retrieve the + * exit status code by invoking the function @p chThdWait(). + * @post Exiting a thread that does not have references (detached) + * causes the thread to remain in the registry. It can only + * be removed by performing a registry scan operation. + * @post Eventual code after this function will never be executed, + * this function never returns. The compiler has no way to + * know this so do not assume that the compiler would remove + * the dead code. + * + * @param[in] msg thread exit code + * + * @sclass + */ +void chThdExitS(msg_t msg) { + thread_t *tp = currp; + + /* Storing exit message.*/ + tp->u.exitcode = msg; + + /* Exit handler hook.*/ + CH_CFG_THREAD_EXIT_HOOK(tp); + +#if CH_CFG_USE_WAITEXIT == TRUE + /* Waking up any waiting thread.*/ + while (list_notempty(&tp->waiting)) { + (void) chSchReadyI(list_remove(&tp->waiting)); + } +#endif + + /* Going into final state.*/ + chSchGoSleepS(CH_STATE_FINAL); + + /* The thread never returns here.*/ + chDbgAssert(false, "zombies apocalypse"); +} + +#if (CH_CFG_USE_WAITEXIT == TRUE) || defined(__DOXYGEN__) +/** + * @brief Blocks the execution of the invoking thread until the specified + * thread terminates then the exit code is returned. + * @details This function waits for the specified thread to terminate then + * decrements its reference counter, if the counter reaches zero then + * the thread working area is returned to the proper allocator and + * the thread is removed from registry. + * @pre The configuration option @p CH_CFG_USE_WAITEXIT must be enabled in + * order to use this function. + * @post Enabling @p chThdWait() requires 2-4 (depending on the + * architecture) extra bytes in the @p thread_t structure. + * @note If @p CH_CFG_USE_DYNAMIC is not specified this function just waits + * for the thread termination, no memory allocators are involved. + * + * @param[in] tp pointer to the thread + * @return The exit code from the terminated thread. + * + * @api + */ +msg_t chThdWait(thread_t *tp) { + msg_t msg; + + chDbgCheck(tp != NULL); + + chSysLock(); + chDbgAssert(tp != currp, "waiting self"); +#if CH_CFG_USE_REGISTRY == TRUE + chDbgAssert(tp->refs > (trefs_t)0, "no references"); +#endif + + if (tp->state != CH_STATE_FINAL) { + list_insert(currp, &tp->waiting); + chSchGoSleepS(CH_STATE_WTEXIT); + } + msg = tp->u.exitcode; + chSysUnlock(); + +#if CH_CFG_USE_REGISTRY == TRUE + /* Releasing a reference to the thread.*/ + chThdRelease(tp); +#endif + + return msg; +} +#endif /* CH_CFG_USE_WAITEXIT */ + /** * @brief Changes the running thread priority level then reschedules if * necessary. @@ -482,124 +680,6 @@ void chThdYield(void) { chSysUnlock(); } -/** - * @brief Terminates the current thread. - * @details The thread goes in the @p CH_STATE_FINAL state holding the - * specified exit status code, other threads can retrieve the - * exit status code by invoking the function @p chThdWait(). - * @post Eventual code after this function will never be executed, - * this function never returns. The compiler has no way to - * know this so do not assume that the compiler would remove - * the dead code. - * - * @param[in] msg thread exit code - * - * @api - */ -void chThdExit(msg_t msg) { - - chSysLock(); - chThdExitS(msg); - /* The thread never returns here.*/ -} - -/** - * @brief Terminates the current thread. - * @details The thread goes in the @p CH_STATE_FINAL state holding the - * specified exit status code, other threads can retrieve the - * exit status code by invoking the function @p chThdWait(). - * @post Eventual code after this function will never be executed, - * this function never returns. The compiler has no way to - * know this so do not assume that the compiler would remove - * the dead code. - * - * @param[in] msg thread exit code - * - * @sclass - */ -void chThdExitS(msg_t msg) { - thread_t *tp = currp; - - tp->u.exitcode = msg; -#if defined(CH_CFG_THREAD_EXIT_HOOK) - CH_CFG_THREAD_EXIT_HOOK(tp); -#endif -#if CH_CFG_USE_WAITEXIT == TRUE - while (list_notempty(&tp->waiting)) { - (void) chSchReadyI(list_remove(&tp->waiting)); - } -#endif -#if CH_CFG_USE_REGISTRY == TRUE - /* Static threads are immediately removed from the registry because - there is no memory to recover.*/ - if ((tp->flags & CH_FLAG_MODE_MASK) == CH_FLAG_MODE_STATIC) { - REG_REMOVE(tp); - } -#endif - chSchGoSleepS(CH_STATE_FINAL); - - /* The thread never returns here.*/ - chDbgAssert(false, "zombies apocalypse"); -} - -#if (CH_CFG_USE_WAITEXIT == TRUE) || defined(__DOXYGEN__) -/** - * @brief Blocks the execution of the invoking thread until the specified - * thread terminates then the exit code is returned. - * @details This function waits for the specified thread to terminate then - * decrements its reference counter, if the counter reaches zero then - * the thread working area is returned to the proper allocator.
- * The memory used by the exited thread is handled in different ways - * depending on the API that spawned the thread: - * - If the thread was spawned by @p chThdCreateStatic() or by - * @p chThdCreateI() then nothing happens and the thread working - * area is not released or modified in any way. This is the - * default, totally static, behavior. - * - If the thread was spawned by @p chThdCreateFromHeap() then - * the working area is returned to the system heap. - * - If the thread was spawned by @p chThdCreateFromMemoryPool() - * then the working area is returned to the owning memory pool. - * . - * @pre The configuration option @p CH_CFG_USE_WAITEXIT must be enabled in - * order to use this function. - * @post Enabling @p chThdWait() requires 2-4 (depending on the - * architecture) extra bytes in the @p thread_t structure. - * @post After invoking @p chThdWait() the thread pointer becomes invalid - * and must not be used as parameter for further system calls. - * @note If @p CH_CFG_USE_DYNAMIC is not specified this function just waits for - * the thread termination, no memory allocators are involved. - * - * @param[in] tp pointer to the thread - * @return The exit code from the terminated thread. - * - * @api - */ -msg_t chThdWait(thread_t *tp) { - msg_t msg; - - chDbgCheck(tp != NULL); - - chSysLock(); - chDbgAssert(tp != currp, "waiting self"); -#if CH_CFG_USE_DYNAMIC == TRUE - chDbgAssert(tp->refs > (trefs_t)0, "not referenced"); -#endif - if (tp->state != CH_STATE_FINAL) { - list_insert(currp, &tp->waiting); - chSchGoSleepS(CH_STATE_WTEXIT); - } - msg = tp->u.exitcode; - chSysUnlock(); - -#if CH_CFG_USE_DYNAMIC == TRUE - /* Releasing a lock if it is a dynamic thread.*/ - chThdRelease(tp); -#endif - - return msg; -} -#endif /* CH_CFG_USE_WAITEXIT */ - /** * @brief Sends the current thread sleeping and sets a reference variable. * @note This function must reschedule, it can only be called from thread diff --git a/release_note_next.txt b/release_note_next.txt index 0bb3bce0c..302fa9cdc 100644 --- a/release_note_next.txt +++ b/release_note_next.txt @@ -24,12 +24,14 @@ a series of important new features. - Common ports architecture. - Ability to use the new shared RTOS components. +- New threading API, now creating static threads is even faster. +- Extended priority range from 1..127 to 1..255. +- Enhanced dynamic threading, safer and easier to use. +- Enhanced Registry, it is now possible to find threads by name, by pointer + or by working area. - Enhanced trace buffer, it is able to store events regarding not just threads but also IRQs, halts and user events. The trace record now stores both the "slow" system time and a RT stamp for increased accuracy. -- Enhanced Registry, it is now possible to find threads by name or by pointer. -- New threading API, now creating static threads is even faster. -- Extended priority range to 1..255. - New kernel hooks for a more flexible code instrumentation. - Experimental NASA OSAL implementation.