Enhanced dynamic support.

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@8948 35acf78f-673a-0410-8e92-d51de3d6d3f4
master
Giovanni Di Sirio 2016-02-26 09:40:45 +00:00
parent 3e6e47ee7d
commit c2a407c4d5
6 changed files with 218 additions and 204 deletions

View File

@ -49,6 +49,10 @@
#error "CH_CFG_USE_DYNAMIC requires CH_CFG_USE_WAITEXIT" #error "CH_CFG_USE_DYNAMIC requires CH_CFG_USE_WAITEXIT"
#endif #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) #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" #error "CH_CFG_USE_DYNAMIC requires CH_CFG_USE_HEAP and/or CH_CFG_USE_MEMPOOLS"
#endif #endif
@ -71,8 +75,6 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
thread_t *chThdAddRef(thread_t *tp);
void chThdRelease(thread_t *tp);
#if CH_CFG_USE_HEAP == TRUE #if CH_CFG_USE_HEAP == TRUE
thread_t *chThdCreateFromHeap(memory_heap_t *heapp, size_t size, thread_t *chThdCreateFromHeap(memory_heap_t *heapp, size_t size,
const char *name, tprio_t prio, const char *name, tprio_t prio,

View File

@ -235,7 +235,7 @@ struct ch_thread {
* @brief Various thread flags. * @brief Various thread flags.
*/ */
tmode_t 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. * @brief References to this thread.
*/ */

View File

@ -181,6 +181,13 @@ extern "C" {
thread_t *chThdCreateStatic(void *wsp, size_t size, thread_t *chThdCreateStatic(void *wsp, size_t size,
tprio_t prio, tfunc_t pf, void *arg); tprio_t prio, tfunc_t pf, void *arg);
thread_t *chThdStart(thread_t *tp); 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); tprio_t chThdSetPriority(tprio_t newprio);
void chThdTerminate(thread_t *tp); void chThdTerminate(thread_t *tp);
msg_t chThdSuspendS(thread_reference_t *trp); msg_t chThdSuspendS(thread_reference_t *trp);
@ -195,11 +202,6 @@ extern "C" {
void chThdSleepUntil(systime_t time); void chThdSleepUntil(systime_t time);
systime_t chThdSleepUntilWindowed(systime_t prev, systime_t next); systime_t chThdSleepUntilWindowed(systime_t prev, systime_t next);
void chThdYield(void); 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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -54,78 +54,6 @@
/* Module exported functions. */ /* 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 <b>and</b> 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__) #if (CH_CFG_USE_HEAP == TRUE) || defined(__DOXYGEN__)
/** /**
* @brief Creates a new thread allocating the memory from the heap. * @brief Creates a new thread allocating the memory from the heap.

View File

@ -103,10 +103,8 @@ thread_t *_thread_init(thread_t *tp, const char *name, tprio_t prio) {
#if CH_DBG_THREADS_PROFILING == TRUE #if CH_DBG_THREADS_PROFILING == TRUE
tp->time = (systime_t)0; tp->time = (systime_t)0;
#endif #endif
#if CH_CFG_USE_DYNAMIC == TRUE
tp->refs = (trefs_t)1;
#endif
#if CH_CFG_USE_REGISTRY == TRUE #if CH_CFG_USE_REGISTRY == TRUE
tp->refs = (trefs_t)1;
tp->name = name; tp->name = name;
REG_INSERT(tp); REG_INSERT(tp);
#endif #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. * @brief Creates a new thread into a static memory area.
* @details The new thread is initialized but not inserted in the ready list, * @details The new thread is initialized but not inserted in the ready list,
* the initial state is @p CH_STATE_WTSTART. * 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 * @post The initialized thread can be subsequently started by invoking
* @p chThdStart(), @p chThdStartI() or @p chSchWakeupS() * @p chThdStart(), @p chThdStartI() or @p chSchWakeupS()
* depending on the execution context. * 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. * @brief Creates a new thread into a static memory area.
* @details The new thread is initialized but not inserted in the ready list, * @details The new thread is initialized but not inserted in the ready list,
* the initial state is @p CH_STATE_WTSTART. * 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 * @post The initialized thread can be subsequently started by invoking
* @p chThdStart(), @p chThdStartI() or @p chSchWakeupS() * @p chThdStart(), @p chThdStartI() or @p chSchWakeupS()
* depending on the execution context. * 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. * @brief Creates a new thread into a static memory area.
* @details The new thread is initialized and make ready to execute. * @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 * @post The initialized thread can be subsequently started by invoking
* @p chThdStart(), @p chThdStartI() or @p chSchWakeupS() * @p chThdStart(), @p chThdStartI() or @p chSchWakeupS()
* depending on the execution context. * 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. * @brief Creates a new thread into a static memory area.
* @details The new thread is initialized and make ready to execute. * @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 * @note A thread can terminate by calling @p chThdExit() or by simply
* returning from its main function. * 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. * @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 * @note A thread can terminate by calling @p chThdExit() or by simply
* returning from its main function. * returning from its main function.
* *
@ -346,6 +364,186 @@ thread_t *chThdStart(thread_t *tp) {
return 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 <b>and</b> 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.<br>
* 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 * @brief Changes the running thread priority level then reschedules if
* necessary. * necessary.
@ -482,124 +680,6 @@ void chThdYield(void) {
chSysUnlock(); 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.<br>
* 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. * @brief Sends the current thread sleeping and sets a reference variable.
* @note This function must reschedule, it can only be called from thread * @note This function must reschedule, it can only be called from thread

View File

@ -24,12 +24,14 @@ a series of important new features.
- Common ports architecture. - Common ports architecture.
- Ability to use the new shared RTOS components. - 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 - 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 but also IRQs, halts and user events. The trace record now stores both the
"slow" system time and a RT stamp for increased accuracy. "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. - New kernel hooks for a more flexible code instrumentation.
- Experimental NASA OSAL implementation. - Experimental NASA OSAL implementation.