aboutsummaryrefslogtreecommitdiffstats
path: root/os/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'os/kernel')
-rw-r--r--os/kernel/include/chdebug.h105
-rw-r--r--os/kernel/include/chschd.h39
-rw-r--r--os/kernel/include/chsys.h88
-rw-r--r--os/kernel/include/chthreads.h6
-rw-r--r--os/kernel/src/chcond.c4
-rw-r--r--os/kernel/src/chdebug.c193
-rw-r--r--os/kernel/src/chevents.c2
-rw-r--r--os/kernel/src/chmboxes.c6
-rw-r--r--os/kernel/src/chmemcore.c2
-rw-r--r--os/kernel/src/chmempools.c2
-rw-r--r--os/kernel/src/chmtx.c4
-rw-r--r--os/kernel/src/chqueues.c8
-rw-r--r--os/kernel/src/chschd.c84
-rw-r--r--os/kernel/src/chsem.c13
-rw-r--r--os/kernel/src/chsys.c24
-rw-r--r--os/kernel/src/chthreads.c2
-rw-r--r--os/kernel/src/chvt.c2
-rw-r--r--os/kernel/templates/chconf.h71
-rw-r--r--os/kernel/templates/chcore.h2
19 files changed, 490 insertions, 167 deletions
diff --git a/os/kernel/include/chdebug.h b/os/kernel/include/chdebug.h
index b2edf176e..f3bf6b026 100644
--- a/os/kernel/include/chdebug.h
+++ b/os/kernel/include/chdebug.h
@@ -29,15 +29,31 @@
#ifndef _CHDEBUG_H_
#define _CHDEBUG_H_
+#if CH_DBG_ENABLE_ASSERTS || CH_DBG_ENABLE_CHECKS || \
+ CH_DBG_ENABLE_STACK_CHECK || CH_DBG_SYSTEM_STATE_CHECK
+#define CH_DBG_ENABLED TRUE
+#else
+#define CH_DBG_ENABLED FALSE
+#endif
+
+#define __QUOTE_THIS(p) #p
+
+/*===========================================================================*/
/**
- * @brief Trace buffer entries.
+ * @name Debug related settings
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief Trace buffer entries.
*/
#ifndef CH_TRACE_BUFFER_SIZE
#define CH_TRACE_BUFFER_SIZE 64
#endif
/**
- * @brief Fill value for thread stack area in debug mode.
+ * @brief Fill value for thread stack area in debug mode.
*/
#ifndef CH_STACK_FILL_VALUE
#define CH_STACK_FILL_VALUE 0x55
@@ -54,11 +70,33 @@
#define CH_THREAD_FILL_VALUE 0xFF
#endif
-#define __QUOTE_THIS(p) #p
+/** @} */
+
+/*===========================================================================*/
+/* System state checker related code and variables. */
+/*===========================================================================*/
+
+#if !CH_DBG_SYSTEM_STATE_CHECK
+#define dbg_check_disable()
+#define dbg_check_suspend()
+#define dbg_check_enable()
+#define dbg_check_lock()
+#define dbg_check_unlock()
+#define dbg_check_lock_from_isr()
+#define dbg_check_unlock_from_isr()
+#define dbg_check_enter_isr()
+#define dbg_check_leave_isr()
+#define chDbgCheckClassI();
+#define chDbgCheckClassS();
+#endif
+
+/*===========================================================================*/
+/* Trace related structures and macros. */
+/*===========================================================================*/
#if CH_DBG_ENABLE_TRACE || defined(__DOXYGEN__)
/**
- * @brief Trace buffer record.
+ * @brief Trace buffer record.
*/
typedef struct {
systime_t se_time; /**< @brief Time of the switch event. */
@@ -68,7 +106,7 @@ typedef struct {
} ch_swc_event_t;
/**
- * @brief Trace buffer header.
+ * @brief Trace buffer header.
*/
typedef struct {
unsigned tb_size; /**< @brief Trace buffer size (entries).*/
@@ -76,9 +114,25 @@ typedef struct {
/** @brief Ring buffer.*/
ch_swc_event_t tb_buffer[CH_TRACE_BUFFER_SIZE];
} ch_trace_buffer_t;
+
+#if !defined(__DOXYGEN__)
+extern ch_trace_buffer_t dbg_trace_buffer;
+#endif
+
#endif /* CH_DBG_ENABLE_TRACE */
+#if !CH_DBG_ENABLE_TRACE
+/* When the trace feature is disabled this function is replaced by an empty
+ macro.*/
+#define dbg_trace(otp)
+#endif
+
+/*===========================================================================*/
+/* Parameters checking related macros. */
+/*===========================================================================*/
+
#if CH_DBG_ENABLE_CHECKS || defined(__DOXYGEN__)
+
/**
* @brief Function parameter check.
* @details If the condition check fails then the kernel panics and halts.
@@ -102,6 +156,10 @@ typedef struct {
}
#endif /* !CH_DBG_ENABLE_CHECKS */
+/*===========================================================================*/
+/* Assertions related macros. */
+/*===========================================================================*/
+
#if CH_DBG_ENABLE_ASSERTS || defined(__DOXYGEN__)
/**
* @brief Condition assertion.
@@ -130,37 +188,44 @@ typedef struct {
#define chDbgAssert(c, m, r) {(void)(c);}
#endif /* !CH_DBG_ENABLE_ASSERTS */
-#if !(CH_DBG_ENABLE_ASSERTS || \
- CH_DBG_ENABLE_CHECKS || \
- CH_DBG_ENABLE_STACK_CHECK)
+extern char *dbg_panic_msg;
+
+/*===========================================================================*/
+/* Panic related macros. */
+/*===========================================================================*/
+
+#if !CH_DBG_ENABLED
/* When the debug features are disabled this function is replaced by an empty
macro.*/
#define chDbgPanic(msg) {}
#endif
-#if !CH_DBG_ENABLE_TRACE
-/* When the trace feature is disabled this function is replaced by an empty
- macro.*/
-#define chDbgTrace(otp) {}
-#endif
-
-#if !defined(__DOXYGEN__)
#ifdef __cplusplus
extern "C" {
#endif
+#if CH_DBG_SYSTEM_STATE_CHECK
+ void dbg_check_disable(void);
+ void dbg_check_suspend(void);
+ void dbg_check_enable(void);
+ void dbg_check_lock(void);
+ void dbg_check_unlock(void);
+ void dbg_check_lock_from_isr(void);
+ void dbg_check_unlock_from_isr(void);
+ void dbg_check_enter_isr(void);
+ void dbg_check_leave_isr(void);
+ void chDbgCheckClassI(void);
+ void chDbgCheckClassS(void);
+#endif
#if CH_DBG_ENABLE_TRACE || defined(__DOXYGEN__)
- extern ch_trace_buffer_t dbg_trace_buffer;
void _trace_init(void);
- void chDbgTrace(Thread *otp);
+ void dbg_trace(Thread *otp);
#endif
-#if CH_DBG_ENABLE_ASSERTS || CH_DBG_ENABLE_CHECKS || CH_DBG_ENABLE_STACK_CHECK
- extern char *dbg_panic_msg;
+#if CH_DBG_ENABLED
void chDbgPanic(char *msg);
#endif
#ifdef __cplusplus
}
#endif
-#endif /* !defined(__DOXYGEN__) */
#endif /* _CHDEBUG_H_ */
diff --git a/os/kernel/include/chschd.h b/os/kernel/include/chschd.h
index cd545a05e..0e933e8ba 100644
--- a/os/kernel/include/chschd.h
+++ b/os/kernel/include/chschd.h
@@ -134,14 +134,14 @@ extern "C" {
#if !defined(PORT_OPTIMIZED_WAKEUPS)
void chSchWakeupS(Thread *tp, msg_t msg);
#endif
-#if !defined(PORT_OPTIMIZED_DORESCHEDULEI)
- void chSchDoRescheduleI(void);
-#endif
#if !defined(PORT_OPTIMIZED_RESCHEDULES)
void chSchRescheduleS(void);
#endif
-#if !defined(PORT_OPTIMIZED_ISRESCHREQUIREDEXI)
- bool_t chSchIsRescRequiredExI(void);
+#if !defined(PORT_OPTIMIZED_ISPREEMPTIONREQUIRED)
+ bool_t chSchIsPreemptionRequired(void);
+#endif
+#if !defined(PORT_OPTIMIZED_DORESCHEDULE)
+ void chSchDoReschedule(void);
#endif
#ifdef __cplusplus
}
@@ -179,10 +179,37 @@ extern "C" {
#if !defined(PORT_OPTIMIZED_DOYIELDS) || defined(__DOXYGEN__)
#define chSchDoYieldS() { \
if (chSchCanYieldS()) \
- chSchDoRescheduleI(); \
+ chSchDoReschedule(); \
}
#endif /* !defined(PORT_OPTIMIZED_DOYIELDS) */
+/**
+ * @brief Inlineable preemption code.
+ * @details This is the common preemption code, this function must be invoked
+ * exclusively from the port layer.
+ *
+ * @special
+ */
+#if (CH_TIME_QUANTUM > 0) || defined(__DOXYGEN__)
+#define chSchPreemption() { \
+ tprio_t p1 = firstprio(&rlist.r_queue); \
+ tprio_t p2 = currp->p_prio; \
+ if (rlist.r_preempt) { \
+ if (p1 > p2) \
+ chSchDoReschedule(); \
+ } \
+ else { \
+ if (p1 >= p2) \
+ chSchDoReschedule(); \
+ } \
+}
+#else /* CH_TIME_QUANTUM == 0 */
+#define chSchPreemption() { \
+ if (p1 >= p2) \
+ chSchDoReschedule(); \
+}
+#endif /* CH_TIME_QUANTUM == 0 */
+
#endif /* _CHSCHD_H_ */
/** @} */
diff --git a/os/kernel/include/chsys.h b/os/kernel/include/chsys.h
index 37d4cd7ce..f807182ac 100644
--- a/os/kernel/include/chsys.h
+++ b/os/kernel/include/chsys.h
@@ -66,14 +66,19 @@
/**
* @brief Performs a context switch.
- * @note This function should nevel be used from user code directly.
+ * @note Not a user function, it is meant to be invoked by the scheduler
+ * itself or from within the port layer.
*
* @param[in] ntp the thread to be switched in
* @param[in] otp the thread to be switched out
*
* @special
*/
-#define chSysSwitchI(ntp, otp) port_switch(ntp, otp)
+#define chSysSwitch(ntp, otp) { \
+ dbg_trace(otp); \
+ THREAD_CONTEXT_SWITCH_HOOK(ntp, otp); \
+ port_switch(ntp, otp); \
+}
/**
* @brief Raises the system interrupt priority mask to the maximum level.
@@ -83,7 +88,10 @@
*
* @special
*/
-#define chSysDisable() port_disable()
+#define chSysDisable() { \
+ port_disable(); \
+ dbg_check_disable(); \
+}
/**
* @brief Raises the system interrupt priority mask to system level.
@@ -96,7 +104,10 @@
*
* @special
*/
-#define chSysSuspend() port_suspend()
+#define chSysSuspend() { \
+ port_suspend(); \
+ dbg_check_suspend(); \
+}
/**
* @brief Lowers the system interrupt priority mask to user level.
@@ -107,45 +118,30 @@
*
* @special
*/
-#define chSysEnable() port_enable()
+#define chSysEnable() { \
+ dbg_check_enable(); \
+ port_enable(); \
+}
/**
* @brief Enters the kernel lock mode.
- * @note The use of kernel lock mode is not recommended in the user code,
- * it is a better idea to use the semaphores or mutexes instead.
- * @see CH_USE_NESTED_LOCKS
*
* @special
*/
-#if CH_USE_NESTED_LOCKS || defined(__DOXYGEN__)
-#if CH_OPTIMIZE_SPEED || defined(__DOXYGEN__)
-#define chSysLock() { \
- if (currp->p_locks++ == 0) \
- port_lock(); \
+#define chSysLock() { \
+ port_lock(); \
+ dbg_check_lock(); \
}
-#endif /* CH_OPTIMIZE_SPEED */
-#else /* !CH_USE_NESTED_LOCKS */
-#define chSysLock() port_lock()
-#endif /* !CH_USE_NESTED_LOCKS */
/**
* @brief Leaves the kernel lock mode.
- * @note The use of kernel lock mode is not recommended in the user code,
- * it is a better idea to use the semaphores or mutexes instead.
- * @see CH_USE_NESTED_LOCKS
*
* @special
*/
-#if CH_USE_NESTED_LOCKS || defined(__DOXYGEN__)
-#if CH_OPTIMIZE_SPEED || defined(__DOXYGEN__)
-#define chSysUnlock() { \
- if (--currp->p_locks == 0) \
- port_unlock(); \
+#define chSysUnlock() { \
+ dbg_check_unlock(); \
+ port_unlock(); \
}
-#endif /* CH_OPTIMIZE_SPEED */
-#else /* !CH_USE_NESTED_LOCKS */
-#define chSysUnlock() port_unlock()
-#endif /* !CH_USE_NESTED_LOCKS */
/**
* @brief Enters the kernel lock mode from within an interrupt handler.
@@ -159,7 +155,10 @@
*
* @special
*/
-#define chSysLockFromIsr() port_lock_from_isr()
+#define chSysLockFromIsr() { \
+ port_lock_from_isr(); \
+ dbg_check_lock_from_isr(); \
+}
/**
* @brief Leaves the kernel lock mode from within an interrupt handler.
@@ -174,27 +173,42 @@
*
* @special
*/
-#define chSysUnlockFromIsr() port_unlock_from_isr()
+#define chSysUnlockFromIsr() { \
+ dbg_check_unlock_from_isr(); \
+ port_unlock_from_isr(); \
+}
/**
* @brief IRQ handler enter code.
* @note Usually IRQ handlers functions are also declared naked.
* @note On some architectures this macro can be empty.
+ *
+ * @special
*/
-#define CH_IRQ_PROLOGUE() PORT_IRQ_PROLOGUE()
+#define CH_IRQ_PROLOGUE() { \
+ PORT_IRQ_PROLOGUE(); \
+ dbg_check_enter_isr(); \
+}
/**
* @brief IRQ handler exit code.
* @note Usually IRQ handlers function are also declared naked.
* @note This macro usually performs the final reschedule by using
- * @p chSchRescRequiredI() and @p chSchDoRescheduleI().
+ * @p chSchIsPreemptionRequired() and @p chSchDoReschedule().
+ *
+ * @special
*/
-#define CH_IRQ_EPILOGUE() PORT_IRQ_EPILOGUE()
+#define CH_IRQ_EPILOGUE() { \
+ dbg_check_leave_isr(); \
+ PORT_IRQ_EPILOGUE(); \
+}
/**
* @brief Standard normal IRQ handler declaration.
* @note @p id can be a function name or a vector number depending on the
* port implementation.
+ *
+ * @special
*/
#define CH_IRQ_HANDLER(id) PORT_IRQ_HANDLER(id)
@@ -203,6 +217,8 @@
* @note @p id can be a function name or a vector number depending on the
* port implementation.
* @note Not all architectures support fast interrupts.
+ *
+ * @special
*/
#define CH_FAST_IRQ_HANDLER(id) PORT_FAST_IRQ_HANDLER(id)
@@ -211,10 +227,6 @@ extern "C" {
#endif
void chSysInit(void);
void chSysTimerHandlerI(void);
-#if CH_USE_NESTED_LOCKS && !CH_OPTIMIZE_SPEED
- void chSysLock(void);
- void chSysUnlock(void);
-#endif /* CH_USE_NESTED_LOCKS && !CH_OPTIMIZE_SPEED */
#ifdef __cplusplus
}
#endif
diff --git a/os/kernel/include/chthreads.h b/os/kernel/include/chthreads.h
index b02960bd4..a0a668df4 100644
--- a/os/kernel/include/chthreads.h
+++ b/os/kernel/include/chthreads.h
@@ -75,12 +75,6 @@ struct Thread {
*/
trefs_t p_refs;
#endif
-#if CH_USE_NESTED_LOCKS || defined(__DOXYGEN__)
- /**
- * @brief Number of nested locks.
- */
- cnt_t p_locks;
-#endif
#if CH_DBG_THREADS_PROFILING || defined(__DOXYGEN__)
/**
* @brief Thread consumed time in ticks.
diff --git a/os/kernel/src/chcond.c b/os/kernel/src/chcond.c
index 456fc454f..d1aeb75af 100644
--- a/os/kernel/src/chcond.c
+++ b/os/kernel/src/chcond.c
@@ -86,6 +86,7 @@ void chCondSignal(CondVar *cp) {
*/
void chCondSignalI(CondVar *cp) {
+ chDbgCheckClassI();
chDbgCheck(cp != NULL, "chCondSignalI");
if (notempty(&cp->c_queue))
@@ -120,6 +121,7 @@ void chCondBroadcast(CondVar *cp) {
*/
void chCondBroadcastI(CondVar *cp) {
+ chDbgCheckClassI();
chDbgCheck(cp != NULL, "chCondBroadcastI");
/* Empties the condition variable queue and inserts all the Threads into the
@@ -177,6 +179,7 @@ msg_t chCondWaitS(CondVar *cp) {
Mutex *mp;
msg_t msg;
+ chDbgCheckClassS();
chDbgCheck(cp != NULL, "chCondWaitS");
chDbgAssert(ctp->p_mtxlist != NULL,
"chCondWaitS(), #1",
@@ -261,6 +264,7 @@ msg_t chCondWaitTimeoutS(CondVar *cp, systime_t time) {
Mutex *mp;
msg_t msg;
+ chDbgCheckClassS();
chDbgCheck((cp != NULL) && (time != TIME_IMMEDIATE), "chCondWaitTimeoutS");
chDbgAssert(currp->p_mtxlist != NULL,
"chCondWaitTimeoutS(), #1",
diff --git a/os/kernel/src/chdebug.c b/os/kernel/src/chdebug.c
index 0e378cc6d..8fd081c05 100644
--- a/os/kernel/src/chdebug.c
+++ b/os/kernel/src/chdebug.c
@@ -24,18 +24,191 @@
*
* @addtogroup debug
* @details Debug APIs and services:
+ * - Runtime system state and call protocol check. The following
+ * panic messages can be generated:
+ * - SV#1, misplaced @p chSysDisable().
+ * - SV#2, misplaced @p chSysSuspend()
+ * - SV#3, misplaced @p chSysEnable().
+ * - SV#4, misplaced @p chSysLock().
+ * - SV#5, misplaced @p chSysUnlock().
+ * - SV#6, misplaced @p chSysLockFromIsr().
+ * - SV#7, misplaced @p chSysUnlockFromIsr().
+ * - SV#8, misplaced @p CH_IRQ_PROLOGUE().
+ * - SV#9, misplaced @p CH_IRQ_EPILOGUE().
+ * - SV#10, misplaced I-class function.
+ * - SV#11, misplaced S-class function.
+ * .
* - Trace buffer.
* - Parameters check.
* - Kernel assertions.
+ * - Kernel panics.
* .
- * @pre In order to use the debug APIs the @p CH_DBG_ENABLE_TRACE,
- * @p CH_DBG_ENABLE_ASSERTS, @p CH_DBG_ENABLE_CHECKS options must
- * be enabled in @p chconf.h.
+ * @note Stack checks are not implemented in this module but in the port
+ * layer in an architecture-dependent way.
* @{
*/
#include "ch.h"
+/*===========================================================================*/
+/* System state checker related code and variables. */
+/*===========================================================================*/
+
+#if CH_DBG_SYSTEM_STATE_CHECK || defined(__DOXYGEN__)
+
+/**
+ * @brief ISR nesting level.
+ */
+cnt_t dbg_isr_cnt;
+
+/**
+ * @brief Lock nesting level.
+ */
+cnt_t dbg_lock_cnt;
+
+/**
+ * @brief Guard code for @p chSysDisable().
+ *
+ * @notapi
+ */
+void dbg_check_disable(void) {
+
+ if ((dbg_isr_cnt != 0) || (dbg_lock_cnt != 0))
+ chDbgPanic("SV#1");
+}
+
+/**
+ * @brief Guard code for @p chSysSuspend().
+ *
+ * @notapi
+ */
+void dbg_check_suspend(void) {
+
+ if ((dbg_isr_cnt != 0) || (dbg_lock_cnt != 0))
+ chDbgPanic("SV#2");
+}
+
+/**
+ * @brief Guard code for @p chSysEnable().
+ *
+ * @notapi
+ */
+void dbg_check_enable(void) {
+
+ if ((dbg_isr_cnt != 0) || (dbg_lock_cnt != 0))
+ chDbgPanic("SV#3");
+}
+
+/**
+ * @brief Guard code for @p chSysLock().
+ *
+ * @notapi
+ */
+void dbg_check_lock(void) {
+
+ if ((dbg_isr_cnt != 0) || (dbg_lock_cnt != 0))
+ chDbgPanic("SV#4");
+ dbg_lock_cnt = 1;
+}
+
+/**
+ * @brief Guard code for @p chSysUnlock().
+ *
+ * @notapi
+ */
+void dbg_check_unlock(void) {
+
+ if ((dbg_isr_cnt != 0) || (dbg_lock_cnt <= 0))
+ chDbgPanic("SV#5");
+ dbg_lock_cnt = 0;
+}
+
+/**
+ * @brief Guard code for @p chSysLockFromIsr().
+ *
+ * @notapi
+ */
+void dbg_check_lock_from_isr(void) {
+
+ if ((dbg_isr_cnt <= 0) || (dbg_lock_cnt != 0))
+ chDbgPanic("SV#6");
+ dbg_lock_cnt = 1;
+}
+
+/**
+ * @brief Guard code for @p chSysUnlockFromIsr().
+ *
+ * @notapi
+ */
+void dbg_check_unlock_from_isr(void) {
+
+ if ((dbg_isr_cnt <= 0) || (dbg_lock_cnt <= 0))
+ chDbgPanic("SV#7");
+ dbg_lock_cnt = 0;
+}
+
+/**
+ * @brief Guard code for @p CH_IRQ_PROLOGUE().
+ *
+ * @notapi
+ */
+void dbg_check_enter_isr(void) {
+
+ port_lock_from_isr();
+ if ((dbg_isr_cnt < 0) || (dbg_lock_cnt != 0))
+ chDbgPanic("SV#8");
+ dbg_isr_cnt++;
+ port_unlock_from_isr();
+}
+
+/**
+ * @brief Guard code for @p CH_IRQ_EPILOGUE().
+ *
+ * @notapi
+ */
+void dbg_check_leave_isr(void) {
+
+ port_lock_from_isr();
+ if ((dbg_isr_cnt <= 0) || (dbg_lock_cnt != 0))
+ chDbgPanic("SV#9");
+ dbg_isr_cnt--;
+ port_unlock_from_isr();
+}
+
+/**
+ * @brief I-class functions context check.
+ * @details Verifies that the system is in an appropriate state for invoking
+ * an I-class API function. A panic is generated if the state is
+ * not compatible.
+ *
+ * @api
+ */
+void chDbgCheckClassI(void) {
+
+ if ((dbg_isr_cnt < 0) || (dbg_lock_cnt <= 0))
+ chDbgPanic("SV#10");
+}
+
+/**
+ * @brief S-class functions context check.
+ * @details Verifies that the system is in an appropriate state for invoking
+ * an S-class API function. A panic is generated if the state is
+ * not compatible.
+ *
+ * @api
+ */
+void chDbgCheckClassS(void) {
+
+ if ((dbg_isr_cnt != 0) || (dbg_lock_cnt <= 0))
+ chDbgPanic("SV#11");
+}
+
+#endif /* CH_DBG_SYSTEM_STATE_CHECK */
+
+/*===========================================================================*/
+/* Trace related code and variables. */
+/*===========================================================================*/
+
#if CH_DBG_ENABLE_TRACE || defined(__DOXYGEN__)
/**
* @brief Public trace buffer.
@@ -59,7 +232,7 @@ void _trace_init(void) {
*
* @notapi
*/
-void chDbgTrace(Thread *otp) {
+void dbg_trace(Thread *otp) {
dbg_trace_buffer.tb_ptr->se_time = chTimeNow();
dbg_trace_buffer.tb_ptr->se_tp = currp;
@@ -71,13 +244,15 @@ void chDbgTrace(Thread *otp) {
}
#endif /* CH_DBG_ENABLE_TRACE */
-#if CH_DBG_ENABLE_ASSERTS || CH_DBG_ENABLE_CHECKS || \
- CH_DBG_ENABLE_STACK_CHECK || defined(__DOXYGEN__)
+/*===========================================================================*/
+/* Panic related code and variables. */
+/*===========================================================================*/
+
+#if CH_DBG_ENABLED || defined(__DOXYGEN__)
/**
* @brief Pointer to the panic message.
* @details This pointer is meant to be accessed through the debugger, it is
- * written once and then the system is halted. This variable can be
- * set to @p NULL if the halt is caused by a stack overflow.
+ * written once and then the system is halted.
*/
char *dbg_panic_msg;
@@ -91,6 +266,6 @@ void chDbgPanic(char *msg) {
dbg_panic_msg = msg;
chSysHalt();
}
-#endif /* CH_DBG_ENABLE_ASSERTS || CH_DBG_ENABLE_CHECKS || CH_DBG_ENABLE_STACK_CHECK */
+#endif /* CH_DBG_ENABLED */
/** @} */
diff --git a/os/kernel/src/chevents.c b/os/kernel/src/chevents.c
index d74ad2dc4..7193e3a12 100644
--- a/os/kernel/src/chevents.c
+++ b/os/kernel/src/chevents.c
@@ -185,6 +185,7 @@ void chEvtSignalFlags(Thread *tp, eventmask_t mask) {
*/
void chEvtSignalFlagsI(Thread *tp, eventmask_t mask) {
+ chDbgCheckClassI();
chDbgCheck(tp != NULL, "chEvtSignalI");
tp->p_epending |= mask;
@@ -237,6 +238,7 @@ void chEvtBroadcastFlags(EventSource *esp, eventmask_t mask) {
void chEvtBroadcastFlagsI(EventSource *esp, eventmask_t mask) {
EventListener *elp;
+ chDbgCheckClassI();
chDbgCheck(esp != NULL, "chEvtBroadcastMaskI");
elp = esp->es_next;
diff --git a/os/kernel/src/chmboxes.c b/os/kernel/src/chmboxes.c
index af6ee5ea8..bf5fdfe29 100644
--- a/os/kernel/src/chmboxes.c
+++ b/os/kernel/src/chmboxes.c
@@ -143,6 +143,7 @@ msg_t chMBPost(Mailbox *mbp, msg_t msg, systime_t time) {
msg_t chMBPostS(Mailbox *mbp, msg_t msg, systime_t time) {
msg_t rdymsg;
+ chDbgCheckClassS();
chDbgCheck(mbp != NULL, "chMBPostS");
rdymsg = chSemWaitTimeoutS(&mbp->mb_emptysem, time);
@@ -172,6 +173,7 @@ msg_t chMBPostS(Mailbox *mbp, msg_t msg, systime_t time) {
*/
msg_t chMBPostI(Mailbox *mbp, msg_t msg) {
+ chDbgCheckClassI();
chDbgCheck(mbp != NULL, "chMBPostI");
if (chSemGetCounterI(&mbp->mb_emptysem) <= 0)
@@ -234,6 +236,7 @@ msg_t chMBPostAhead(Mailbox *mbp, msg_t msg, systime_t time) {
msg_t chMBPostAheadS(Mailbox *mbp, msg_t msg, systime_t time) {
msg_t rdymsg;
+ chDbgCheckClassS();
chDbgCheck(mbp != NULL, "chMBPostAheadS");
rdymsg = chSemWaitTimeoutS(&mbp->mb_emptysem, time);
@@ -263,6 +266,7 @@ msg_t chMBPostAheadS(Mailbox *mbp, msg_t msg, systime_t time) {
*/
msg_t chMBPostAheadI(Mailbox *mbp, msg_t msg) {
+ chDbgCheckClassI();
chDbgCheck(mbp != NULL, "chMBPostAheadI");
if (chSemGetCounterI(&mbp->mb_emptysem) <= 0)
@@ -325,6 +329,7 @@ msg_t chMBFetch(Mailbox *mbp, msg_t *msgp, systime_t time) {
msg_t chMBFetchS(Mailbox *mbp, msg_t *msgp, systime_t time) {
msg_t rdymsg;
+ chDbgCheckClassS();
chDbgCheck((mbp != NULL) && (msgp != NULL), "chMBFetchS");
rdymsg = chSemWaitTimeoutS(&mbp->mb_fullsem, time);
@@ -354,6 +359,7 @@ msg_t chMBFetchS(Mailbox *mbp, msg_t *msgp, systime_t time) {
*/
msg_t chMBFetchI(Mailbox *mbp, msg_t *msgp) {
+ chDbgCheckClassI();
chDbgCheck((mbp != NULL) && (msgp != NULL), "chMBFetchI");
if (chSemGetCounterI(&mbp->mb_fullsem) <= 0)
diff --git a/os/kernel/src/chmemcore.c b/os/kernel/src/chmemcore.c
index 311d170c5..0eac9a429 100644
--- a/os/kernel/src/chmemcore.c
+++ b/os/kernel/src/chmemcore.c
@@ -105,6 +105,8 @@ void *chCoreAlloc(size_t size) {
void *chCoreAllocI(size_t size) {
void *p;
+ chDbgCheckClassI();
+
size = MEM_ALIGN_NEXT(size);
if ((size_t)(endmem - nextmem) < size)
return NULL;
diff --git a/os/kernel/src/chmempools.c b/os/kernel/src/chmempools.c
index 38adc3d49..767bfda09 100644
--- a/os/kernel/src/chmempools.c
+++ b/os/kernel/src/chmempools.c
@@ -72,6 +72,7 @@ void chPoolInit(MemoryPool *mp, size_t size, memgetfunc_t provider) {
void *chPoolAllocI(MemoryPool *mp) {
void *objp;
+ chDbgCheckClassI();
chDbgCheck(mp != NULL, "chPoolAllocI");
if ((objp = mp->mp_next) != NULL)
@@ -114,6 +115,7 @@ void *chPoolAlloc(MemoryPool *mp) {
void chPoolFreeI(MemoryPool *mp, void *objp) {
struct pool_header *php = objp;
+ chDbgCheckClassI();
chDbgCheck((mp != NULL) && (objp != NULL) && MEM_IS_ALIGNED(objp),
"chPoolFreeI");
diff --git a/os/kernel/src/chmtx.c b/os/kernel/src/chmtx.c
index df71d1cc6..7d5bbe15e 100644
--- a/os/kernel/src/chmtx.c
+++ b/os/kernel/src/chmtx.c
@@ -114,6 +114,7 @@ void chMtxLock(Mutex *mp) {
void chMtxLockS(Mutex *mp) {
Thread *ctp = currp;
+ chDbgCheckClassS();
chDbgCheck(mp != NULL, "chMtxLockS");
/* Ia the mutex already locked? */
@@ -157,6 +158,7 @@ void chMtxLockS(Mutex *mp) {
#endif
/* Re-enqueues tp with its new priority on the ready list.*/
chSchReadyI(dequeue(tp));
+ break;
}
break;
}
@@ -224,6 +226,7 @@ bool_t chMtxTryLock(Mutex *mp) {
*/
bool_t chMtxTryLockS(Mutex *mp) {
+ chDbgCheckClassS();
chDbgCheck(mp != NULL, "chMtxTryLockS");
if (mp->m_owner != NULL)
@@ -308,6 +311,7 @@ Mutex *chMtxUnlockS(void) {
Thread *ctp = currp;
Mutex *ump, *mp;
+ chDbgCheckClassS();
chDbgAssert(ctp->p_mtxlist != NULL,
"chMtxUnlockS(), #1",
"owned mutexes list empty");
diff --git a/os/kernel/src/chqueues.c b/os/kernel/src/chqueues.c
index 8532f8307..cf3d21732 100644
--- a/os/kernel/src/chqueues.c
+++ b/os/kernel/src/chqueues.c
@@ -108,6 +108,8 @@ void chIQInit(InputQueue *iqp, uint8_t *bp, size_t size, qnotify_t infy) {
*/
void chIQResetI(InputQueue *iqp) {
+ chDbgCheckClassI();
+
iqp->q_rdptr = iqp->q_wrptr = iqp->q_buffer;
iqp->q_counter = 0;
while (notempty(&iqp->q_waiting))
@@ -129,6 +131,8 @@ void chIQResetI(InputQueue *iqp) {
*/
msg_t chIQPutI(InputQueue *iqp, uint8_t b) {
+ chDbgCheckClassI();
+
if (chIQIsFullI(iqp))
return Q_FULL;
@@ -284,6 +288,8 @@ void chOQInit(OutputQueue *oqp, uint8_t *bp, size_t size, qnotify_t onfy) {
*/
void chOQResetI(OutputQueue *oqp) {
+ chDbgCheckClassI();
+
oqp->q_rdptr = oqp->q_wrptr = oqp->q_buffer;
oqp->q_counter = chQSizeI(oqp);
while (notempty(&oqp->q_waiting))
@@ -349,6 +355,8 @@ msg_t chOQPutTimeout(OutputQueue *oqp, uint8_t b, systime_t time) {
msg_t chOQGetI(OutputQueue *oqp) {
uint8_t b;
+ chDbgCheckClassI();
+
if (chOQIsEmptyI(oqp))
return Q_EMPTY;
diff --git a/os/kernel/src/chschd.c b/os/kernel/src/chschd.c
index d41649b4c..f2014b8c7 100644
--- a/os/kernel/src/chschd.c
+++ b/os/kernel/src/chschd.c
@@ -75,7 +75,7 @@ void _scheduler_init(void) {
Thread *chSchReadyI(Thread *tp) {
Thread *cp;
- /* Integrity check.*/
+ /* Integrity checks.*/
chDbgAssert((tp->p_state != THD_STATE_READY) &&
(tp->p_state != THD_STATE_FINAL),
"chSchReadyI(), #1",
@@ -107,14 +107,15 @@ Thread *chSchReadyI(Thread *tp) {
void chSchGoSleepS(tstate_t newstate) {
Thread *otp;
+ chDbgCheckClassS();
+
(otp = currp)->p_state = newstate;
#if CH_TIME_QUANTUM > 0
rlist.r_preempt = CH_TIME_QUANTUM;
#endif
setcurrp(fifo_remove(&rlist.r_queue));
currp->p_state = THD_STATE_CURRENT;
- chDbgTrace(otp);
- chSysSwitchI(currp, otp);
+ chSysSwitch(currp, otp);
}
#endif /* !defined(PORT_OPTIMIZED_GOSLEEPS) */
@@ -174,6 +175,8 @@ static void wakeup(void *p) {
*/
msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time) {
+ chDbgCheckClassS();
+
if (TIME_INFINITE != time) {
VirtualTimer vt;
@@ -208,6 +211,8 @@ msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time) {
#if !defined(PORT_OPTIMIZED_WAKEUPS) || defined(__DOXYGEN__)
void chSchWakeupS(Thread *ntp, msg_t msg) {
+ chDbgCheckClassS();
+
ntp->p_u.rdymsg = msg;
/* If the waken thread has a not-greater priority than the current
one then it is just inserted in the ready list else it made
@@ -222,37 +227,12 @@ void chSchWakeupS(Thread *ntp, msg_t msg) {
#endif
setcurrp(ntp);
ntp->p_state = THD_STATE_CURRENT;
- chDbgTrace(otp);
- chSysSwitchI(ntp, otp);
+ chSysSwitch(ntp, otp);
}
}
#endif /* !defined(PORT_OPTIMIZED_WAKEUPS) */
/**
- * @brief Switches to the first thread on the runnable queue.
- * @note It is intended to be called if @p chSchRescRequiredI() evaluates
- * to @p TRUE.
- *
- * @iclass
- */
-#if !defined(PORT_OPTIMIZED_DORESCHEDULEI) || defined(__DOXYGEN__)
-void chSchDoRescheduleI(void) {
- Thread *otp;
-
-#if CH_TIME_QUANTUM > 0
- rlist.r_preempt = CH_TIME_QUANTUM;
-#endif
- otp = currp;
- /* Picks the first thread from the ready queue and makes it current.*/
- setcurrp(fifo_remove(&rlist.r_queue));
- currp->p_state = THD_STATE_CURRENT;
- chSchReadyI(otp);
- chDbgTrace(otp);
- chSysSwitchI(currp, otp);
-}
-#endif /* !defined(PORT_OPTIMIZED_DORESCHEDULEI) */
-
-/**
* @brief Performs a reschedule if a higher priority thread is runnable.
* @details If a thread with a higher priority than the current thread is in
* the ready list then make the higher priority thread running.
@@ -262,25 +242,28 @@ void chSchDoRescheduleI(void) {
#if !defined(PORT_OPTIMIZED_RESCHEDULES) || defined(__DOXYGEN__)
void chSchRescheduleS(void) {
+ chDbgCheckClassS();
+
if (chSchIsRescRequiredI())
- chSchDoRescheduleI();
+ chSchDoReschedule();
}
#endif /* !defined(PORT_OPTIMIZED_RESCHEDULES) */
/**
- * @brief Evaluates if a reschedule is required.
+ * @brief Evaluates if preemption is required.
* @details The decision is taken by comparing the relative priorities and
* depending on the state of the round robin timeout counter.
- * @note This function is meant to be used in the timer interrupt handler
- * where @p chVTDoTickI() is invoked.
+ * @note Not a user function, it is meant to be invoked by the scheduler
+ * itself or from within the port layer.
*
- * @retval TRUE if there is a thread that should go in running state.
- * @retval FALSE if a reschedule is not required.
+ * @retval TRUE if there is a thread that must go in running state
+ * immediately.
+ * @retval FALSE if preemption is not required.
*
- * @iclass
+ * @special
*/
-#if !defined(PORT_OPTIMIZED_ISRESCHREQUIREDEXI) || defined(__DOXYGEN__)
-bool_t chSchIsRescRequiredExI(void) {
+#if !defined(PORT_OPTIMIZED_ISPREEMPTIONREQUIRED) || defined(__DOXYGEN__)
+bool_t chSchIsPreemptionRequired(void) {
tprio_t p1 = firstprio(&rlist.r_queue);
tprio_t p2 = currp->p_prio;
#if CH_TIME_QUANTUM > 0
@@ -295,6 +278,29 @@ bool_t chSchIsRescRequiredExI(void) {
return p1 > p2;
#endif
}
-#endif /* !defined(PORT_OPTIMIZED_ISRESCHREQUIREDEXI) */
+#endif /* !defined(PORT_OPTIMIZED_ISPREEMPTIONREQUIRED) */
+
+/**
+ * @brief Switches to the first thread on the runnable queue.
+ * @note Not a user function, it is meant to be invoked by the scheduler
+ * itself or from within the port layer.
+ *
+ * @special
+ */
+#if !defined(PORT_OPTIMIZED_DORESCHEDULE) || defined(__DOXYGEN__)
+void chSchDoReschedule(void) {
+ Thread *otp;
+
+#if CH_TIME_QUANTUM > 0
+ rlist.r_preempt = CH_TIME_QUANTUM;
+#endif
+ otp = currp;
+ /* Picks the first thread from the ready queue and makes it current.*/
+ setcurrp(fifo_remove(&rlist.r_queue));
+ currp->p_state = THD_STATE_CURRENT;
+ chSchReadyI(otp);
+ chSysSwitch(currp, otp);
+}
+#endif /* !defined(PORT_OPTIMIZED_DORESCHEDULE) */
/** @} */
diff --git a/os/kernel/src/chsem.c b/os/kernel/src/chsem.c
index c22a568ea..bf985bead 100644
--- a/os/kernel/src/chsem.c
+++ b/os/kernel/src/chsem.c
@@ -129,8 +129,8 @@ void chSemReset(Semaphore *sp, cnt_t n) {
void chSemResetI(Semaphore *sp, cnt_t n) {
cnt_t cnt;
+ chDbgCheckClassI();
chDbgCheck((sp != NULL) && (n >= 0), "chSemResetI");
-
chDbgAssert(((sp->s_cnt >= 0) && isempty(&sp->s_queue)) ||
((sp->s_cnt < 0) && notempty(&sp->s_queue)),
"chSemResetI(), #1",
@@ -177,8 +177,8 @@ msg_t chSemWait(Semaphore *sp) {
*/
msg_t chSemWaitS(Semaphore *sp) {
+ chDbgCheckClassS();
chDbgCheck(sp != NULL, "chSemWaitS");
-
chDbgAssert(((sp->s_cnt >= 0) && isempty(&sp->s_queue)) ||
((sp->s_cnt < 0) && notempty(&sp->s_queue)),
"chSemWaitS(), #1",
@@ -242,8 +242,8 @@ msg_t chSemWaitTimeout(Semaphore *sp, systime_t time) {
*/
msg_t chSemWaitTimeoutS(Semaphore *sp, systime_t time) {
+ chDbgCheckClassS();
chDbgCheck(sp != NULL, "chSemWaitTimeoutS");
-
chDbgAssert(((sp->s_cnt >= 0) && isempty(&sp->s_queue)) ||
((sp->s_cnt < 0) && notempty(&sp->s_queue)),
"chSemWaitTimeoutS(), #1",
@@ -271,7 +271,6 @@ msg_t chSemWaitTimeoutS(Semaphore *sp, systime_t time) {
void chSemSignal(Semaphore *sp) {
chDbgCheck(sp != NULL, "chSemSignal");
-
chDbgAssert(((sp->s_cnt >= 0) && isempty(&sp->s_queue)) ||
((sp->s_cnt < 0) && notempty(&sp->s_queue)),
"chSemSignal(), #1",
@@ -296,8 +295,8 @@ void chSemSignal(Semaphore *sp) {
*/
void chSemSignalI(Semaphore *sp) {
+ chDbgCheckClassI();
chDbgCheck(sp != NULL, "chSemSignalI");
-
chDbgAssert(((sp->s_cnt >= 0) && isempty(&sp->s_queue)) ||
((sp->s_cnt < 0) && notempty(&sp->s_queue)),
"chSemSignalI(), #1",
@@ -327,8 +326,8 @@ void chSemSignalI(Semaphore *sp) {
*/
void chSemAddCounterI(Semaphore *sp, cnt_t n) {
+ chDbgCheckClassI();
chDbgCheck((sp != NULL) && (n > 0), "chSemAddCounterI");
-
chDbgAssert(((sp->s_cnt >= 0) && isempty(&sp->s_queue)) ||
((sp->s_cnt < 0) && notempty(&sp->s_queue)),
"chSemAddCounterI(), #1",
@@ -361,12 +360,10 @@ msg_t chSemSignalWait(Semaphore *sps, Semaphore *spw) {
msg_t msg;
chDbgCheck((sps != NULL) && (spw != NULL), "chSemSignalWait");
-
chDbgAssert(((sps->s_cnt >= 0) && isempty(&sps->s_queue)) ||
((sps->s_cnt < 0) && notempty(&sps->s_queue)),
"chSemSignalWait(), #1",
"inconsistent semaphore");
-
chDbgAssert(((spw->s_cnt >= 0) && isempty(&spw->s_queue)) ||
((spw->s_cnt < 0) && notempty(&spw->s_queue)),
"chSemSignalWait(), #2",
diff --git a/os/kernel/src/chsys.c b/os/kernel/src/chsys.c
index 4c8cd708d..866ee81a8 100644
--- a/os/kernel/src/chsys.c
+++ b/os/kernel/src/chsys.c
@@ -98,6 +98,8 @@ void chSysInit(void) {
setcurrp(_thread_init(&mainthread, NORMALPRIO));
currp->p_state = THD_STATE_CURRENT;
#if CH_DBG_ENABLE_STACK_CHECK
+ /* This is a special case because the main thread Thread structure is not
+ adjacent to its stack area.*/
currp->p_stklimit = &__main_thread_stack_base__;
#endif
chSysEnable();
@@ -126,6 +128,8 @@ void chSysInit(void) {
*/
void chSysTimerHandlerI(void) {
+ chDbgCheckClassI();
+
#if CH_TIME_QUANTUM > 0
/* Running thread has not used up quantum yet? */
if (rlist.r_preempt > 0)
@@ -141,24 +145,4 @@ void chSysTimerHandlerI(void) {
#endif
}
-#if CH_USE_NESTED_LOCKS && !CH_OPTIMIZE_SPEED
-void chSysLock(void) {
-
- chDbgAssert(currp->p_locks >= 0,
- "chSysLock(), #1",
- "negative nesting counter");
- if (currp->p_locks++ == 0)
- port_lock();
-}
-
-void chSysUnlock(void) {
-
- chDbgAssert(currp->p_locks > 0,
- "chSysUnlock(), #1",
- "non-positive nesting counter");
- if (--currp->p_locks == 0)
- port_unlock();
-}
-#endif /* CH_USE_NESTED_LOCKS && !CH_OPTIMIZE_SPEED */
-
/** @} */
diff --git a/os/kernel/src/chthreads.c b/os/kernel/src/chthreads.c
index 182de7673..19accdb55 100644
--- a/os/kernel/src/chthreads.c
+++ b/os/kernel/src/chthreads.c
@@ -154,6 +154,8 @@ Thread *chThdCreateI(void *wsp, size_t size,
/* Thread structure is layed out in the lower part of the thread workspace */
Thread *tp = wsp;
+ chDbgCheckClassI();
+
chDbgCheck((wsp != NULL) && (size >= THD_WA_SIZE(0)) &&
(prio <= HIGHPRIO) && (pf != NULL),
"chThdCreateI");
diff --git a/os/kernel/src/chvt.c b/os/kernel/src/chvt.c
index 4674c728e..fb8e0b0c1 100644
--- a/os/kernel/src/chvt.c
+++ b/os/kernel/src/chvt.c
@@ -70,6 +70,7 @@ void _vt_init(void) {
void chVTSetI(VirtualTimer *vtp, systime_t time, vtfunc_t vtfunc, void *par) {
VirtualTimer *p;
+ chDbgCheckClassI();
chDbgCheck((vtp != NULL) && (vtfunc != NULL) && (time != TIME_IMMEDIATE),
"chVTSetI");
@@ -98,6 +99,7 @@ void chVTSetI(VirtualTimer *vtp, systime_t time, vtfunc_t vtfunc, void *par) {
*/
void chVTResetI(VirtualTimer *vtp) {
+ chDbgCheckClassI();
chDbgCheck(vtp != NULL, "chVTResetI");
chDbgAssert(vtp->vt_func != NULL,
"chVTResetI(), #1",
diff --git a/os/kernel/templates/chconf.h b/os/kernel/templates/chconf.h
index c9c4c286a..9dd831c96 100644
--- a/os/kernel/templates/chconf.h
+++ b/os/kernel/templates/chconf.h
@@ -33,7 +33,10 @@
#define _CHCONF_H_
/*===========================================================================*/
-/* Kernel parameters. */
+/**
+ * @name Kernel parameters and options
+ * @{
+ */
/*===========================================================================*/
/**
@@ -61,21 +64,6 @@
#endif
/**
- * @brief Nested locks.
- * @details If enabled then the use of nested @p chSysLock() / @p chSysUnlock()
- * operations is allowed.<br>
- * For performance and code size reasons the recommended setting
- * is to leave this option disabled.<br>
- * You may use this option if you need to merge ChibiOS/RT with
- * external libraries that require nested lock/unlock operations.
- *
- * @note The default is @p FALSE.
- */
-#if !defined(CH_USE_NESTED_LOCKS) || defined(__DOXYGEN__)
-#define CH_USE_NESTED_LOCKS FALSE
-#endif
-
-/**
* @brief Managed RAM size.
* @details Size of the RAM area to be managed by the OS. If set to zero
* then the whole available RAM is used. The core memory is made
@@ -107,8 +95,13 @@
#define CH_NO_IDLE_THREAD FALSE
#endif
+/** @} */
+
/*===========================================================================*/
-/* Performance options. */
+/**
+ * @name Performance options
+ * @{
+ */
/*===========================================================================*/
/**
@@ -123,8 +116,13 @@
#define CH_OPTIMIZE_SPEED TRUE
#endif
+/** @} */
+
/*===========================================================================*/
-/* Subsystem options. */
+/**
+ * @name Subsystem options
+ * @{
+ */
/*===========================================================================*/
/**
@@ -346,11 +344,27 @@
#define CH_USE_DYNAMIC TRUE
#endif
+/** @} */
+
/*===========================================================================*/
-/* Debug options. */
+/**
+ * @name Debug options
+ * @{
+ */
/*===========================================================================*/
/**
+ * @brief Debug option, system state check.
+ * @details If enabled the correct call protocol for system APIs is checked
+ * at runtime.
+ *
+ * @note The default is @p FALSE.
+ */
+#if !defined(CH_DBG_SYSTEM_STATE_CHECK) || defined(__DOXYGEN__)
+#define CH_DBG_SYSTEM_STATE_CHECK FALSE
+#endif
+
+/**
* @brief Debug option, parameters checks.
* @details If enabled then the checks on the API functions input
* parameters are activated.
@@ -423,8 +437,13 @@
#define CH_DBG_THREADS_PROFILING TRUE
#endif
+/** @} */
+
/*===========================================================================*/
-/* Kernel hooks. */
+/**
+ * @name Kernel hooks
+ * @{
+ */
/*===========================================================================*/
/**
@@ -464,6 +483,16 @@
#endif
/**
+ * @brief Context switch hook.
+ * @details This hook is invoked just before switching between threads.
+ */
+#if !defined(THREAD_CONTEXT_SWITCH_HOOK) || defined(__DOXYGEN__)
+#define THREAD_CONTEXT_SWITCH_HOOK(ntp, otp) { \
+ /* System halt code here.*/ \
+}
+#endif
+
+/**
* @brief Idle Loop hook.
* @details This hook is continuously invoked by the idle thread loop.
*/
@@ -495,6 +524,8 @@
}
#endif
+/** @} */
+
/*===========================================================================*/
/* Port-specific settings (override port settings defaulted in chcore.h). */
/*===========================================================================*/
diff --git a/os/kernel/templates/chcore.h b/os/kernel/templates/chcore.h
index 5c8236c7b..416b3f1aa 100644
--- a/os/kernel/templates/chcore.h
+++ b/os/kernel/templates/chcore.h
@@ -151,7 +151,7 @@ struct context {
#define THD_WA_SIZE(n) STACK_ALIGN(sizeof(Thread) + \
sizeof(struct intctx) + \
sizeof(struct extctx) + \
- (n) + (PORT_INT_REQUIRED_STACK))
+ (n) + (PORT_INT_REQUIRED_STACK))
/**
* @brief Static working area allocation.