From cf204e72ea5fd6e4be8b3295cb148fde5fdd47d2 Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Tue, 16 Feb 2016 10:07:00 +0000 Subject: Tree reorganization. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@8900 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/nil/include/ch.h | 522 +++++++++++++++++++++++++++++++++++++++++----------- os/nil/nil.mk | 29 ++- os/nil/src/ch.c | 340 ++++++++++++++++++++++++++-------- 3 files changed, 703 insertions(+), 188 deletions(-) (limited to 'os/nil') diff --git a/os/nil/include/ch.h b/os/nil/include/ch.h index 168709049..419822471 100644 --- a/os/nil/include/ch.h +++ b/os/nil/include/ch.h @@ -18,7 +18,7 @@ */ /** - * @file nil.h + * @file ch.h * @brief Nil RTOS main header file. * @details This header includes all the required kernel headers so it is the * only header you usually need to include in your application. @@ -27,18 +27,11 @@ * @{ */ -#ifndef _NIL_H_ -#define _NIL_H_ +#ifndef _CH_H_ +#define _CH_H_ -/** - * @brief Type of a structure representing a thread. - * @note It is required as an early definition. - */ -typedef struct nil_thread thread_t; - -#include "nilconf.h" -#include "niltypes.h" -#include "nilcore.h" +#include "chconf.h" +#include "chtypes.h" /*===========================================================================*/ /* Module constants. */ @@ -61,22 +54,22 @@ typedef struct nil_thread thread_t; /** * @brief Kernel version string. */ -#define CH_KERNEL_VERSION "1.1.1" +#define CH_KERNEL_VERSION "2.0.0" /** * @brief Kernel version major number. */ -#define CH_KERNEL_MAJOR 1 +#define CH_KERNEL_MAJOR 2 /** * @brief Kernel version minor number. */ -#define CH_KERNEL_MINOR 1 +#define CH_KERNEL_MINOR 0 /** * @brief Kernel version patch number. */ -#define CH_KERNEL_PATCH 1 +#define CH_KERNEL_PATCH 0 /** @} */ /** @@ -150,26 +143,26 @@ typedef struct nil_thread thread_t; * @note This number is not inclusive of the idle thread which is * implicitly handled. */ -#if !defined(NIL_CFG_NUM_THREADS) || defined(__DOXYGEN__) -#define NIL_CFG_NUM_THREADS 2 +#if !defined(CH_CFG_NUM_THREADS) || defined(__DOXYGEN__) +#define CH_CFG_NUM_THREADS 2 #endif /** * @brief System time counter resolution. * @note Allowed values are 16 or 32 bits. */ -#if !defined(NIL_CFG_ST_RESOLUTION) || defined(__DOXYGEN__) -#define NIL_CFG_ST_RESOLUTION 32 +#if !defined(CH_CFG_ST_RESOLUTION) || defined(__DOXYGEN__) +#define CH_CFG_ST_RESOLUTION 32 #endif /** * @brief System tick frequency. - * @note This value together with the @p NIL_CFG_ST_RESOLUTION + * @note This value together with the @p CH_CFG_ST_RESOLUTION * option defines the maximum amount of time allowed for * timeouts. */ -#if !defined(NIL_CFG_ST_FREQUENCY) || defined(__DOXYGEN__) -#define NIL_CFG_ST_FREQUENCY 100 +#if !defined(CH_CFG_ST_FREQUENCY) || defined(__DOXYGEN__) +#define CH_CFG_ST_FREQUENCY 100 #endif /** @@ -180,8 +173,29 @@ typedef struct nil_thread thread_t; * The value one is not valid, timeouts are rounded up to * this value. */ -#if !defined(NIL_CFG_ST_TIMEDELTA) || defined(__DOXYGEN__) -#define NIL_CFG_ST_TIMEDELTA 0 +#if !defined(CH_CFG_ST_TIMEDELTA) || defined(__DOXYGEN__) +#define CH_CFG_ST_TIMEDELTA 0 +#endif + +/** + * @brief Semaphores APIs. + * @details If enabled then the Semaphores APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) +#define CH_CFG_USE_SEMAPHORES TRUE +#endif + +/** + * @brief Mutexes APIs. + * @details If enabled then the mutexes APIs are included in the kernel. + * + * @note Feature not currently implemented. + * @note The default is @p FALSE. + */ +#if !defined(CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__) +#define CH_CFG_USE_MUTEXES FALSE #endif /** @@ -190,44 +204,122 @@ typedef struct nil_thread thread_t; * * @note The default is @p TRUE. */ -#if !defined(NIL_CFG_USE_EVENTS) || defined(__DOXYGEN__) -#define NIL_CFG_USE_EVENTS TRUE +#if !defined(CH_CFG_USE_EVENTS) || defined(__DOXYGEN__) +#define CH_CFG_USE_EVENTS TRUE +#endif + +/** + * @brief Mailboxes APIs. + * @details If enabled then the asynchronous messages (mailboxes) APIs are + * included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_SEMAPHORES. + */ +#if !defined(CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__) +#define CH_CFG_USE_MAILBOXES TRUE +#endif + +/** + * @brief Core Memory Manager APIs. + * @details If enabled then the core memory manager APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MEMCORE) || defined(__DOXYGEN__) +#define CH_CFG_USE_MEMCORE TRUE +#endif + +/** + * @brief Heap Allocator APIs. + * @details If enabled then the memory heap allocator APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_HEAP) || defined(__DOXYGEN__) +#define CH_CFG_USE_HEAP TRUE +#endif + +/** + * @brief Memory Pools Allocator APIs. + * @details If enabled then the memory pools allocator APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__) +#define CH_CFG_USE_MEMPOOLS TRUE +#endif + +/** + * @brief Debug option, kernel statistics. + * + * @note Feature not currently implemented. + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_STATISTICS) || defined(__DOXYGEN__) +#define CH_DBG_STATISTICS FALSE +#endif + +/** + * @brief Debug option, system state check. + * @note This is a planned feature, not yet implemented. + * + * @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. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_ENABLE_CHECKS) || defined(__DOXYGEN__) +#define CH_DBG_ENABLE_CHECKS FALSE #endif /** * @brief System assertions. + * + * @note The default is @p FALSE. */ -#if !defined(NIL_CFG_ENABLE_ASSERTS) || defined(__DOXYGEN__) -#define NIL_CFG_ENABLE_ASSERTS FALSE +#if !defined(CH_DBG_ENABLE_ASSERTS) || defined(__DOXYGEN__) +#define CH_DBG_ENABLE_ASSERTS FALSE #endif /** * @brief Stack check. + * + * @note The default is @p FALSE. */ -#if !defined(NIL_CFG_ENABLE_STACK_CHECK) || defined(__DOXYGEN__) -#define NIL_CFG_ENABLE_STACK_CHECK FALSE +#if !defined(CH_DBG_ENABLE_STACK_CHECK) || defined(__DOXYGEN__) +#define CH_DBG_ENABLE_STACK_CHECK FALSE #endif /** * @brief System initialization hook. */ -#if !defined(NIL_CFG_SYSTEM_INIT_HOOK) || defined(__DOXYGEN__) -#define NIL_CFG_SYSTEM_INIT_HOOK() {} +#if !defined(CH_CFG_SYSTEM_INIT_HOOK) || defined(__DOXYGEN__) +#define CH_CFG_SYSTEM_INIT_HOOK() {} #endif /** * @brief Threads descriptor structure extension. * @details User fields added to the end of the @p thread_t structure. */ -#if !defined(NIL_CFG_THREAD_EXT_FIELDS) || defined(__DOXYGEN__) -#define NIL_CFG_THREAD_EXT_FIELDS +#if !defined(CH_CFG_THREAD_EXT_FIELDS) || defined(__DOXYGEN__) +#define CH_CFG_THREAD_EXT_FIELDS #endif /** * @brief Threads initialization hook. */ -#if !defined(NIL_CFG_THREAD_EXT_INIT_HOOK) || defined(__DOXYGEN__) -#define NIL_CFG_THREAD_EXT_INIT_HOOK(tr) {} +#if !defined(CH_CFG_THREAD_EXT_INIT_HOOK) || defined(__DOXYGEN__) +#define CH_CFG_THREAD_EXT_INIT_HOOK(tr) {} #endif /** @@ -236,8 +328,8 @@ typedef struct nil_thread thread_t; * should be invoked from here. * @note This macro can be used to activate a power saving mode. */ -#if !defined(NIL_CFG_IDLE_ENTER_HOOK) || defined(__DOXYGEN__) -#define NIL_CFG_IDLE_ENTER_HOOK() {} +#if !defined(CH_CFG_IDLE_ENTER_HOOK) || defined(__DOXYGEN__) +#define CH_CFG_IDLE_ENTER_HOOK() {} #endif /** @@ -246,44 +338,59 @@ typedef struct nil_thread thread_t; * should be invoked from here. * @note This macro can be used to deactivate a power saving mode. */ -#if !defined(NIL_CFG_IDLE_LEAVE_HOOK) || defined(__DOXYGEN__) -#define NIL_CFG_IDLE_LEAVE_HOOK() {} +#if !defined(CH_CFG_IDLE_LEAVE_HOOK) || defined(__DOXYGEN__) +#define CH_CFG_IDLE_LEAVE_HOOK() {} #endif /** * @brief System halt hook. */ -#if !defined(NIL_CFG_SYSTEM_HALT_HOOK) || defined(__DOXYGEN__) -#define NIL_CFG_SYSTEM_HALT_HOOK(reason) {} +#if !defined(CH_CFG_SYSTEM_HALT_HOOK) || defined(__DOXYGEN__) +#define CH_CFG_SYSTEM_HALT_HOOK(reason) {} #endif /*===========================================================================*/ /* Derived constants and error checks. */ /*===========================================================================*/ -#if NIL_CFG_NUM_THREADS < 1 +#if !defined(_CHIBIOS_NIL_CONF_) +#error "missing or wrong configuration file" +#endif + +#if CH_CFG_NUM_THREADS < 1 #error "at least one thread must be defined" #endif -#if NIL_CFG_NUM_THREADS > 12 -#error "Nil is not recommended for thread-intensive applications, consider" \ - "ChibiOS/RT instead" +#if CH_CFG_NUM_THREADS > 16 +#error "ChibiOS/NIL is not recommended for thread-intensive applications," \ + "consider ChibiOS/RT instead" #endif -#if (NIL_CFG_ST_RESOLUTION != 16) && (NIL_CFG_ST_RESOLUTION != 32) -#error "invalid NIL_CFG_ST_RESOLUTION specified, must be 16 or 32" +#if (CH_CFG_ST_RESOLUTION != 16) && (CH_CFG_ST_RESOLUTION != 32) +#error "invalid CH_CFG_ST_RESOLUTION specified, must be 16 or 32" #endif -#if NIL_CFG_ST_FREQUENCY <= 0 -#error "invalid NIL_CFG_ST_FREQUENCY specified, must be greated than zero" +#if CH_CFG_ST_FREQUENCY <= 0 +#error "invalid CH_CFG_ST_FREQUENCY specified, must be greated than zero" #endif -#if (NIL_CFG_ST_TIMEDELTA < 0) || (NIL_CFG_ST_TIMEDELTA == 1) -#error "invalid NIL_CFG_ST_TIMEDELTA specified, must " \ +#if (CH_CFG_ST_TIMEDELTA < 0) || (CH_CFG_ST_TIMEDELTA == 1) +#error "invalid CH_CFG_ST_TIMEDELTA specified, must " \ "be zero or greater than one" #endif -#if (NIL_CFG_ENABLE_ASSERTS == TRUE) || (NIL_CFG_ENABLE_STACK_CHECK == TRUE) +#if CH_CFG_USE_MUTEXES == TRUE +#error "mutexes not yet supported" +#endif + +#if CH_DBG_STATISTICS == TRUE +#error "statistics not yet supported" +#endif + +#if (CH_DBG_SYSTEM_STATE_CHECK == TRUE) || \ + (CH_DBG_ENABLE_CHECKS == TRUE) || \ + (CH_DBG_ENABLE_ASSERTS == TRUE) || \ + (CH_DBG_ENABLE_STACK_CHECK == TRUE) #define NIL_DBG_ENABLED TRUE #else #define NIL_DBG_ENABLED FALSE @@ -291,9 +398,7 @@ typedef struct nil_thread thread_t; /** Boundaries of the idle thread boundaries, only required if stack checking is enabled.*/ -#if (NIL_CFG_ENABLE_STACK_CHECK == TRUE) || defined(__DOXYGEN__) -extern stkalign_t __main_thread_stack_base__, __main_thread_stack_end__; - +#if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || defined(__DOXYGEN__) #define THD_IDLE_BASE (&__main_thread_stack_base__) #define THD_IDLE_END (&__main_thread_stack_end__) #else @@ -306,10 +411,23 @@ extern stkalign_t __main_thread_stack_base__, __main_thread_stack_end__; /*===========================================================================*/ /** - * @brief Type of internal context structure. + * @brief Type of system time. */ -typedef struct port_intctx intctx_t; +#if (CH_CFG_ST_RESOLUTION == 32) || defined(__DOXYGEN__) +typedef uint32_t systime_t; +#else +typedef uint16_t systime_t; +#endif + +/** + * @brief Type of a structure representing a thread. + * @note It is required as an early definition. + */ +typedef struct nil_thread thread_t; + +#include "chcore.h" +#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__) /** * @brief Type of a structure representing a semaphore. */ @@ -321,6 +439,7 @@ typedef struct nil_semaphore semaphore_t; struct nil_semaphore { volatile cnt_t cnt; /**< @brief Semaphore counter. */ }; +#endif /* CH_CFG_USE_SEMAPHORES == TRUE */ /** * @brief Thread function. @@ -352,29 +471,31 @@ typedef thread_t * thread_reference_t; * @brief Structure representing a thread. */ struct nil_thread { - intctx_t *ctxp; /**< @brief Pointer to internal context. */ - tstate_t state; /**< @brief Thread state. */ + struct port_context ctx; /**< @brief Processor context. */ + tstate_t state; /**< @brief Thread state. */ /* Note, the following union contains a pointer while the thread is in a sleeping state (!NIL_THD_IS_READY()) else contains the wake-up message.*/ union { - msg_t msg; /**< @brief Wake-up message. */ - void *p; /**< @brief Generic pointer. */ - thread_reference_t *trp; /**< @brief Pointer to thread reference. */ - semaphore_t *semp; /**< @brief Pointer to semaphore. */ -#if (NIL_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__) - eventmask_t ewmask; /**< @brief Enabled events mask. */ + msg_t msg; /**< @brief Wake-up message. */ + void *p; /**< @brief Generic pointer. */ + thread_reference_t *trp; /**< @brief Pointer to thread reference.*/ +#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__) + semaphore_t *semp; /**< @brief Pointer to semaphore. */ +#endif +#if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__) + eventmask_t ewmask; /**< @brief Enabled events mask. */ #endif } u1; - volatile systime_t timeout;/**< @brief Timeout counter, zero + volatile systime_t timeout; /**< @brief Timeout counter, zero if disabled. */ -#if (NIL_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__) - eventmask_t epmask; /**< @brief Pending events mask. */ +#if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__) + eventmask_t epmask; /**< @brief Pending events mask. */ #endif -#if (NIL_CFG_ENABLE_STACK_CHECK == TRUE) || defined(__DOXYGEN__) - stkalign_t *stklim;/**< @brief Thread stack boundary. */ +#if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || defined(__DOXYGEN__) + stkalign_t *stklimit; /**< @brief Thread stack boundary. */ #endif /* Optional extra fields.*/ - NIL_CFG_THREAD_EXT_FIELDS + CH_CFG_THREAD_EXT_FIELDS }; /** @@ -398,13 +519,13 @@ struct nil_system { * or to an higher priority thread if a switch is required. */ thread_t *next; -#if (NIL_CFG_ST_TIMEDELTA == 0) || defined(__DOXYGEN__) +#if (CH_CFG_ST_TIMEDELTA == 0) || defined(__DOXYGEN__) /** * @brief System time. */ volatile systime_t systime; #endif -#if (NIL_CFG_ST_TIMEDELTA > 0) || defined(__DOXYGEN__) +#if (CH_CFG_ST_TIMEDELTA > 0) || defined(__DOXYGEN__) /** * @brief System time of the last tick event. */ @@ -414,10 +535,16 @@ struct nil_system { */ systime_t nexttime; #endif +#if (CH_DBG_SYSTEM_STATE_CHECK == TRUE) || defined(__DOXYGEN__) /** - * @brief Thread structures for all the defined threads. + * @brief ISR nesting level. */ - thread_t threads[NIL_CFG_NUM_THREADS + 1]; + cnt_t isr_cnt; + /** + * @brief Lock nesting level. + */ + cnt_t lock_cnt; +#endif #if (NIL_DBG_ENABLED == TRUE) || defined(__DOXYGEN__) /** * @brief Panic message. @@ -428,12 +555,21 @@ struct nil_system { */ const char * volatile dbg_panic_msg; #endif + /** + * @brief Thread structures for all the defined threads. + */ + thread_t threads[CH_CFG_NUM_THREADS + 1]; }; /*===========================================================================*/ /* Module macros. */ /*===========================================================================*/ +#if CH_DBG_SYSTEM_STATE_CHECK == TRUE +#define _dbg_enter_lock() (nil.lock_cnt = (cnt_t)1) +#define _dbg_leave_lock() (nil.lock_cnt = (cnt_t)0) +#endif + /** * @name Threads tables definition macros * @{ @@ -442,7 +578,7 @@ struct nil_system { * @brief Start of user threads table. */ #define THD_TABLE_BEGIN \ - const thread_config_t nil_thd_configs[NIL_CFG_NUM_THREADS + 1] = { + const thread_config_t nil_thd_configs[CH_CFG_NUM_THREADS + 1] = { /** * @brief Entry of user threads table @@ -460,20 +596,53 @@ struct nil_system { /** @} */ /** - * @name Working Areas and Alignment + * @name Memory alignment support macros */ /** - * @brief Enforces a correct alignment for a stack area size value. + * @brief Alignment mask constant. * - * @param[in] n the stack size to be aligned to the next stack - * alignment boundary - * @return The aligned stack size. + * @param[in] a alignment, must be a power of two + */ +#define MEM_ALIGN_MASK(a) ((size_t)(a) - 1U) + +/** + * @brief Aligns to the previous aligned memory address. * - * @api + * @param[in] p variable to be aligned + * @param[in] a alignment, must be a power of two + */ +#define MEM_ALIGN_PREV(p, a) ((size_t)(p) & ~MEM_ALIGN_MASK(a)) + +/** + * @brief Aligns to the new aligned memory address. + * + * @param[in] p variable to be aligned + * @param[in] a alignment, must be a power of two + */ +#define MEM_ALIGN_NEXT(p, a) MEM_ALIGN_PREV((size_t)(p) + \ + MEM_ALIGN_MASK(a), (a)) + +/** + * @brief Returns whatever a pointer or memory size is aligned. + * + * @param[in] p variable to be aligned + * @param[in] a alignment, must be a power of two + */ +#define MEM_IS_ALIGNED(p, a) (((size_t)(p) & MEM_ALIGN_MASK(a)) == 0U) + +/** + * @brief Returns whatever a constant is a valid alignment. + * @details Valid alignments are powers of two. + * + * @param[in] a alignment to be checked, must be a constant */ -#define THD_ALIGN_STACK_SIZE(n) \ - ((((n) - 1U) | (sizeof(stkalign_t) - 1U)) + 1U) +#define MEM_IS_VALID_ALIGNMENT(a) \ + (((size_t)(a) != 0U) && (((size_t)(a) & ((size_t)(a) - 1U)) == 0U)) +/** @} */ +/** + * @name Working Areas + */ /** * @brief Calculates the total Working Area size. * @@ -482,8 +651,8 @@ struct nil_system { * * @api */ -#define THD_WORKING_AREA_SIZE(n) \ - THD_ALIGN_STACK_SIZE(PORT_WA_SIZE(n)) +#define THD_WORKING_AREA_SIZE(n) MEM_ALIGN_NEXT(PORT_WA_SIZE(n), \ + PORT_STACK_ALIGN) /** * @brief Static working area allocation. @@ -495,8 +664,7 @@ struct nil_system { * * @api */ -#define THD_WORKING_AREA(s, n) \ - stkalign_t s[THD_WORKING_AREA_SIZE(n) / sizeof(stkalign_t)] +#define THD_WORKING_AREA(s, n) PORT_WORKING_AREA(s, n) /** @} */ /** @@ -556,7 +724,9 @@ struct nil_system { * * @special */ -#define CH_IRQ_PROLOGUE() PORT_IRQ_PROLOGUE() +#define CH_IRQ_PROLOGUE() \ + PORT_IRQ_PROLOGUE(); \ + _dbg_check_enter_isr() /** * @brief IRQ handler exit code. @@ -564,7 +734,9 @@ struct nil_system { * * @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. @@ -605,7 +777,7 @@ struct nil_system { * @api */ #define S2ST(sec) \ - ((systime_t)((uint32_t)(sec) * (uint32_t)NIL_CFG_ST_FREQUENCY)) + ((systime_t)((uint32_t)(sec) * (uint32_t)CH_CFG_ST_FREQUENCY)) /** * @brief Milliseconds to system ticks. @@ -619,7 +791,7 @@ struct nil_system { */ #define MS2ST(msec) \ ((systime_t)(((((uint32_t)(msec)) * \ - ((uint32_t)NIL_CFG_ST_FREQUENCY)) + 999UL) / 1000UL)) + ((uint32_t)CH_CFG_ST_FREQUENCY)) + 999UL) / 1000UL)) /** * @brief Microseconds to system ticks. @@ -633,7 +805,7 @@ struct nil_system { */ #define US2ST(usec) \ ((systime_t)(((((uint32_t)(usec)) * \ - ((uint32_t)NIL_CFG_ST_FREQUENCY)) + 999999UL) / 1000000UL)) + ((uint32_t)CH_CFG_ST_FREQUENCY)) + 999999UL) / 1000000UL)) /** @} */ /** @@ -701,32 +873,67 @@ struct nil_system { #endif /** - * @brief Enters the kernel lock mode. + * @brief Raises the system interrupt priority mask to the maximum level. + * @details All the maskable interrupt sources are disabled regardless their + * hardware priority. + * @note Do not invoke this API from within a kernel lock. * * @special */ -#define chSysDisable() port_disable() +#define chSysDisable() { \ + port_disable(); \ + _dbg_check_disable(); \ +} /** - * @brief Enters the kernel lock mode. + * @brief Raises the system interrupt priority mask to system level. + * @details The interrupt sources that should not be able to preempt the kernel + * are disabled, interrupt sources with higher priority are still + * enabled. + * @note Do not invoke this API from within a kernel lock. + * @note This API is no replacement for @p chSysLock(), the @p chSysLock() + * could do more than just disable the interrupts. * * @special */ -#define chSysEnable() port_enable() +#define chSysSuspend() { \ + port_suspend(); \ + _dbg_check_suspend(); \ +} + +/** + * @brief Lowers the system interrupt priority mask to user level. + * @details All the interrupt sources are enabled. + * @note Do not invoke this API from within a kernel lock. + * @note This API is no replacement for @p chSysUnlock(), the + * @p chSysUnlock() could do more than just enable the interrupts. + * + * @special + */ +#define chSysEnable() { \ + _dbg_check_enable(); \ + port_enable(); \ +} /** * @brief Enters the kernel lock state. * * @special */ -#define chSysLock() port_lock() +#define chSysLock() { \ + port_lock(); \ + _dbg_check_lock(); \ +} /** * @brief Leaves the kernel lock state. * * @special */ -#define chSysUnlock() port_unlock() +#define chSysUnlock() { \ + _dbg_check_unlock(); \ + port_unlock(); \ +} /** * @brief Enters the kernel lock state from within an interrupt handler. @@ -740,7 +947,10 @@ struct nil_system { * * @special */ -#define chSysLockFromISR() port_lock_from_isr() +#define chSysLockFromISR() { \ + port_lock_from_isr(); \ + _dbg_check_lock_from_isr(); \ +} /** * @brief Leaves the kernel lock state from within an interrupt handler. @@ -755,7 +965,10 @@ struct nil_system { * * @special */ -#define chSysUnlockFromISR() port_unlock_from_isr() +#define chSysUnlockFromISR() { \ + _dbg_check_unlock_from_isr(); \ + port_unlock_from_isr(); \ +} /** * @brief Evaluates if a reschedule is required. @@ -834,6 +1047,7 @@ struct nil_system { (void) chSchGoSleepTimeoutS(NIL_STATE_SLEEPING, (abstime) - \ chVTGetSystemTimeX()) +#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__) /** * @brief Initializes a semaphore with the specified counter value. * @@ -873,12 +1087,34 @@ struct nil_system { */ #define chSemWaitS(sp) chSemWaitTimeoutS(sp, TIME_INFINITE) +/** + * @brief Decreases the semaphore counter. + * @details This macro can be used when the counter is known to be positive. + * + * @param[in] sp pointer to a @p semaphore_t structure + * + * @iclass + */ +#define chSemFastWaitI(sp) ((sp)->cnt--) + +/** + * @brief Increases the semaphore counter. + * @details This macro can be used when the counter is known to be not + * negative. + * + * @param[in] sp pointer to a @p semaphore_t structure + * + * @iclass + */ +#define chSemFastSignalI(sp) ((sp)->cnt++) + /** * @brief Returns the semaphore counter current value. * * @iclass */ #define chSemGetCounterI(sp) ((sp)->cnt) +#endif /* CH_CFG_USE_SEMAPHORES == TRUE */ /** * @brief Current system time. @@ -893,7 +1129,7 @@ struct nil_system { * * @xclass */ -#if (NIL_CFG_ST_TIMEDELTA == 0) || defined(__DOXYGEN__) +#if (CH_CFG_ST_TIMEDELTA == 0) || defined(__DOXYGEN__) #define chVTGetSystemTimeX() (nil.systime) #else #define chVTGetSystemTimeX() port_timer_get_time() @@ -927,12 +1163,34 @@ struct nil_system { #define chVTIsTimeWithinX(time, start, end) \ ((bool)((systime_t)((time) - (start)) < (systime_t)((end) - (start)))) +/** + * @brief Function parameters check. + * @details If the condition check fails then the kernel panics and halts. + * @note The condition is tested only if the @p CH_DBG_ENABLE_CHECKS switch + * is specified in @p chconf.h else the macro does nothing. + * + * @param[in] c the condition to be verified to be true + * + * @api + */ +#if !defined(chDbgCheck) +#define chDbgCheck(c) do { \ + /*lint -save -e506 -e774 [2.1, 14.3] Can be a constant by design.*/ \ + if (CH_DBG_ENABLE_CHECKS != FALSE) { \ + if (!(c)) { \ + /*lint -restore*/ \ + chSysHalt(__func__); \ + } \ + } \ +} while (false) +#endif /* !defined(chDbgCheck) */ + /** * @brief Condition assertion. * @details If the condition check fails then the kernel panics with a * message and halts. - * @note The condition is tested only if the @p NIL_CFG_ENABLE_ASSERTS - * switch is specified in @p nilconf.h else the macro does nothing. + * @note The condition is tested only if the @p CH_DBG_ENABLE_ASSERTS + * switch is specified in @p chconf.h else the macro does nothing. * @note The remark string is not currently used except for putting a * comment in the code about the assertion. * @@ -944,7 +1202,7 @@ struct nil_system { #if !defined(chDbgAssert) #define chDbgAssert(c, r) do { \ /*lint -save -e506 -e774 [2.1, 14.3] Can be a constant by design.*/ \ - if (NIL_CFG_ENABLE_ASSERTS != FALSE) { \ + if (CH_DBG_ENABLE_ASSERTS != FALSE) { \ if (!(c)) { \ /*lint -restore*/ \ chSysHalt(__func__); \ @@ -954,13 +1212,33 @@ struct nil_system { #endif /* !defined(chDbgAssert) */ /** @} */ +/* Empty macros if the state checker is not enabled.*/ +#if CH_DBG_SYSTEM_STATE_CHECK == FALSE +#define _dbg_enter_lock() +#define _dbg_leave_lock() +#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 + /*===========================================================================*/ /* External declarations. */ /*===========================================================================*/ #if !defined(__DOXYGEN__) +#if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || defined(__DOXYGEN__) +extern stkalign_t __main_thread_stack_base__, __main_thread_stack_end__; +#endif extern nil_system_t nil; -extern const thread_config_t nil_thd_configs[NIL_CFG_NUM_THREADS + 1]; +extern const thread_config_t nil_thd_configs[CH_CFG_NUM_THREADS + 1]; #endif #ifdef __cplusplus @@ -976,28 +1254,50 @@ extern "C" { void chSysPolledDelayX(rtcnt_t cycles); void chSysRestoreStatusX(syssts_t sts); thread_t *chSchReadyI(thread_t *tp, msg_t msg); + bool chSchIsPreemptionRequired(void); + void chSchDoReschedule(void); void chSchRescheduleS(void); msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t timeout); msg_t chThdSuspendTimeoutS(thread_reference_t *trp, systime_t timeout); void chThdResumeI(thread_reference_t *trp, msg_t msg); void chThdSleep(systime_t timeout); void chThdSleepUntil(systime_t abstime); +#if CH_CFG_USE_SEMAPHORES == TRUE msg_t chSemWaitTimeout(semaphore_t *sp, systime_t timeout); msg_t chSemWaitTimeoutS(semaphore_t *sp, systime_t timeout); void chSemSignal(semaphore_t *sp); void chSemSignalI(semaphore_t *sp); void chSemReset(semaphore_t *sp, cnt_t n); void chSemResetI(semaphore_t *sp, cnt_t n); -#if NIL_CFG_USE_EVENTS == TRUE +#endif /* CH_CFG_USE_SEMAPHORES == TRUE */ +#if CH_CFG_USE_EVENTS == TRUE void chEvtSignal(thread_t *tp, eventmask_t mask); void chEvtSignalI(thread_t *tp, eventmask_t mask); eventmask_t chEvtWaitAnyTimeout(eventmask_t mask, systime_t timeout); - eventmask_t chEvtWaitAnyTimeoutS(eventmask_t mask, systime_t timeout); +#endif +#if CH_DBG_SYSTEM_STATE_CHECK == TRUE + 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 #ifdef __cplusplus } #endif -#endif /* _NIL_H_ */ +/* Optional subsystems.*/ +#include "chmboxes.h" +#include "chmemcore.h" +#include "chmempools.h" +#include "chheap.h" + +#endif /* _CH_H_ */ /** @} */ diff --git a/os/nil/nil.mk b/os/nil/nil.mk index 51f0e8083..496100648 100644 --- a/os/nil/nil.mk +++ b/os/nil/nil.mk @@ -1,5 +1,28 @@ -# List of all the ChibiOS/NIL kernel files. -KERNSRC = ${CHIBIOS}/os/nil/src/nil.c +# List of all the ChibiOS/NIL kernel files, there is no need to remove the files +# from this list, you can disable parts of the kernel by editing chconf.h. +ifeq ($(USE_SMART_BUILD),yes) +CHCONF := $(strip $(shell cat chconf.h | egrep -e "define")) +KERNSRC := ${CHIBIOS}/os/nil/src/ch.c +ifneq ($(findstring CH_CFG_USE_MAILBOXES TRUE,$(CHCONF)),) +KERNSRC += $(CHIBIOS)/os/common/oslib/src/chmboxes.c +endif +ifneq ($(findstring CH_CFG_USE_MEMCORE TRUE,$(CHCONF)),) +KERNSRC += $(CHIBIOS)/os/common/oslib/src/chmemcore.c +endif +ifneq ($(findstring CH_CFG_USE_HEAP TRUE,$(CHCONF)),) +KERNSRC += $(CHIBIOS)/os/common/oslib/src/chheap.c +endif +ifneq ($(findstring CH_CFG_USE_MEMPOOLS TRUE,$(CHCONF)),) +KERNSRC += $(CHIBIOS)/os/common/oslib/src/chmempools.c +endif +else +KERNSRC := ${CHIBIOS}/os/nil/src/ch.c \ + ${CHIBIOS}/os/common/oslib/src/chmboxes.c \ + ${CHIBIOS}/os/common/oslib/src/chmemcore.c \ + ${CHIBIOS}/os/common/oslib/src/chmempools.c \ + ${CHIBIOS}/os/common/oslib/src/chheap.c +endif # Required include directories -KERNINC = ${CHIBIOS}/os/nil/include +KERNINC := ${CHIBIOS}/os/nil/include \ + ${CHIBIOS}/os/common/oslib/include diff --git a/os/nil/src/ch.c b/os/nil/src/ch.c index 0db75db37..29ec1af5c 100644 --- a/os/nil/src/ch.c +++ b/os/nil/src/ch.c @@ -18,14 +18,14 @@ */ /** - * @file nil.c + * @file ch.c * @brief Nil RTOS main source file. * * @addtogroup NIL_KERNEL * @{ */ -#include "nil.h" +#include "ch.h" /*===========================================================================*/ /* Module local definitions. */ @@ -56,6 +56,156 @@ nil_system_t nil; /* Module exported functions. */ /*===========================================================================*/ +#if (CH_DBG_SYSTEM_STATE_CHECK == TRUE) || defined(__DOXYGEN__) +/** + * @brief Guard code for @p chSysDisable(). + * + * @notapi + */ +void _dbg_check_disable(void) { + + if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) { + chSysHalt("SV#1"); + } +} + +/** + * @brief Guard code for @p chSysSuspend(). + * + * @notapi + */ +void _dbg_check_suspend(void) { + + if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) { + chSysHalt("SV#2"); + } +} + +/** + * @brief Guard code for @p chSysEnable(). + * + * @notapi + */ +void _dbg_check_enable(void) { + + if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) { + chSysHalt("SV#3"); + } +} + +/** + * @brief Guard code for @p chSysLock(). + * + * @notapi + */ +void _dbg_check_lock(void) { + + if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) { + chSysHalt("SV#4"); + } + _dbg_enter_lock(); +} + +/** + * @brief Guard code for @p chSysUnlock(). + * + * @notapi + */ +void _dbg_check_unlock(void) { + + if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt <= (cnt_t)0)) { + chSysHalt("SV#5"); + } + _dbg_leave_lock(); +} + +/** + * @brief Guard code for @p chSysLockFromIsr(). + * + * @notapi + */ +void _dbg_check_lock_from_isr(void) { + + if ((nil.isr_cnt <= (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) { + chSysHalt("SV#6"); + } + _dbg_enter_lock(); +} + +/** + * @brief Guard code for @p chSysUnlockFromIsr(). + * + * @notapi + */ +void _dbg_check_unlock_from_isr(void) { + + if ((nil.isr_cnt <= (cnt_t)0) || (nil.lock_cnt <= (cnt_t)0)) { + chSysHalt("SV#7"); + } + _dbg_leave_lock(); +} + +/** + * @brief Guard code for @p CH_IRQ_PROLOGUE(). + * + * @notapi + */ +void _dbg_check_enter_isr(void) { + + port_lock_from_isr(); + if ((nil.isr_cnt < (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) { + chSysHalt("SV#8"); + } + nil.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 ((nil.isr_cnt <= (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) { + chSysHalt("SV#9"); + } + nil.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 ((nil.isr_cnt < (cnt_t)0) || (nil.lock_cnt <= (cnt_t)0)) { + chSysHalt("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 ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt <= (cnt_t)0)) { + chSysHalt("SV#11"); + } +} +#endif /* CH_DBG_SYSTEM_STATE_CHECK == TRUE */ + /** * @brief Initializes the kernel. * @details Initializes the kernel structures, the current instructions flow @@ -71,43 +221,59 @@ void chSysInit(void) { thread_t *tp; const thread_config_t *tcp; - /* Port layer initialization.*/ - port_init(); +#if CH_DBG_SYSTEM_STATE_CHECK == TRUE + nil.isr_cnt = (cnt_t)0; + nil.lock_cnt = (cnt_t)0; +#endif /* System initialization hook.*/ - NIL_CFG_SYSTEM_INIT_HOOK(); + CH_CFG_SYSTEM_INIT_HOOK(); /* Iterates through the list of defined threads.*/ tp = &nil.threads[0]; tcp = nil_thd_configs; - while (tp < &nil.threads[NIL_CFG_NUM_THREADS]) { -#if NIL_CFG_ENABLE_STACK_CHECK - tp->stklim = (stkalign_t *)tcp->wbase; + while (tp < &nil.threads[CH_CFG_NUM_THREADS]) { +#if CH_DBG_ENABLE_STACK_CHECK + tp->stklimit = (stkalign_t *)tcp->wbase; #endif /* Port dependent thread initialization.*/ - PORT_SETUP_CONTEXT(tp, tcp->wend, tcp->funcp, tcp->arg); + PORT_SETUP_CONTEXT(tp, tcp->wbase, tcp->wend, tcp->funcp, tcp->arg); /* Initialization hook.*/ - NIL_CFG_THREAD_EXT_INIT_HOOK(tp); + CH_CFG_THREAD_EXT_INIT_HOOK(tp); tp++; tcp++; } -#if NIL_CFG_ENABLE_STACK_CHECK +#if CH_DBG_ENABLE_STACK_CHECK /* The idle thread is a special case because its stack is set up by the runtime environment.*/ - tp->stklim = THD_IDLE_BASE; + tp->stklimit = THD_IDLE_BASE; +#endif + + /* Interrupts partially enabled. It is equivalent to entering the + kernel critical zone.*/ + chSysSuspend(); +#if CH_DBG_SYSTEM_STATE_CHECK == TRUE + nil.lock_cnt = (cnt_t)1; +#endif + + /* Heap initialization, if enabled.*/ +#if CH_CFG_USE_HEAP == TRUE + _heap_init(); #endif + /* Port layer initialization last because it depend on some of the + initializations performed before.*/ + port_init(); + /* Runs the highest priority thread, the current one becomes the idle thread.*/ nil.current = nil.next = nil.threads; port_switch(nil.current, tp); - - /* Interrupts enabled for the idle thread.*/ - chSysEnable(); + chSysUnlock(); } /** @@ -132,7 +298,7 @@ void chSysHalt(const char *reason) { (void)reason; #endif - NIL_CFG_SYSTEM_HALT_HOOK(reason); + CH_CFG_SYSTEM_HALT_HOOK(reason); /* Harmless infinite loop.*/ while (true) { @@ -148,7 +314,9 @@ void chSysHalt(const char *reason) { */ void chSysTimerHandlerI(void) { -#if NIL_CFG_ST_TIMEDELTA == 0 + chDbgCheckClassI(); + +#if CH_CFG_ST_TIMEDELTA == 0 thread_t *tp = &nil.threads[0]; nil.systime++; do { @@ -177,7 +345,7 @@ void chSysTimerHandlerI(void) { chSysUnlockFromISR(); tp++; chSysLockFromISR(); - } while (tp < &nil.threads[NIL_CFG_NUM_THREADS]); + } while (tp < &nil.threads[CH_CFG_NUM_THREADS]); #else thread_t *tp = &nil.threads[0]; systime_t next = (systime_t)0; @@ -193,16 +361,20 @@ void chSysTimerHandlerI(void) { tp->timeout -= nil.nexttime - nil.lasttime; if (tp->timeout == (systime_t)0) { +#if CH_CFG_USE_SEMAPHORES == TRUE /* Timeout on semaphores requires a special handling because the semaphore counter must be incremented.*/ - /*lint -save -e9013 [15.7] There is no else because it is not needed.*/ - if (NIL_THD_IS_WTSEM(tp)) { + if (NIL_THD_IS_WTSEM(tp)) { tp->u1.semp->cnt++; } - else if (NIL_THD_IS_SUSP(tp)) { - *tp->u1.trp = NULL; + else { +#endif + if (NIL_THD_IS_SUSP(tp)) { + *tp->u1.trp = NULL; + } +#if CH_CFG_USE_SEMAPHORES == TRUE } - /*lint -restore*/ +#endif (void) chSchReadyI(tp, MSG_TIMEOUT); } else { @@ -216,7 +388,7 @@ void chSysTimerHandlerI(void) { chSysUnlockFromISR(); tp++; chSysLockFromISR(); - } while (tp < &nil.threads[NIL_CFG_NUM_THREADS]); + } while (tp < &nil.threads[CH_CFG_NUM_THREADS]); nil.lasttime = nil.nexttime; if (next > (systime_t)0) { nil.nexttime += next; @@ -270,7 +442,7 @@ void chSysUnconditionalUnlock(void) { * * @xclass */ -syssts_t chSysGetStatusAndLockX(void) { +syssts_t chSysGetStatusAndLockX(void) { syssts_t sts = port_get_irq_status(); if (port_irq_enabled(sts)) { @@ -360,9 +532,8 @@ void chSysPolledDelayX(rtcnt_t cycles) { */ thread_t *chSchReadyI(thread_t *tp, msg_t msg) { - chDbgAssert((tp >= nil.threads) && - (tp < &nil.threads[NIL_CFG_NUM_THREADS]), - "pointer out of range"); + chDbgCheckClassI(); + chDbgCheck((tp >= nil.threads) && (tp < &nil.threads[CH_CFG_NUM_THREADS])); chDbgAssert(!NIL_THD_IS_READY(tp), "already ready"); chDbgAssert(nil.next <= nil.current, "priority ordering"); @@ -375,6 +546,41 @@ thread_t *chSchReadyI(thread_t *tp, msg_t msg) { return tp; } +/** + * @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 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 must go in running state + * immediately. + * @retval false if preemption is not required. + * + * @special + */ +bool chSchIsPreemptionRequired(void) { + + return chSchIsRescRequiredI(); +} + +/** + * @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 + */ +void chSchDoReschedule(void) { + thread_t *otp = nil.current; + + nil.current = nil.next; + if (otp == &nil.threads[CH_CFG_NUM_THREADS]) { + CH_CFG_IDLE_LEAVE_HOOK(); + } + port_switch(nil.next, otp); +} + /** * @brief Reschedules if needed. * @@ -382,14 +588,10 @@ thread_t *chSchReadyI(thread_t *tp, msg_t msg) { */ void chSchRescheduleS(void) { - if (chSchIsRescRequiredI()) { - thread_t *otp = nil.current; + chDbgCheckClassS(); - nil.current = nil.next; - if (otp == &nil.threads[NIL_CFG_NUM_THREADS]) { - NIL_CFG_IDLE_LEAVE_HOOK(); - } - port_switch(nil.next, otp); + if (chSchIsRescRequiredI()) { + chSchDoReschedule(); } } @@ -413,20 +615,22 @@ void chSchRescheduleS(void) { msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t timeout) { thread_t *ntp, *otp = nil.current; - chDbgAssert(otp != &nil.threads[NIL_CFG_NUM_THREADS], + chDbgCheckClassS(); + + chDbgAssert(otp != &nil.threads[CH_CFG_NUM_THREADS], "idle cannot sleep"); /* Storing the wait object for the current thread.*/ otp->state = newstate; -#if NIL_CFG_ST_TIMEDELTA > 0 +#if CH_CFG_ST_TIMEDELTA > 0 if (timeout != TIME_INFINITE) { systime_t abstime; /* TIMEDELTA makes sure to have enough time to reprogram the timer before the free-running timer counter reaches the selected timeout.*/ - if (timeout < (systime_t)NIL_CFG_ST_TIMEDELTA) { - timeout = (systime_t)NIL_CFG_ST_TIMEDELTA; + if (timeout < (systime_t)CH_CFG_ST_TIMEDELTA) { + timeout = (systime_t)CH_CFG_ST_TIMEDELTA; } /* Absolute time of the timeout event.*/ @@ -461,8 +665,8 @@ msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t timeout) { /* Is this thread ready to execute?*/ if (NIL_THD_IS_READY(ntp)) { nil.current = nil.next = ntp; - if (ntp == &nil.threads[NIL_CFG_NUM_THREADS]) { - NIL_CFG_IDLE_ENTER_HOOK(); + if (ntp == &nil.threads[CH_CFG_NUM_THREADS]) { + CH_CFG_IDLE_ENTER_HOOK(); } port_switch(ntp, otp); return nil.current->u1.msg; @@ -470,7 +674,7 @@ msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t timeout) { /* Points to the next thread in lowering priority order.*/ ntp++; - chDbgAssert(ntp <= &nil.threads[NIL_CFG_NUM_THREADS], + chDbgAssert(ntp <= &nil.threads[CH_CFG_NUM_THREADS], "pointer out of range"); } } @@ -549,6 +753,7 @@ void chThdSleepUntil(systime_t abstime) { chSysUnlock(); } +#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__) /** * @brief Performs a wait operation on a semaphore with timeout specification. * @@ -599,6 +804,9 @@ msg_t chSemWaitTimeout(semaphore_t *sp, systime_t timeout) { */ msg_t chSemWaitTimeoutS(semaphore_t *sp, systime_t timeout) { + chDbgCheckClassS(); + chDbgCheck(sp != NULL); + /* Note, the semaphore counter is a volatile variable so accesses are manually optimized.*/ cnt_t cnt = sp->cnt; @@ -646,6 +854,9 @@ void chSemSignal(semaphore_t *sp) { */ void chSemSignalI(semaphore_t *sp) { + chDbgCheckClassI(); + chDbgCheck(sp != NULL); + if (++sp->cnt <= (cnt_t)0) { thread_reference_t tr = nil.threads; while (true) { @@ -659,7 +870,7 @@ void chSemSignalI(semaphore_t *sp) { } tr++; - chDbgAssert(tr < &nil.threads[NIL_CFG_NUM_THREADS], + chDbgAssert(tr < &nil.threads[CH_CFG_NUM_THREADS], "pointer out of range"); } } @@ -709,12 +920,15 @@ void chSemResetI(semaphore_t *sp, cnt_t n) { thread_t *tp; cnt_t cnt; + chDbgCheckClassI(); + chDbgCheck((sp != NULL) && (n >= (cnt_t)0)); + cnt = sp->cnt; sp->cnt = n; tp = nil.threads; while (cnt < (cnt_t)0) { - chDbgAssert(tp < &nil.threads[NIL_CFG_NUM_THREADS], + chDbgAssert(tp < &nil.threads[CH_CFG_NUM_THREADS], "pointer out of range"); /* Is this thread waiting on this semaphore?*/ @@ -729,7 +943,6 @@ void chSemResetI(semaphore_t *sp, cnt_t n) { } } -#if (NIL_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__) /** * @brief Adds a set of event flags directly to the specified @p thread_t. * @@ -745,7 +958,9 @@ void chEvtSignal(thread_t *tp, eventmask_t mask) { chSchRescheduleS(); chSysUnlock(); } +#endif /* CH_CFG_USE_SEMAPHORES == TRUE */ +#if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__) /** * @brief Adds a set of event flags directly to the specified @p thread_t. * @post This function does not reschedule so a call to a rescheduling @@ -760,6 +975,9 @@ void chEvtSignal(thread_t *tp, eventmask_t mask) { */ void chEvtSignalI(thread_t *tp, eventmask_t mask) { + chDbgCheckClassI(); + chDbgCheck(tp != NULL); + tp->epmask |= mask; if (NIL_THD_IS_WTOREVT(tp) && ((tp->epmask & tp->u1.ewmask) != (eventmask_t)0)) { @@ -786,37 +1004,10 @@ void chEvtSignalI(thread_t *tp, eventmask_t mask) { * @api */ eventmask_t chEvtWaitAnyTimeout(eventmask_t mask, systime_t timeout) { - eventmask_t m; - - chSysLock(); - m = chEvtWaitAnyTimeoutS(mask, timeout); - chSysUnlock(); - - return m; -} - -/** - * @brief Waits for any of the specified events. - * @details The function waits for any event among those specified in - * @p mask to become pending then the events are cleared and - * returned. - * - * @param[in] mask mask of the event flags that the function should wait - * for, @p ALL_EVENTS enables all the events - * @param[in] timeout the number of ticks before the operation timeouts, - * the following special values are allowed: - * - @a TIME_IMMEDIATE immediate timeout. - * - @a TIME_INFINITE no timeout. - * . - * @return The mask of the served and cleared events. - * @retval 0 if the operation has timed out. - * - * @sclass - */ -eventmask_t chEvtWaitAnyTimeoutS(eventmask_t mask, systime_t timeout) { thread_t *ctp = nil.current; eventmask_t m; + chSysLock(); if ((m = (ctp->epmask & mask)) == (eventmask_t)0) { if (TIME_IMMEDIATE == timeout) { chSysUnlock(); @@ -832,9 +1023,10 @@ eventmask_t chEvtWaitAnyTimeoutS(eventmask_t mask, systime_t timeout) { m = ctp->epmask & mask; } ctp->epmask &= ~m; + chSysUnlock(); return m; } -#endif /* NIL_CFG_USE_EVENTS == TRUE */ +#endif /* CH_CFG_USE_EVENTS == TRUE */ /** @} */ -- cgit v1.2.3