From feb3e92fbac53b1105dae10c770fb730b32721ea Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Wed, 6 Feb 2019 16:26:22 +0000 Subject: [PATCH] Experimental NIL expansion. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@12639 110e8d01-0319-4d1e-a829-52ad28d1bb01 --- demos/STM32/NIL-STM32F303-DISCOVERY/Makefile | 2 +- .../NIL-STM32L476-DISCOVERY/cfg/chconf.h | 9 + os/nil/include/ch.h | 517 ++++-------------- os/nil/include/chevt.h | 87 +++ os/nil/include/chmsg.h | 103 ++++ os/nil/include/chsem.h | 146 +++++ os/nil/nil.mk | 15 +- os/nil/src/ch.c | 322 +---------- os/nil/src/chevt.c | 183 +++++++ os/nil/src/chmsg.c | 133 +++++ os/nil/src/chsem.c | 218 ++++++++ test/lib/ch_test.c | 17 + 12 files changed, 1039 insertions(+), 713 deletions(-) create mode 100644 os/nil/include/chevt.h create mode 100644 os/nil/include/chmsg.h create mode 100644 os/nil/include/chsem.h create mode 100644 os/nil/src/chevt.c create mode 100644 os/nil/src/chmsg.c create mode 100644 os/nil/src/chsem.c diff --git a/demos/STM32/NIL-STM32F303-DISCOVERY/Makefile b/demos/STM32/NIL-STM32F303-DISCOVERY/Makefile index 631095137..bca2377d7 100644 --- a/demos/STM32/NIL-STM32F303-DISCOVERY/Makefile +++ b/demos/STM32/NIL-STM32F303-DISCOVERY/Makefile @@ -5,7 +5,7 @@ # Compiler options here. ifeq ($(USE_OPT),) - USE_OPT = -O0 -ggdb -fomit-frame-pointer -falign-functions=16 + USE_OPT = -O2 -ggdb -fomit-frame-pointer -falign-functions=16 endif # C specific options here (added to USE_OPT). diff --git a/demos/STM32/NIL-STM32L476-DISCOVERY/cfg/chconf.h b/demos/STM32/NIL-STM32L476-DISCOVERY/cfg/chconf.h index e0dca22c5..bd2e50a45 100644 --- a/demos/STM32/NIL-STM32L476-DISCOVERY/cfg/chconf.h +++ b/demos/STM32/NIL-STM32L476-DISCOVERY/cfg/chconf.h @@ -130,6 +130,15 @@ */ #define CH_CFG_USE_EVENTS TRUE +/** + * @brief Synchronous Messages APIs. + * @details If enabled then the synchronous messages APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#define CH_CFG_USE_MESSAGES TRUE + /** * @brief Mailboxes APIs. * @details If enabled then the asynchronous messages (mailboxes) APIs are diff --git a/os/nil/include/ch.h b/os/nil/include/ch.h index 75a89766f..fb98aedad 100644 --- a/os/nil/include/ch.h +++ b/os/nil/include/ch.h @@ -31,8 +31,6 @@ #define CH_H #include "chtypes.h" -#include "chconf.h" -#include "chlicense.h" /*===========================================================================*/ /* Module constants. */ @@ -147,7 +145,11 @@ #define NIL_STATE_WTQUEUE (tstate_t)5 /**< @brief On queue or semaph. */ #define NIL_STATE_WTOREVT (tstate_t)6 /**< @brief Waiting for events. */ #define NIL_STATE_WTANDEVT (tstate_t)7 /**< @brief Waiting for events. */ -#define NIL_STATE_FINAL (tstate_t)8 /**< @brief Thread terminated. */ +#define NIL_STATE_SNDMSGQ (tstate_t)8 /**< @brief Sending a message, + in queue. */ +#define NIL_STATE_WTMSG (tstate_t)10/**< @brief Waiting for a + message. */ +#define NIL_STATE_FINAL (tstate_t)11/**< @brief Thread terminated. */ #define NIL_THD_IS_WTSTART(tp) ((tp)->state == NIL_STATE_WTSTART) #define NIL_THD_IS_READY(tp) ((tp)->state == NIL_STATE_READY) @@ -157,343 +159,115 @@ #define NIL_THD_IS_WTQUEUE(tp) ((tp)->state == NIL_STATE_WTQUEUE) #define NIL_THD_IS_WTOREVT(tp) ((tp)->state == NIL_STATE_WTOREVT) #define NIL_THD_IS_WTANDEVT(tp) ((tp)->state == NIL_STATE_WTANDEVT) +#define NIL_THD_IS_SNDMSGQ(tp) ((tp)->state == NIL_STATE_SNDMSGQ) +#define NIL_THD_IS_WTMSG(tp) ((tp)->state == NIL_STATE_WTMSG) #define NIL_THD_IS_FINAL(tp) ((tp)->state == NIL_STATE_FINAL) #define CH_STATE_NAMES \ "WTSTART", "READY", "SLEEPING", "SUSPENDED", "WTEXIT", "WTQUEUE", \ - "WTOREVT", "WTANDEVT", "FINAL" -/** @} */ - -/** - * @name Events related macros - * @{ - */ -/** - * @brief All events allowed mask. - */ -#define ALL_EVENTS ((eventmask_t)-1) - -/** - * @brief Returns an event mask from an event identifier. - */ -#define EVENT_MASK(eid) ((eventmask_t)(1 << (eid))) + "WTOREVT", "WTANDEVT", "SNDMSGQ", "SNDMSG", "WTMSG", "FINAL" /** @} */ /*===========================================================================*/ /* Module pre-compile time settings. */ /*===========================================================================*/ -/*-* - * @brief Maximum number of user threads in the application. - * @note This number is not inclusive of the idle thread which is - * implicitly handled. - * @note Set this value to be exactly equal to the number of threads you - * will use or you would be wasting RAM and cycles. - * @note This values also defines the number of available priorities - * (0..CH_CFG_MAX_THREADS-1). - */ -#if !defined(CH_CFG_MAX_THREADS) || defined(__DOXYGEN__) -#define CH_CFG_MAX_THREADS 2 -#endif - -/*-* - * @brief Auto starts threads when @p chSysInit() is invoked. - */ -#if !defined(CH_CFG_AUTOSTART_THREADS) || defined(__DOXYGEN__) -#define CH_CFG_AUTOSTART_THREADS TRUE -#endif - -/*-* - * @brief System time counter resolution. - * @note Allowed values are 16 or 32 bits. - */ -#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 CH_CFG_ST_RESOLUTION - * option defines the maximum amount of time allowed for - * timeouts. - */ -#if !defined(CH_CFG_ST_FREQUENCY) || defined(__DOXYGEN__) -#define CH_CFG_ST_FREQUENCY 100 -#endif - -/*-* - * @brief Time delta constant for the tick-less mode. - * @note If this value is zero then the system uses the classic - * periodic tick. This value represents the minimum number - * of ticks that is safe to specify in a timeout directive. - * The value one is not valid, timeouts are rounded up to - * this value. - */ -#if !defined(CH_CFG_ST_TIMEDELTA) || defined(__DOXYGEN__) -#define CH_CFG_ST_TIMEDELTA 0 -#endif - -/*-* - * @brief Threads synchronization APIs. - * @details If enabled then the @p chThdWait() function is included in - * the kernel. - * - * @note The default is @p TRUE. - */ -#if !defined(CH_CFG_USE_WAITEXIT) -#define CH_CFG_USE_WAITEXIT TRUE -#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 - -/*-* - * @brief Events Flags APIs. - * @details If enabled then the event flags APIs are included in the kernel. - * - * @note The default is @p 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 Objects Factory APIs. - * @details If enabled then the objects factory APIs are included in the - * kernel. - * - * @note The default is @p FALSE. - */ -#if !defined(CH_CFG_USE_FACTORY) || defined(__DOXYGEN__) -#define CH_CFG_USE_FACTORY TRUE -#endif - -/*-* - * @brief Maximum length for object names. - * @details If the specified length is zero then the name is stored by - * pointer but this could have unintended side effects. - */ -#if !defined(CH_CFG_FACTORY_MAX_NAMES_LENGTH) || defined(__DOXYGEN__) -#define CH_CFG_FACTORY_MAX_NAMES_LENGTH 8 -#endif - -/*-* - * @brief Enables the registry of generic objects. - */ -#if !defined(CH_CFG_FACTORY_OBJECTS_REGISTRY) || defined(__DOXYGEN__) -#define CH_CFG_FACTORY_OBJECTS_REGISTRY TRUE -#endif - -/*-* - * @brief Enables factory for generic buffers. - */ -#if !defined(CH_CFG_FACTORY_GENERIC_BUFFERS) || defined(__DOXYGEN__) -#define CH_CFG_FACTORY_GENERIC_BUFFERS TRUE -#endif - -/*-* - * @brief Enables factory for semaphores. - */ -#if !defined(CH_CFG_FACTORY_SEMAPHORES) || defined(__DOXYGEN__) -#define CH_CFG_FACTORY_SEMAPHORES TRUE -#endif - -/*-* - * @brief Enables factory for mailboxes. - */ -#if !defined(CH_CFG_FACTORY_MAILBOXES) || defined(__DOXYGEN__) -#define CH_CFG_FACTORY_MAILBOXES TRUE -#endif - -/*-* - * @brief Enables factory for objects FIFOs. - */ -#if !defined(CH_CFG_FACTORY_OBJ_FIFOS) || defined(__DOXYGEN__) -#define CH_CFG_FACTORY_OBJ_FIFOS TRUE -#endif - -/*-* - * @brief Pipes APIs. - * @details If enabled then the pipes APIs are included - * in the kernel. - * - * @note The default is @p TRUE. - */ -#if !defined(CH_CFG_USE_PIPES) || defined(__DOXYGEN__) -#define CH_CFG_USE_PIPES 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(CH_DBG_ENABLE_ASSERTS) || defined(__DOXYGEN__) -#define CH_DBG_ENABLE_ASSERTS FALSE -#endif - -/*-* - * @brief Stack check. - * - * @note The default is @p FALSE. - */ -#if !defined(CH_DBG_ENABLE_STACK_CHECK) || defined(__DOXYGEN__) -#define CH_DBG_ENABLE_STACK_CHECK FALSE -#endif - -/*-* - * @brief System initialization 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(CH_CFG_THREAD_EXT_FIELDS) || defined(__DOXYGEN__) -#define CH_CFG_THREAD_EXT_FIELDS -#endif - -/*-* - * @brief Threads initialization hook. - */ -#if !defined(CH_CFG_THREAD_EXT_INIT_HOOK) || defined(__DOXYGEN__) -#define CH_CFG_THREAD_EXT_INIT_HOOK(tp) {} -#endif - -/*-* - * @brief Threads finalization hook. - * @details User finalization code added to the @p chThdExit() API. - */ -#if !defined(CH_CFG_THREAD_EXIT_HOOK) || defined(__DOXYGEN__) -#define CH_CFG_THREAD_EXIT_HOOK(tp) {} -#endif - -/*-* - * @brief Idle thread enter hook. - * @note This hook is invoked within a critical zone, no OS functions - * should be invoked from here. - * @note This macro can be used to activate a power saving mode. - */ -#if !defined(CH_CFG_IDLE_ENTER_HOOK) || defined(__DOXYGEN__) -#define CH_CFG_IDLE_ENTER_HOOK() {} -#endif - -/*-* - * @brief Idle thread leave hook. - * @note This hook is invoked within a critical zone, no OS functions - * should be invoked from here. - * @note This macro can be used to deactivate a power saving mode. - */ -#if !defined(CH_CFG_IDLE_LEAVE_HOOK) || defined(__DOXYGEN__) -#define CH_CFG_IDLE_LEAVE_HOOK() {} -#endif - -/*-* - * @brief System halt hook. - */ -#if !defined(CH_CFG_SYSTEM_HALT_HOOK) || defined(__DOXYGEN__) -#define CH_CFG_SYSTEM_HALT_HOOK(reason) {} -#endif +#include "chconf.h" +#include "chlicense.h" /*===========================================================================*/ /* Derived constants and error checks. */ /*===========================================================================*/ +/* Checks on configuration options.*/ +#if !defined(CH_CFG_MAX_THREADS) || defined(__DOXYGEN__) +#error "CH_CFG_MAX_THREADS not defined in chconf.h" +#endif + +#if !defined(CH_CFG_AUTOSTART_THREADS) || defined(__DOXYGEN__) +#error "CH_CFG_AUTOSTART_THREADS not defined in chconf.h" +#endif + +#if !defined(CH_CFG_ST_RESOLUTION) || defined(__DOXYGEN__) +#error "CH_CFG_ST_RESOLUTION not defined in chconf.h" +#endif + +#if !defined(CH_CFG_ST_FREQUENCY) || defined(__DOXYGEN__) +#error "CH_CFG_ST_FREQUENCY not defined in chconf.h" +#endif + +#if !defined(CH_CFG_ST_TIMEDELTA) || defined(__DOXYGEN__) +#error "CH_CFG_ST_TIMEDELTA not defined in chconf.h" +#endif + +#if !defined(CH_CFG_USE_WAITEXIT) +#error "CH_CFG_USE_WAITEXIT not defined in chconf.h" +#endif + +#if !defined(CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__) +#error "CH_CFG_USE_MESSAGES not defined in chconf.h" +#endif + +#if !defined(CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) +#error "CH_CFG_USE_SEMAPHORES not defined in chconf.h" +#endif + +#if !defined(CH_CFG_USE_EVENTS) +#error "CH_CFG_USE_EVENTS not defined in chconf.h" +#endif + +#if !defined(CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__) +#error "CH_CFG_USE_MUTEXES not defined in chconf.h" +#endif + +#if !defined(CH_DBG_STATISTICS) || defined(__DOXYGEN__) +#error "CH_DBG_STATISTICS not defined in chconf.h" +#endif + +#if !defined(CH_DBG_SYSTEM_STATE_CHECK) || defined(__DOXYGEN__) +#error "CH_DBG_SYSTEM_STATE_CHECK not defined in chconf.h" +#endif + +#if !defined(CH_DBG_ENABLE_CHECKS) || defined(__DOXYGEN__) +#error "CH_DBG_ENABLE_CHECKS not defined in chconf.h" +#endif + +#if !defined(CH_DBG_ENABLE_ASSERTS) || defined(__DOXYGEN__) +#error "CH_DBG_ENABLE_ASSERTS not defined in chconf.h" +#endif + +#if !defined(CH_DBG_ENABLE_STACK_CHECK) || defined(__DOXYGEN__) +#error "CH_DBG_ENABLE_STACK_CHECK not defined in chconf.h" +#endif + +#if !defined(CH_CFG_SYSTEM_INIT_HOOK) || defined(__DOXYGEN__) +#error "CH_CFG_SYSTEM_INIT_HOOK not defined in chconf.h" +#endif + +#if !defined(CH_CFG_THREAD_EXT_FIELDS) || defined(__DOXYGEN__) +#error "CH_CFG_THREAD_EXT_FIELDS not defined in chconf.h" +#endif + +#if !defined(CH_CFG_THREAD_EXT_INIT_HOOK) || defined(__DOXYGEN__) +#error "CH_CFG_THREAD_EXT_INIT_HOOK not defined in chconf.h" +#endif + +#if !defined(CH_CFG_THREAD_EXIT_HOOK) || defined(__DOXYGEN__) +#error "CH_CFG_THREAD_EXIT_HOOK not defined in chconf.h" +#endif + +#if !defined(CH_CFG_IDLE_ENTER_HOOK) || defined(__DOXYGEN__) +#error "CH_CFG_IDLE_ENTER_HOOK not defined in chconf.h" +#endif + +#if !defined(CH_CFG_IDLE_LEAVE_HOOK) || defined(__DOXYGEN__) +#error "CH_CFG_IDLE_LEAVE_HOOK not defined in chconf.h" +#endif + +#if !defined(CH_CFG_SYSTEM_HALT_HOOK) || defined(__DOXYGEN__) +#error "CH_CFG_SYSTEM_HALT_HOOK not defined in chconf.h" +#endif + /* License checks.*/ #if !defined(CH_CUSTOMER_LIC_NIL) || !defined(CH_LICENSE_FEATURES) #error "malformed chlicense.h" @@ -707,6 +481,9 @@ struct nil_thread { #if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__) eventmask_t epmask; /**< @brief Pending events mask. */ #endif +#if (CH_CFG_USE_MESSAGES == TRUE) || defined(__DOXYGEN__) + msg_t sntmsg; /**< @brief Sent message. */ +#endif #if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || defined(__DOXYGEN__) stkalign_t *wabase; /**< @brief Thread stack boundary. */ #endif @@ -1355,75 +1132,6 @@ struct nil_system { */ #define chThdQueueIsEmptyI(tqp) ((bool)(tqp->cnt >= (cnt_t)0)) -#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__) -/** - * @brief Initializes a semaphore with the specified counter value. - * - * @param[out] sp pointer to a @p semaphore_t structure - * @param[in] n initial value of the semaphore counter. Must be - * non-negative. - * - * @init - */ -#define chSemObjectInit(sp, n) ((sp)->cnt = n) - -/** - * @brief Performs a wait operation on a semaphore. - * - * @param[in] sp pointer to a @p semaphore_t structure - * @return A message specifying how the invoking thread has been - * released from the semaphore. - * @retval CH_MSG_OK if the thread has not stopped on the semaphore or the - * semaphore has been signaled. - * @retval CH_MSG_RST if the semaphore has been reset using @p chSemReset(). - * - * @api - */ -#define chSemWait(sp) chSemWaitTimeout(sp, TIME_INFINITE) - -/** - * @brief Performs a wait operation on a semaphore. - * - * @param[in] sp pointer to a @p semaphore_t structure - * @return A message specifying how the invoking thread has been - * released from the semaphore. - * @retval CH_MSG_OK if the thread has not stopped on the semaphore or the - * semaphore has been signaled. - * @retval CH_MSG_RST if the semaphore has been reset using @p chSemReset(). - * - * @sclass - */ -#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. * @details Returns the number of system ticks since the @p chSysInit() @@ -1576,6 +1284,8 @@ extern const thread_config_t nil_thd_configs[]; #ifdef __cplusplus extern "C" { #endif + thread_t *nil_find_thread(tstate_t state, void *p); + cnt_t nil_ready_all(void *p, cnt_t cnt, msg_t msg); void chSysInit(void); void chSysHalt(const char *reason); void chSysTimerHandlerI(void); @@ -1605,20 +1315,6 @@ extern "C" { void chThdDoDequeueNextI(threads_queue_t *tqp, msg_t msg); void chThdDequeueNextI(threads_queue_t *tqp, msg_t msg); void chThdDequeueAllI(threads_queue_t *tqp, msg_t msg); -#if CH_CFG_USE_SEMAPHORES == TRUE - msg_t chSemWaitTimeout(semaphore_t *sp, sysinterval_t timeout); - msg_t chSemWaitTimeoutS(semaphore_t *sp, sysinterval_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); -#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, sysinterval_t timeout); - eventmask_t chEvtWaitAllTimeout(eventmask_t mask, sysinterval_t timeout); -#endif #if CH_DBG_SYSTEM_STATE_CHECK == TRUE void _dbg_check_disable(void); void _dbg_check_suspend(void); @@ -1636,7 +1332,10 @@ extern "C" { } #endif -/* OSLIB.*/ +/* Optional modules.*/ +#include "chsem.h" +#include "chevt.h" +#include "chmsg.h" #include "chlib.h" #endif /* CH_H */ diff --git a/os/nil/include/chevt.h b/os/nil/include/chevt.h new file mode 100644 index 000000000..10309c462 --- /dev/null +++ b/os/nil/include/chevt.h @@ -0,0 +1,87 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio. + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file nil/include/chevt.h + * @brief Nil RTOS events header file. + * + * @addtogroup NIL_EVENTS + * @{ + */ + +#ifndef CHEVT_H +#define CHEVT_H + +#if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/** + * @name Events related macros + * @{ + */ +/** + * @brief All events allowed mask. + */ +#define ALL_EVENTS ((eventmask_t)-1) + +/** + * @brief Returns an event mask from an event identifier. + */ +#define EVENT_MASK(eid) ((eventmask_t)(1 << (eid))) +/** @} */ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void chEvtSignal(thread_t *tp, eventmask_t mask); + void chEvtSignalI(thread_t *tp, eventmask_t mask); + eventmask_t chEvtWaitAnyTimeout(eventmask_t mask, sysinterval_t timeout); + eventmask_t chEvtWaitAllTimeout(eventmask_t mask, sysinterval_t timeout); +#ifdef __cplusplus +} +#endif + +#endif /* CH_CFG_USE_EVENTS == TRUE */ + +#endif /* CHEVT_H */ + +/** @} */ diff --git a/os/nil/include/chmsg.h b/os/nil/include/chmsg.h new file mode 100644 index 000000000..b734645ca --- /dev/null +++ b/os/nil/include/chmsg.h @@ -0,0 +1,103 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio. + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file nil/include/chmsg.h + * @brief Nil RTOS synchronous messages header file. + * + * @addtogroup NIL_MESSAGES + * @{ + */ + +#ifndef CHMSG_H +#define CHMSG_H + +#if (CH_CFG_USE_MESSAGES == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/** + * @name Macro Functions + * @{ + */ +/** + * @brief Returns the message carried by the specified thread. + * @pre This function must be invoked immediately after exiting a call + * to @p chMsgWait(). + * + * @param[in] tp pointer to the thread + * @return The message carried by the sender. + * + * @api + */ +#define chMsgGet(tp) ((tp)->sntmsg) + +/** + * @brief Releases the thread waiting on top of the messages queue. + * @pre Invoke this function only after a message has been received + * using @p chMsgWait(). + * + * @param[in] tp pointer to the thread + * @param[in] msg message to be returned to the sender + * + * @sclass + */ +#define chMsgReleaseS(tp, msg) do { \ + chSchReadyI(tp, msg); \ + chSchRescheduleS(); \ + } while (0) +/** @} */ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + msg_t chMsgSend(thread_t *tp, msg_t msg); + thread_t * chMsgWait(void); + void chMsgRelease(thread_t *tp, msg_t msg); +#ifdef __cplusplus +} +#endif + +#endif /* CH_CFG_USE_MESSAGES == TRUE */ + +#endif /* CHMSG_H */ + +/** @} */ diff --git a/os/nil/include/chsem.h b/os/nil/include/chsem.h new file mode 100644 index 000000000..84da92684 --- /dev/null +++ b/os/nil/include/chsem.h @@ -0,0 +1,146 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio. + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file nil/include/chsem.h + * @brief Nil RTOS semaphores header file. + * + * @addtogroup NIL_SEMAPHORES + * @{ + */ + +#ifndef CHSEM_H +#define CHSEM_H + +#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/** + * @name Macro Functions + * @{ + */ +/** + * @brief Initializes a semaphore with the specified counter value. + * + * @param[out] sp pointer to a @p semaphore_t structure + * @param[in] n initial value of the semaphore counter. Must be + * non-negative. + * + * @init + */ +#define chSemObjectInit(sp, n) ((sp)->cnt = n) + +/** + * @brief Performs a wait operation on a semaphore. + * + * @param[in] sp pointer to a @p semaphore_t structure + * @return A message specifying how the invoking thread has been + * released from the semaphore. + * @retval CH_MSG_OK if the thread has not stopped on the semaphore or the + * semaphore has been signaled. + * @retval CH_MSG_RST if the semaphore has been reset using @p chSemReset(). + * + * @api + */ +#define chSemWait(sp) chSemWaitTimeout(sp, TIME_INFINITE) + +/** + * @brief Performs a wait operation on a semaphore. + * + * @param[in] sp pointer to a @p semaphore_t structure + * @return A message specifying how the invoking thread has been + * released from the semaphore. + * @retval CH_MSG_OK if the thread has not stopped on the semaphore or the + * semaphore has been signaled. + * @retval CH_MSG_RST if the semaphore has been reset using @p chSemReset(). + * + * @sclass + */ +#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) +/** @} */ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + msg_t chSemWaitTimeout(semaphore_t *sp, sysinterval_t timeout); + msg_t chSemWaitTimeoutS(semaphore_t *sp, sysinterval_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); +#ifdef __cplusplus +} +#endif + +#endif /* CH_CFG_USE_SEMAPHORES == TRUE */ + +#endif /* CHSEM_H */ + +/** @} */ diff --git a/os/nil/nil.mk b/os/nil/nil.mk index 69238e91e..b4cc92b1a 100644 --- a/os/nil/nil.mk +++ b/os/nil/nil.mk @@ -14,8 +14,21 @@ endif CHCONF := $(strip $(shell cat $(CHCONFDIR)/chconf.h | egrep -e "\#define")) KERNSRC := ${CHIBIOS}/os/nil/src/ch.c +ifneq ($(findstring CH_CFG_USE_EVENTS TRUE,$(CHCONF)),) +KERNSRC += $(CHIBIOS)/os/rt/src/chevt.c +endif +ifneq ($(findstring CH_CFG_USE_MESSAGES TRUE,$(CHCONF)),) +KERNSRC += $(CHIBIOS)/os/rt/src/chmsg.c +endif +ifneq ($(findstring CH_CFG_USE_SEMAPHORES TRUE,$(CHCONF)),) +KERNSRC += $(CHIBIOS)/os/rt/src/chsem.c +endif + else -KERNSRC := ${CHIBIOS}/os/nil/src/ch.c +KERNSRC := ${CHIBIOS}/os/nil/src/ch.c \ + ${CHIBIOS}/os/nil/src/chevt.c + ${CHIBIOS}/os/nil/src/chmsg.c \ + ${CHIBIOS}/os/nil/src/chsem.c endif # Required include directories diff --git a/os/nil/src/ch.c b/os/nil/src/ch.c index 233a3f4ae..1d26e9565 100644 --- a/os/nil/src/ch.c +++ b/os/nil/src/ch.c @@ -48,27 +48,36 @@ nil_system_t nil; /* Module local functions. */ /*===========================================================================*/ +/*===========================================================================*/ +/* Module interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + /** * @brief Retrieves the highest priority thread in the specified state and * associated to the specified object. - * @note The search is unbounded, the thread is assumed to exist. * * @param[in] state thread state * @param[in] p object pointer + * @return The pointer to the found thread. + * @retval NULL if the thread is not found. + * + * @notapi */ -static thread_t *nil_find_thread(tstate_t state, void * p) { +thread_t *nil_find_thread(tstate_t state, void *p) { thread_t *tp = nil.threads; - while (true) { + while (tp < &nil.threads[CH_CFG_MAX_THREADS]) { /* Is this thread matching?*/ if ((tp->state == state) && (tp->u1.p == p)) { return tp; } tp++; - - chDbgAssert(tp < &nil.threads[CH_CFG_MAX_THREADS], - "pointer out of range"); } + return NULL; } /** @@ -80,9 +89,9 @@ static thread_t *nil_find_thread(tstate_t state, void * p) { * non negative numbers are ignored * @param[in] msg the wakeup message * - * @iclass + * @notapi */ -static cnt_t nil_ready_all(void * p, cnt_t cnt, msg_t msg) { +cnt_t nil_ready_all(void *p, cnt_t cnt, msg_t msg) { thread_t *tp = nil.threads;; while (cnt < (cnt_t)0) { @@ -101,14 +110,6 @@ static cnt_t nil_ready_all(void * p, cnt_t cnt, msg_t msg) { return cnt; } -/*===========================================================================*/ -/* Module interrupt handlers. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Module exported functions. */ -/*===========================================================================*/ - #if (CH_DBG_SYSTEM_STATE_CHECK == TRUE) || defined(__DOXYGEN__) /** * @brief Guard code for @p chSysDisable(). @@ -1015,6 +1016,9 @@ void chThdDoDequeueNextI(threads_queue_t *tqp, msg_t msg) { tqp->cnt++; tp = nil_find_thread(NIL_STATE_WTQUEUE, (void *)tqp); + + chDbgAssert(tp != NULL, "thread not found"); + (void) chSchReadyI(tp, msg); } @@ -1053,290 +1057,4 @@ void chThdDequeueAllI(threads_queue_t *tqp, msg_t msg) { tqp->cnt = nil_ready_all((void *)tqp, tqp->cnt, msg); } -#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__) -/** - * @brief Performs a wait operation on a semaphore with timeout specification. - * - * @param[in] sp pointer to a @p semaphore_t structure - * @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 A message specifying how the invoking thread has been - * released from the semaphore. - * @retval NIL_MSG_OK if the thread has not stopped on the semaphore or the - * semaphore has been signaled. - * @retval NIL_MSG_RST if the semaphore has been reset using @p chSemReset(). - * @retval NIL_MSG_TMO if the semaphore has not been signaled or reset within - * the specified timeout. - * - * @api - */ -msg_t chSemWaitTimeout(semaphore_t *sp, sysinterval_t timeout) { - msg_t msg; - - chSysLock(); - msg = chSemWaitTimeoutS(sp, timeout); - chSysUnlock(); - - return msg; -} - -/** - * @brief Performs a wait operation on a semaphore with timeout specification. - * - * @param[in] sp pointer to a @p semaphore_t structure - * @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 A message specifying how the invoking thread has been - * released from the semaphore. - * @retval NIL_MSG_OK if the thread has not stopped on the semaphore or the - * semaphore has been signaled. - * @retval NIL_MSG_RST if the semaphore has been reset using @p chSemReset(). - * @retval NIL_MSG_TMO if the semaphore has not been signaled or reset within - * the specified timeout. - * - * @sclass - */ -msg_t chSemWaitTimeoutS(semaphore_t *sp, sysinterval_t timeout) { - - chDbgCheckClassS(); - chDbgCheck(sp != NULL); - - /* Note, the semaphore counter is a volatile variable so accesses are - manually optimized.*/ - cnt_t cnt = sp->cnt; - if (cnt <= (cnt_t)0) { - if (TIME_IMMEDIATE == timeout) { - - return MSG_TIMEOUT; - } - sp->cnt = cnt - (cnt_t)1; - nil.current->u1.semp = sp; - - return chSchGoSleepTimeoutS(NIL_STATE_WTQUEUE, timeout); - } - sp->cnt = cnt - (cnt_t)1; - - return MSG_OK; -} - -/** - * @brief Performs a signal operation on a semaphore. - * - * @param[in] sp pointer to a @p semaphore_t structure - * - * @api - */ -void chSemSignal(semaphore_t *sp) { - - chSysLock(); - chSemSignalI(sp); - chSchRescheduleS(); - chSysUnlock(); -} - -/** - * @brief Performs a signal operation on a semaphore. - * @post This function does not reschedule so a call to a rescheduling - * function must be performed before unlocking the kernel. Note that - * interrupt handlers always reschedule on exit so an explicit - * reschedule must not be performed in ISRs. - * - * @param[in] sp pointer to a @p semaphore_t structure - * - * @iclass - */ -void chSemSignalI(semaphore_t *sp) { - - chDbgCheckClassI(); - chDbgCheck(sp != NULL); - - if (++sp->cnt <= (cnt_t)0) { - thread_t *tp = nil_find_thread(NIL_STATE_WTQUEUE, (void *)sp); - (void) chSchReadyI(tp, MSG_OK); - } -} - -/** - * @brief Performs a reset operation on the semaphore. - * @post After invoking this function all the threads waiting on the - * semaphore, if any, are released and the semaphore counter is set - * to the specified, non negative, value. - * - * @param[in] sp pointer to a @p semaphore_t structure - * @param[in] n the new value of the semaphore counter. The value must - * be non-negative. - * - * @api - */ -void chSemReset(semaphore_t *sp, cnt_t n) { - - chSysLock(); - chSemResetI(sp, n); - chSchRescheduleS(); - chSysUnlock(); -} - -/** - * @brief Performs a reset operation on the semaphore. - * @post After invoking this function all the threads waiting on the - * semaphore, if any, are released and the semaphore counter is set - * to the specified, non negative, value. - * @post This function does not reschedule so a call to a rescheduling - * function must be performed before unlocking the kernel. Note that - * interrupt handlers always reschedule on exit so an explicit - * reschedule must not be performed in ISRs. - * - * @param[in] sp pointer to a @p semaphore_t structure - * @param[in] n the new value of the semaphore counter. The value must - * be non-negative. - * - * @iclass - */ -void chSemResetI(semaphore_t *sp, cnt_t n) { - cnt_t cnt; - - chDbgCheckClassI(); - chDbgCheck((sp != NULL) && (n >= (cnt_t)0)); - - cnt = sp->cnt; - sp->cnt = n; - - /* Does nothing for cnt >= 0, calling anyway.*/ - (void) nil_ready_all((void *)sp, cnt, MSG_RESET); -} -#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. - * - * @param[in] tp the thread to be signaled - * @param[in] mask the event flags set to be ORed - * - * @api - */ -void chEvtSignal(thread_t *tp, eventmask_t mask) { - - chSysLock(); - chEvtSignalI(tp, mask); - chSchRescheduleS(); - chSysUnlock(); -} - -/** - * @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 - * function must be performed before unlocking the kernel. Note that - * interrupt handlers always reschedule on exit so an explicit - * reschedule must not be performed in ISRs. - * - * @param[in] tp the thread to be signaled - * @param[in] mask the event flags set to be ORed - * - * @iclass - */ -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)) || - (NIL_THD_IS_WTANDEVT(tp) && - ((tp->epmask & tp->u1.ewmask) == tp->u1.ewmask))) { - (void) chSchReadyI(tp, MSG_OK); - } -} - -/** - * @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. - * - * @api - */ -eventmask_t chEvtWaitAnyTimeout(eventmask_t mask, sysinterval_t timeout) { - thread_t *ctp = nil.current; - eventmask_t m; - - chSysLock(); - if ((m = (ctp->epmask & mask)) == (eventmask_t)0) { - if (TIME_IMMEDIATE == timeout) { - chSysUnlock(); - - return (eventmask_t)0; - } - ctp->u1.ewmask = mask; - if (chSchGoSleepTimeoutS(NIL_STATE_WTOREVT, timeout) < MSG_OK) { - chSysUnlock(); - - return (eventmask_t)0; - } - m = ctp->epmask & mask; - } - ctp->epmask &= ~m; - chSysUnlock(); - - return m; -} - -/** - * @brief Waits for all the specified events. - * @details The function waits for all the events 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. - * - * @api - */ -eventmask_t chEvtWaitAllTimeout(eventmask_t mask, sysinterval_t timeout) { - thread_t *ctp = nil.current; - - chSysLock(); - if ((ctp->epmask & mask) != mask) { - if (TIME_IMMEDIATE == timeout) { - chSysUnlock(); - - return (eventmask_t)0; - } - ctp->u1.ewmask = mask; - if (chSchGoSleepTimeoutS(NIL_STATE_WTANDEVT, timeout) < MSG_OK) { - chSysUnlock(); - - return (eventmask_t)0; - } - } - ctp->epmask &= ~mask; - chSysUnlock(); - - return mask; -} -#endif /* CH_CFG_USE_EVENTS == TRUE */ - /** @} */ diff --git a/os/nil/src/chevt.c b/os/nil/src/chevt.c new file mode 100644 index 000000000..16746177f --- /dev/null +++ b/os/nil/src/chevt.c @@ -0,0 +1,183 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio. + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file nil/src/chevt.c + * @brief Nil RTOS events source file. + * + * @addtogroup NIL_EVENTS + * @{ + */ + +#include "ch.h" + +#if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +/** + * @brief Adds a set of event flags directly to the specified @p thread_t. + * + * @param[in] tp the thread to be signaled + * @param[in] mask the event flags set to be ORed + * + * @api + */ +void chEvtSignal(thread_t *tp, eventmask_t mask) { + + chSysLock(); + chEvtSignalI(tp, mask); + chSchRescheduleS(); + chSysUnlock(); +} + +/** + * @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 + * function must be performed before unlocking the kernel. Note that + * interrupt handlers always reschedule on exit so an explicit + * reschedule must not be performed in ISRs. + * + * @param[in] tp the thread to be signaled + * @param[in] mask the event flags set to be ORed + * + * @iclass + */ +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)) || + (NIL_THD_IS_WTANDEVT(tp) && + ((tp->epmask & tp->u1.ewmask) == tp->u1.ewmask))) { + (void) chSchReadyI(tp, MSG_OK); + } +} + +/** + * @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. + * + * @api + */ +eventmask_t chEvtWaitAnyTimeout(eventmask_t mask, sysinterval_t timeout) { + thread_t *ctp = nil.current; + eventmask_t m; + + chSysLock(); + if ((m = (ctp->epmask & mask)) == (eventmask_t)0) { + if (TIME_IMMEDIATE == timeout) { + chSysUnlock(); + + return (eventmask_t)0; + } + ctp->u1.ewmask = mask; + if (chSchGoSleepTimeoutS(NIL_STATE_WTOREVT, timeout) < MSG_OK) { + chSysUnlock(); + + return (eventmask_t)0; + } + m = ctp->epmask & mask; + } + ctp->epmask &= ~m; + chSysUnlock(); + + return m; +} + +/** + * @brief Waits for all the specified events. + * @details The function waits for all the events 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. + * + * @api + */ +eventmask_t chEvtWaitAllTimeout(eventmask_t mask, sysinterval_t timeout) { + thread_t *ctp = nil.current; + + chSysLock(); + if ((ctp->epmask & mask) != mask) { + if (TIME_IMMEDIATE == timeout) { + chSysUnlock(); + + return (eventmask_t)0; + } + ctp->u1.ewmask = mask; + if (chSchGoSleepTimeoutS(NIL_STATE_WTANDEVT, timeout) < MSG_OK) { + chSysUnlock(); + + return (eventmask_t)0; + } + } + ctp->epmask &= ~mask; + chSysUnlock(); + + return mask; +} + +#endif /* CH_CFG_USE_EVENTS == TRUE */ + +/** @} */ diff --git a/os/nil/src/chmsg.c b/os/nil/src/chmsg.c new file mode 100644 index 000000000..08a6a9a71 --- /dev/null +++ b/os/nil/src/chmsg.c @@ -0,0 +1,133 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio. + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file nil/src/chmsg.c + * @brief Nil RTOS synchronous messages source file. + * + * @addtogroup NIL_MESSAGES + * @{ + */ + +#include "ch.h" + +#if (CH_CFG_USE_MESSAGES == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +/** + * @brief Sends a message to the specified thread. + * @details The sender is stopped until the receiver executes a + * @p chMsgRelease()after receiving the message. + * + * @param[in] tp the pointer to the thread + * @param[in] msg the message + * @return The answer message from @p chMsgRelease(). + * + * @api + */ +msg_t chMsgSend(thread_t *tp, msg_t msg) { + thread_t *ctp = nil.current; + + chDbgCheck(tp != NULL); + + chSysLock(); + ctp->sntmsg = msg; + ctp->u1.tp = tp; + if (NIL_THD_IS_WTMSG(tp)) { + (void) chSchReadyI(tp, (msg_t)ctp); + } + msg = chSchGoSleepTimeoutS(NIL_STATE_SNDMSGQ, TIME_INFINITE); + chSysUnlock(); + + return msg; +} + +/** + * @brief Suspends the thread and waits for an incoming message. + * @post After receiving a message the function @p chMsgGet() must be + * called in order to retrieve the message and then @p chMsgRelease() + * must be invoked in order to acknowledge the reception and send + * the answer. + * @note If the message is a pointer then you can assume that the data + * pointed by the message is stable until you invoke @p chMsgRelease() + * because the sending thread is suspended until then. + * @note The reference counter of the sender thread is not increased, the + * returned pointer is a temporary reference. + * + * @return A pointer to the thread carrying the message. + * + * @api + */ +thread_t *chMsgWait(void) { + thread_t *tp; + + chSysLock(); + tp = nil_find_thread(NIL_STATE_SNDMSGQ, nil.current); + if (tp == NULL) { + tp = (thread_t *)chSchGoSleepTimeoutS(NIL_STATE_WTMSG, TIME_INFINITE); + } + chSysUnlock(); + + return tp; +} + +/** + * @brief Releases a sender thread specifying a response message. + * @pre Invoke this function only after a message has been received + * using @p chMsgWait(). + * + * @param[in] tp pointer to the thread + * @param[in] msg message to be returned to the sender + * + * @api + */ +void chMsgRelease(thread_t *tp, msg_t msg) { + + chSysLock(); + chDbgAssert(tp->state == NIL_STATE_SNDMSGQ, "invalid state"); + chMsgReleaseS(tp, msg); + chSysUnlock(); +} + +#endif /* CH_CFG_USE_MESSAGES == TRUE */ + +/** @} */ diff --git a/os/nil/src/chsem.c b/os/nil/src/chsem.c new file mode 100644 index 000000000..d56bf03c0 --- /dev/null +++ b/os/nil/src/chsem.c @@ -0,0 +1,218 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio. + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file nil/src/chsem.c + * @brief Nil RTOS semaphores source file. + * + * @addtogroup NIL_SEMAPHORES + * @{ + */ + +#include "ch.h" + +#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +/** + * @brief Performs a wait operation on a semaphore with timeout specification. + * + * @param[in] sp pointer to a @p semaphore_t structure + * @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 A message specifying how the invoking thread has been + * released from the semaphore. + * @retval NIL_MSG_OK if the thread has not stopped on the semaphore or the + * semaphore has been signaled. + * @retval NIL_MSG_RST if the semaphore has been reset using @p chSemReset(). + * @retval NIL_MSG_TMO if the semaphore has not been signaled or reset within + * the specified timeout. + * + * @api + */ +msg_t chSemWaitTimeout(semaphore_t *sp, sysinterval_t timeout) { + msg_t msg; + + chSysLock(); + msg = chSemWaitTimeoutS(sp, timeout); + chSysUnlock(); + + return msg; +} + +/** + * @brief Performs a wait operation on a semaphore with timeout specification. + * + * @param[in] sp pointer to a @p semaphore_t structure + * @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 A message specifying how the invoking thread has been + * released from the semaphore. + * @retval NIL_MSG_OK if the thread has not stopped on the semaphore or the + * semaphore has been signaled. + * @retval NIL_MSG_RST if the semaphore has been reset using @p chSemReset(). + * @retval NIL_MSG_TMO if the semaphore has not been signaled or reset within + * the specified timeout. + * + * @sclass + */ +msg_t chSemWaitTimeoutS(semaphore_t *sp, sysinterval_t timeout) { + + chDbgCheckClassS(); + chDbgCheck(sp != NULL); + + /* Note, the semaphore counter is a volatile variable so accesses are + manually optimized.*/ + cnt_t cnt = sp->cnt; + if (cnt <= (cnt_t)0) { + if (TIME_IMMEDIATE == timeout) { + + return MSG_TIMEOUT; + } + sp->cnt = cnt - (cnt_t)1; + nil.current->u1.semp = sp; + + return chSchGoSleepTimeoutS(NIL_STATE_WTQUEUE, timeout); + } + sp->cnt = cnt - (cnt_t)1; + + return MSG_OK; +} + +/** + * @brief Performs a signal operation on a semaphore. + * + * @param[in] sp pointer to a @p semaphore_t structure + * + * @api + */ +void chSemSignal(semaphore_t *sp) { + + chSysLock(); + chSemSignalI(sp); + chSchRescheduleS(); + chSysUnlock(); +} + +/** + * @brief Performs a signal operation on a semaphore. + * @post This function does not reschedule so a call to a rescheduling + * function must be performed before unlocking the kernel. Note that + * interrupt handlers always reschedule on exit so an explicit + * reschedule must not be performed in ISRs. + * + * @param[in] sp pointer to a @p semaphore_t structure + * + * @iclass + */ +void chSemSignalI(semaphore_t *sp) { + + chDbgCheckClassI(); + chDbgCheck(sp != NULL); + + if (++sp->cnt <= (cnt_t)0) { + thread_t *tp = nil_find_thread(NIL_STATE_WTQUEUE, (void *)sp); + + chDbgAssert(tp != NULL, "thread not found"); + + (void) chSchReadyI(tp, MSG_OK); + } +} + +/** + * @brief Performs a reset operation on the semaphore. + * @post After invoking this function all the threads waiting on the + * semaphore, if any, are released and the semaphore counter is set + * to the specified, non negative, value. + * + * @param[in] sp pointer to a @p semaphore_t structure + * @param[in] n the new value of the semaphore counter. The value must + * be non-negative. + * + * @api + */ +void chSemReset(semaphore_t *sp, cnt_t n) { + + chSysLock(); + chSemResetI(sp, n); + chSchRescheduleS(); + chSysUnlock(); +} + +/** + * @brief Performs a reset operation on the semaphore. + * @post After invoking this function all the threads waiting on the + * semaphore, if any, are released and the semaphore counter is set + * to the specified, non negative, value. + * @post This function does not reschedule so a call to a rescheduling + * function must be performed before unlocking the kernel. Note that + * interrupt handlers always reschedule on exit so an explicit + * reschedule must not be performed in ISRs. + * + * @param[in] sp pointer to a @p semaphore_t structure + * @param[in] n the new value of the semaphore counter. The value must + * be non-negative. + * + * @iclass + */ +void chSemResetI(semaphore_t *sp, cnt_t n) { + cnt_t cnt; + + chDbgCheckClassI(); + chDbgCheck((sp != NULL) && (n >= (cnt_t)0)); + + cnt = sp->cnt; + sp->cnt = n; + + /* Does nothing for cnt >= 0, calling anyway.*/ + (void) nil_ready_all((void *)sp, cnt, MSG_RESET); +} + +#endif /* CH_CFG_USE_SEMAPHORES == TRUE */ + +/** @} */ diff --git a/test/lib/ch_test.c b/test/lib/ch_test.c index 859ecdf9f..f7eb8f453 100644 --- a/test/lib/ch_test.c +++ b/test/lib/ch_test.c @@ -255,6 +255,23 @@ msg_t test_execute(BaseSequentialStream *stream, const testsuite_t *tsp) { test_print("*** Test Board: "); test_println(BOARD_NAME); #endif +#if defined(__GNUC__) && !defined(TEST_SUPPRESS_SIZE_REPORT) + { + extern uint8_t __text_base, __text_end, + _data_start, _data_end, + _bss_start, _bss_end; + test_println("***"); + test_print("*** Text size: "); + test_printn((uint32_t)(&__text_end - &__text_base)); + test_println(" bytes"); + test_print("*** Data size: "); + test_printn((uint32_t)(&_data_end - &_data_start)); + test_println(" bytes"); + test_print("*** BSS size: "); + test_printn((uint32_t)(&_bss_end - &_bss_start)); + test_println(" bytes"); + } +#endif #if defined(TEST_REPORT_HOOK_HEADER) TEST_REPORT_HOOK_HEADER #endif