aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/Doxyfile2
-rw-r--r--os/kernel/include/ch.h4
-rw-r--r--os/kernel/include/inline.h13
-rw-r--r--os/kernel/include/lists.h29
-rw-r--r--os/kernel/include/threads.h11
-rw-r--r--os/kernel/src/chlists.c28
-rw-r--r--os/kernel/src/chthreads.c122
-rw-r--r--os/kernel/templates/chtypes.h5
-rw-r--r--os/ports/GCC/ARMCM3/chtypes.h19
-rw-r--r--os/ports/GCC/AVR/chcore.c16
-rw-r--r--readme.txt9
-rw-r--r--todo.txt2
12 files changed, 191 insertions, 69 deletions
diff --git a/docs/Doxyfile b/docs/Doxyfile
index 24c925847..e0546572b 100644
--- a/docs/Doxyfile
+++ b/docs/Doxyfile
@@ -31,7 +31,7 @@ PROJECT_NAME = ChibiOS/RT
# This could be handy for archiving the generated documentation or
# if some version control system is used.
-PROJECT_NUMBER = 1.5.0
+PROJECT_NUMBER = 1.5.1
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
diff --git a/os/kernel/include/ch.h b/os/kernel/include/ch.h
index 4e35936ae..683c69cc6 100644
--- a/os/kernel/include/ch.h
+++ b/os/kernel/include/ch.h
@@ -35,7 +35,7 @@
/**
* Kernel version string.
*/
-#define CH_KERNEL_VERSION "1.5.0unstable"
+#define CH_KERNEL_VERSION "1.5.1unstable"
/**
* Kernel version major number.
@@ -50,7 +50,7 @@
/**
* Kernel version patch number.
*/
-#define CH_KERNEL_PATCH 0
+#define CH_KERNEL_PATCH 1
/*
* Common values.
diff --git a/os/kernel/include/inline.h b/os/kernel/include/inline.h
index dbac5d553..6f6734893 100644
--- a/os/kernel/include/inline.h
+++ b/os/kernel/include/inline.h
@@ -67,6 +67,19 @@ static INLINE Thread *dequeue(Thread *tp) {
tp->p_next->p_prev = tp->p_prev;
return tp;
}
+
+static INLINE void list_insert(Thread *tp, ThreadsList *tlp) {
+
+ tp->p_next = tlp->p_next;
+ tlp->p_next = tp;
+}
+
+static INLINE Thread *list_remove(ThreadsList *tlp) {
+
+ Thread *tp = tlp->p_next;
+ tlp->p_next = tp->p_next;
+ return tp;
+}
#endif /* CH_OPTIMIZE_SPEED */
#endif /* _INLINE_H_ */
diff --git a/os/kernel/include/lists.h b/os/kernel/include/lists.h
index 2ef0429ff..13d498939 100644
--- a/os/kernel/include/lists.h
+++ b/os/kernel/include/lists.h
@@ -30,17 +30,24 @@
typedef struct Thread Thread;
/**
- * Threads queue initialization.
+ * @brief Threads queue initialization.
*/
#define queue_init(tqp) ((tqp)->p_next = (tqp)->p_prev = (Thread *)(tqp));
/**
- * Macro evaluating to @p TRUE if the specified threads queue is empty.
+ * @brief Threads list initialization.
+ */
+#define list_init(tlp) ((tlp)->p_next = (Thread *)(tlp))
+
+/**
+ * @brief Evaluates to @p TRUE if the specified threads queue or list is
+ * empty.
*/
#define isempty(p) ((p)->p_next == (Thread *)(p))
/**
- * Macro evaluating to @p TRUE if the specified threads queue is not empty.
+ * @brief Evaluates to @p TRUE if the specified threads queue or list is
+ * not empty.
*/
#define notempty(p) ((p)->p_next != (Thread *)(p))
@@ -66,11 +73,21 @@ typedef struct Thread Thread;
*/
typedef struct {
Thread *p_next; /**< First @p Thread in the queue, or
- @p ThreadQueue when empty.*/
+ @p ThreadQueue when empty. */
Thread *p_prev; /**< Last @p Thread in the queue, or
- @p ThreadQueue when empty.*/
+ @p ThreadQueue when empty. */
} ThreadsQueue;
+/**
+ * @brief Generic threads single link list, it works like a stack.
+ */
+typedef struct {
+
+ Thread *p_next; /**< Last pushed @p Thread on the stack
+ list, or pointer to itself if
+ empty. */
+} ThreadsList;
+
#if !CH_OPTIMIZE_SPEED
#ifdef __cplusplus
@@ -81,6 +98,8 @@ extern "C" {
Thread *fifo_remove(ThreadsQueue *tqp);
Thread *lifo_remove(ThreadsQueue *tqp);
Thread *dequeue(Thread *tp);
+ void list_insert(Thread *tp, ThreadsList *tlp);
+ Thread *list_remove(ThreadsList *tlp);
#ifdef __cplusplus
}
#endif
diff --git a/os/kernel/include/threads.h b/os/kernel/include/threads.h
index f94beac32..a9209e6ea 100644
--- a/os/kernel/include/threads.h
+++ b/os/kernel/include/threads.h
@@ -54,6 +54,9 @@ struct Thread {
/* End of the fields shared with the ThreadsQueue structure. */
tprio_t p_prio; /**< Thread priority. */
/* End of the fields shared with the ReadyList structure. */
+#if CH_USE_DYNAMIC
+ trefs_t p_refs; /**< References to this thread. */
+#endif
tstate_t p_state; /**< Current thread state. */
tmode_t p_flags; /**< Various thread flags. */
struct context p_ctx; /**< Processor context. */
@@ -61,7 +64,7 @@ struct Thread {
cnt_t p_locks; /**< Number of nested locks. */
#endif
#if CH_DBG_THREADS_PROFILING
- volatile systime_t p_time; /**< Thread consumed time in ticks.
+ volatile systime_t p_time; /**< Thread consumed time in ticks.
@note This field can overflow. */
#endif
union {
@@ -76,7 +79,7 @@ struct Thread {
#endif
} p_u; /**< State-specific fields. */
#if CH_USE_WAITEXIT
- Thread *p_waiting; /**< Thread waiting for termination.*/
+ ThreadsList p_waiting; /**< Termination waiting list. */
#endif
#if CH_USE_MESSAGES
ThreadsQueue p_msgqueue; /**< Messages queue. */
@@ -167,6 +170,10 @@ extern "C" {
void chThdSleepUntil(systime_t time);
void chThdYield(void);
void chThdExit(msg_t msg);
+#if CH_USE_DYNAMIC
+ Thread *chThdAddRef(Thread *tp);
+ Thread *chThdRelease(Thread *tp);
+#endif
#if CH_USE_WAITEXIT
msg_t chThdWait(Thread *tp);
#endif
diff --git a/os/kernel/src/chlists.c b/os/kernel/src/chlists.c
index 4b87105bc..53f91649a 100644
--- a/os/kernel/src/chlists.c
+++ b/os/kernel/src/chlists.c
@@ -110,6 +110,34 @@ Thread *dequeue(Thread *tp) {
tp->p_next->p_prev = tp->p_prev;
return tp;
}
+
+/**
+ * @brief Pushes a Thread on top of a stack list.
+ * @note This function is @b not an API.
+ *
+ * @param[in] tp the pointer to the thread to be inserted in the list
+ * @param[in] tlp the pointer to the threads list header
+ */
+void list_insert(Thread *tp, ThreadsList *tlp) {
+
+ tp->p_next = tlp->p_next;
+ tlp->p_next = tp;
+}
+
+/**
+ * @brief Pops a Thread from the top of a stack list and returns it.
+ * @note The list must be non-empty before calling this function.
+ * @note This function is @b not an API.
+ *
+ * @param[in] tlp the pointer to the threads list header
+ * @return The removed thread pointer.
+ */
+Thread *list_remove(ThreadsList *tlp) {
+
+ Thread *tp = tlp->p_next;
+ tlp->p_next = tp->p_next;
+ return tp;
+}
#endif /* CH_OPTIMIZE_SPEED */
/** @} */
diff --git a/os/kernel/src/chthreads.c b/os/kernel/src/chthreads.c
index 6aab8f891..26183706a 100644
--- a/os/kernel/src/chthreads.c
+++ b/os/kernel/src/chthreads.c
@@ -26,14 +26,17 @@
#include "ch.h"
-/*
- * Initializes a thread structure.
+/**
+ * @brief Initializes a thread structure.
*/
Thread *init_thread(Thread *tp, tprio_t prio) {
tp->p_flags = THD_MEM_MODE_STATIC;
tp->p_prio = prio;
tp->p_state = THD_STATE_SUSPENDED;
+#if CH_USE_DYNAMIC
+ tp->p_refs = 1;
+#endif
#if CH_USE_NESTED_LOCKS
tp->p_locks = 0;
#endif
@@ -41,12 +44,11 @@ Thread *init_thread(Thread *tp, tprio_t prio) {
tp->p_time = 0;
#endif
#if CH_USE_MUTEXES
- /* realprio is the thread's own, non-inherited, priority */
tp->p_realprio = prio;
tp->p_mtxlist = NULL;
#endif
#if CH_USE_WAITEXIT
- tp->p_waiting = NULL;
+ list_init(&tp->p_waiting);
#endif
#if CH_USE_MESSAGES
queue_init(&tp->p_msgqueue);
@@ -120,7 +122,7 @@ Thread *chThdCreateStatic(void *wsp, size_t size,
return chThdResume(chThdInit(wsp, size, prio, pf, arg));
}
-#if CH_USE_DYNAMIC && CH_USE_WAITEXIT && CH_USE_HEAP
+#if CH_USE_DYNAMIC && CH_USE_HEAP
/**
* @brief Creates a new thread allocating the memory from the heap.
*
@@ -153,9 +155,9 @@ Thread *chThdCreateFromHeap(MemoryHeap *heapp, size_t size,
tp->p_flags = THD_MEM_MODE_HEAP;
return chThdResume(tp);
}
-#endif /* CH_USE_DYNAMIC && CH_USE_WAITEXIT && CH_USE_HEAP */
+#endif /* CH_USE_DYNAMIC && CH_USE_HEAP */
-#if CH_USE_DYNAMIC && CH_USE_WAITEXIT && CH_USE_MEMPOOLS
+#if CH_USE_DYNAMIC && CH_USE_MEMPOOLS
/**
* @brief Creates a new thread allocating the memory from the specified Memory
* Pool.
@@ -191,7 +193,7 @@ Thread *chThdCreateFromMemoryPool(MemoryPool *mp, tprio_t prio,
tp->p_mpool = mp;
return chThdResume(tp);
}
-#endif /* CH_USE_DYNAMIC && CH_USE_WAITEXIT && CH_USE_MEMPOOLS */
+#endif /* CH_USE_DYNAMIC && CH_USE_MEMPOOLS */
/**
* @brief Changes the running thread priority level then reschedules if
@@ -310,6 +312,7 @@ void chThdYield(void) {
*
* @param[in] msg the thread exit code. The code can be retrieved by using
* @p chThdWait().
+ * @return The same thread pointer passed as parameter.
*/
void chThdExit(msg_t msg) {
Thread *tp = currp;
@@ -318,17 +321,67 @@ void chThdExit(msg_t msg) {
tp->p_u.exitcode = msg;
THREAD_EXT_EXIT(tp);
#if CH_USE_WAITEXIT
- if (tp->p_waiting != NULL)
- chSchReadyI(tp->p_waiting);
+ while (notempty(&tp->p_waiting))
+ chSchReadyI(list_remove(&tp->p_waiting));
#endif
chSchGoSleepS(THD_STATE_FINAL);
}
-#if CH_USE_WAITEXIT
+#if CH_USE_DYNAMIC || defined(__DOXYGEN__)
+Thread *chThdAddRef(Thread *tp) {
+
+ chSysLock();
+ chDbgAssert(tp->p_refs < 255, "chThdAddRef(), #1", "too many references");
+ tp->p_refs++;
+ chSysUnlock();
+ return tp;
+}
/**
- * @brief Blocks the execution of the invoking thread until the specified
- * thread terminates then the exit code is returned.
- * @details The memory used by the exited thread is handled in different ways
+ * @brief Releases a reference to a thread object.
+ * @details If the references counter reaches zero and the thread is in
+ * @p THD_STATE_FINAL state then the thread's memory is returned
+ * to the proper allocator.
+ * @note Static threads are not affected.
+ *
+ * @param[in] tp the thread pointer
+ * @return The same thread pointer passed as parameter.
+ */
+Thread *chThdRelease(Thread *tp) {
+ trefs_t refs;
+
+ chSysLock();
+ chDbgAssert(tp->p_refs > 0, "chThdRelease(), #1", "not referenced");
+ refs = --tp->p_refs;
+ chSysUnlock();
+
+ /* If the references counter reaches zero then the memory can be returned
+ to the proper allocator. Of course static threads are not affected.*/
+ if (refs == 0) {
+ switch (tp->p_flags & THD_MEM_MODE_MASK) {
+#if CH_USE_HEAP
+ case THD_MEM_MODE_HEAP:
+ chHeapFree(tp);
+ break;
+#endif
+#if CH_USE_MEMPOOLS
+ case THD_MEM_MODE_MEMPOOL:
+ chPoolFree(tp->p_mpool, tp);
+ break;
+#endif
+ }
+ }
+ return tp;
+}
+#endif /* CH_USE_DYNAMIC */
+
+#if CH_USE_WAITEXIT || 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 that the specified thread terminates 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 chThdInit() then nothing happens and the thread working area
@@ -339,61 +392,34 @@ void chThdExit(msg_t msg) {
* - If the thread was spawned by @p chThdCreateFromMemoryPool()
* then the working area is returned to the owning memory pool.
* .
+ * Please read the @ref article_lifecycle article for more details.
* @param[in] tp the thread pointer
* @return The exit code from the terminated thread
* @note After invoking @p chThdWait() the thread pointer becomes invalid and
* must not be used as parameter for further system calls.
* @note The function is available only if the @p CH_USE_WAITEXIT
* option is enabled in @p chconf.h.
- * @note Only one thread can be waiting for another thread at any time. You
- * should imagine the threads as having a reference counter that is set
- * to one when the thread is created, chThdWait() decreases the reference
- * and the memory is freed when the counter reaches zero. In the current
- * implementation there is no real reference counter in the thread
- * structure but it is a planned extension.
+ * @note If @p CH_USE_DYNAMIC is not specified this function just waits for
+ * the thread termination, no memory allocators are involved.
*/
msg_t chThdWait(Thread *tp) {
msg_t msg;
-#if CH_USE_DYNAMIC
- tmode_t mode;
-#endif
chDbgCheck(tp != NULL, "chThdWait");
chSysLock();
-
chDbgAssert(tp != currp, "chThdWait(), #1", "waiting self");
- chDbgAssert(tp->p_waiting == NULL, "chThdWait(), #2",
- "some other thread waiting");
-
+ chDbgAssert(tp->p_refs > 0, "chThdWait(), #2", "not referenced");
if (tp->p_state != THD_STATE_FINAL) {
- tp->p_waiting = currp;
+ list_insert(currp, &tp->p_waiting);
chSchGoSleepS(THD_STATE_WTEXIT);
}
msg = tp->p_u.exitcode;
-#if !CH_USE_DYNAMIC
chSysUnlock();
- return msg;
-#else /* CH_USE_DYNAMIC */
-
- /* Returning memory.*/
- mode = tp->p_flags & THD_MEM_MODE_MASK;
- chSysUnlock();
-
- switch (mode) {
-#if CH_USE_HEAP
- case THD_MEM_MODE_HEAP:
- chHeapFree(tp);
- break;
-#endif
-#if CH_USE_MEMPOOLS
- case THD_MEM_MODE_MEMPOOL:
- chPoolFree(tp->p_mpool, tp);
- break;
+#if CH_USE_DYNAMIC
+ chThdRelease(tp);
#endif
- }
return msg;
-#endif /* CH_USE_DYNAMIC */
}
#endif /* CH_USE_WAITEXIT */
diff --git a/os/kernel/templates/chtypes.h b/os/kernel/templates/chtypes.h
index 2a8e27a59..362e1d291 100644
--- a/os/kernel/templates/chtypes.h
+++ b/os/kernel/templates/chtypes.h
@@ -35,7 +35,7 @@
#include <stdint.h>
#endif
-/** Signed boolean. */
+/** Boolean, recommended the fastest signed. */
typedef int32_t bool_t;
/** Thread mode flags, uint8_t is ok. */
@@ -44,6 +44,9 @@ typedef uint8_t tmode_t;
/** Thread state, uint8_t is ok. */
typedef uint8_t tstate_t;
+/** Thread references counter, uint8_t is ok. */
+typedef uint8_t trefs_t;
+
/** Priority, use the fastest unsigned type. */
typedef uint32_t tprio_t;
diff --git a/os/ports/GCC/ARMCM3/chtypes.h b/os/ports/GCC/ARMCM3/chtypes.h
index 4865002f3..1a854d209 100644
--- a/os/ports/GCC/ARMCM3/chtypes.h
+++ b/os/ports/GCC/ARMCM3/chtypes.h
@@ -36,15 +36,16 @@
#include <stdint.h>
#endif
-typedef int32_t bool_t; /**< Fast boolean type. */
-typedef uint8_t tmode_t; /**< Thread flags. */
-typedef uint8_t tstate_t; /**< Thread state. */
-typedef uint32_t tprio_t; /**< Thread priority. */
-typedef int32_t msg_t; /**< Inter-thread message. */
-typedef int32_t eventid_t; /**< Event Id. */
-typedef uint32_t eventmask_t; /**< Events mask. */
-typedef uint32_t systime_t; /**< System time. */
-typedef int32_t cnt_t; /**< Resources counter. */
+typedef int32_t bool_t; /**< Fast boolean type. */
+typedef uint8_t tmode_t; /**< Thread flags. */
+typedef uint8_t tstate_t; /**< Thread state. */
+typedef uint8_t trefs_t; /**< Thread references counter. */
+typedef uint32_t tprio_t; /**< Thread priority. */
+typedef int32_t msg_t; /**< Inter-thread message. */
+typedef int32_t eventid_t; /**< Event Id. */
+typedef uint32_t eventmask_t; /**< Events mask. */
+typedef uint32_t systime_t; /**< System time. */
+typedef int32_t cnt_t; /**< Resources counter. */
#define INLINE inline
#define PACK_STRUCT_STRUCT __attribute__((packed))
diff --git a/os/ports/GCC/AVR/chcore.c b/os/ports/GCC/AVR/chcore.c
index e4f12b088..e99c2b970 100644
--- a/os/ports/GCC/AVR/chcore.c
+++ b/os/ports/GCC/AVR/chcore.c
@@ -59,6 +59,21 @@ void port_switch(Thread *otp, Thread *ntp) {
asm volatile ("push r28");
asm volatile ("push r29");
+ /* This is required because the context offset changes if CH_USE_DYNAMIC
+ is activated.*/
+#if CH_USE_DYNAMIC
+ asm volatile ("movw r30, r24");
+ asm volatile ("in r0, 0x3d");
+ asm volatile ("std Z+8, r0");
+ asm volatile ("in r0, 0x3e");
+ asm volatile ("std Z+9, r0");
+
+ asm volatile ("movw r30, r22");
+ asm volatile ("ldd r0, Z+8");
+ asm volatile ("out 0x3d, r0");
+ asm volatile ("ldd r0, Z+9");
+ asm volatile ("out 0x3e, r0");
+#else /* !CH_USE_DYNAMIC */
asm volatile ("movw r30, r24");
asm volatile ("in r0, 0x3d");
asm volatile ("std Z+7, r0");
@@ -70,6 +85,7 @@ void port_switch(Thread *otp, Thread *ntp) {
asm volatile ("out 0x3d, r0");
asm volatile ("ldd r0, Z+8");
asm volatile ("out 0x3e, r0");
+#endif /* !CH_USE_DYNAMIC */
asm volatile ("pop r29");
asm volatile ("pop r28");
diff --git a/readme.txt b/readme.txt
index 9c17eeeb5..d97427fa0 100644
--- a/readme.txt
+++ b/readme.txt
@@ -51,6 +51,15 @@
*** Releases ***
*****************************************************************************
+*** 1.5.1 ***
+- NEW: Implemented the concept of thread references, this mechanism ensures
+ that a dynamic thread's memory is not freed while some other thread still
+ owns a pointer to the thread. Static threads are not affected by the new
+ mechanism. Two new APIs have been added: chThdAddRef() and chThdRelease().
+- NEW: Not more than one thread can be waiting in chThdWait(), this
+ capability was already present in beta versions before 0.8.0 but removed
+ because at the time there was not the references mechanism in place.
+
*** 1.5.0 ***
- FIX: Fixed missing dependencies check for CH_USE_DYNAMIC (bug 2942757)
(backported in 1.4.1).
diff --git a/todo.txt b/todo.txt
index 2733b634e..bc1430f4d 100644
--- a/todo.txt
+++ b/todo.txt
@@ -6,7 +6,7 @@ X = In progress, some work done.
Before 1.6.0:
* Remove instances of unnamed structures/unions.
-- Reference counter for threads, concept of detached threads, threads
+* Reference counter for threads, concept of detached threads, threads
management.
- Active threads registry in the kernel.
- Debug-related features and tools.