Tree reorganization.

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@8900 35acf78f-673a-0410-8e92-d51de3d6d3f4
This commit is contained in:
Giovanni Di Sirio 2016-02-16 10:07:00 +00:00
parent 641f2c3726
commit cf204e72ea
105 changed files with 2270 additions and 12007 deletions

View File

@ -18,7 +18,7 @@
*/ */
/** /**
* @file nil.h * @file ch.h
* @brief Nil RTOS main header file. * @brief Nil RTOS main header file.
* @details This header includes all the required kernel headers so it is the * @details This header includes all the required kernel headers so it is the
* only header you usually need to include in your application. * only header you usually need to include in your application.
@ -27,18 +27,11 @@
* @{ * @{
*/ */
#ifndef _NIL_H_ #ifndef _CH_H_
#define _NIL_H_ #define _CH_H_
/** #include "chconf.h"
* @brief Type of a structure representing a thread. #include "chtypes.h"
* @note It is required as an early definition.
*/
typedef struct nil_thread thread_t;
#include "nilconf.h"
#include "niltypes.h"
#include "nilcore.h"
/*===========================================================================*/ /*===========================================================================*/
/* Module constants. */ /* Module constants. */
@ -61,22 +54,22 @@ typedef struct nil_thread thread_t;
/** /**
* @brief Kernel version string. * @brief Kernel version string.
*/ */
#define CH_KERNEL_VERSION "1.1.1" #define CH_KERNEL_VERSION "2.0.0"
/** /**
* @brief Kernel version major number. * @brief Kernel version major number.
*/ */
#define CH_KERNEL_MAJOR 1 #define CH_KERNEL_MAJOR 2
/** /**
* @brief Kernel version minor number. * @brief Kernel version minor number.
*/ */
#define CH_KERNEL_MINOR 1 #define CH_KERNEL_MINOR 0
/** /**
* @brief Kernel version patch number. * @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 * @note This number is not inclusive of the idle thread which is
* implicitly handled. * implicitly handled.
*/ */
#if !defined(NIL_CFG_NUM_THREADS) || defined(__DOXYGEN__) #if !defined(CH_CFG_NUM_THREADS) || defined(__DOXYGEN__)
#define NIL_CFG_NUM_THREADS 2 #define CH_CFG_NUM_THREADS 2
#endif #endif
/** /**
* @brief System time counter resolution. * @brief System time counter resolution.
* @note Allowed values are 16 or 32 bits. * @note Allowed values are 16 or 32 bits.
*/ */
#if !defined(NIL_CFG_ST_RESOLUTION) || defined(__DOXYGEN__) #if !defined(CH_CFG_ST_RESOLUTION) || defined(__DOXYGEN__)
#define NIL_CFG_ST_RESOLUTION 32 #define CH_CFG_ST_RESOLUTION 32
#endif #endif
/** /**
* @brief System tick frequency. * @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 * option defines the maximum amount of time allowed for
* timeouts. * timeouts.
*/ */
#if !defined(NIL_CFG_ST_FREQUENCY) || defined(__DOXYGEN__) #if !defined(CH_CFG_ST_FREQUENCY) || defined(__DOXYGEN__)
#define NIL_CFG_ST_FREQUENCY 100 #define CH_CFG_ST_FREQUENCY 100
#endif #endif
/** /**
@ -180,8 +173,29 @@ typedef struct nil_thread thread_t;
* The value one is not valid, timeouts are rounded up to * The value one is not valid, timeouts are rounded up to
* this value. * this value.
*/ */
#if !defined(NIL_CFG_ST_TIMEDELTA) || defined(__DOXYGEN__) #if !defined(CH_CFG_ST_TIMEDELTA) || defined(__DOXYGEN__)
#define NIL_CFG_ST_TIMEDELTA 0 #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 #endif
/** /**
@ -190,44 +204,122 @@ typedef struct nil_thread thread_t;
* *
* @note The default is @p TRUE. * @note The default is @p TRUE.
*/ */
#if !defined(NIL_CFG_USE_EVENTS) || defined(__DOXYGEN__) #if !defined(CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
#define NIL_CFG_USE_EVENTS TRUE #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 #endif
/** /**
* @brief System assertions. * @brief System assertions.
*
* @note The default is @p FALSE.
*/ */
#if !defined(NIL_CFG_ENABLE_ASSERTS) || defined(__DOXYGEN__) #if !defined(CH_DBG_ENABLE_ASSERTS) || defined(__DOXYGEN__)
#define NIL_CFG_ENABLE_ASSERTS FALSE #define CH_DBG_ENABLE_ASSERTS FALSE
#endif #endif
/** /**
* @brief Stack check. * @brief Stack check.
*
* @note The default is @p FALSE.
*/ */
#if !defined(NIL_CFG_ENABLE_STACK_CHECK) || defined(__DOXYGEN__) #if !defined(CH_DBG_ENABLE_STACK_CHECK) || defined(__DOXYGEN__)
#define NIL_CFG_ENABLE_STACK_CHECK FALSE #define CH_DBG_ENABLE_STACK_CHECK FALSE
#endif #endif
/** /**
* @brief System initialization hook. * @brief System initialization hook.
*/ */
#if !defined(NIL_CFG_SYSTEM_INIT_HOOK) || defined(__DOXYGEN__) #if !defined(CH_CFG_SYSTEM_INIT_HOOK) || defined(__DOXYGEN__)
#define NIL_CFG_SYSTEM_INIT_HOOK() {} #define CH_CFG_SYSTEM_INIT_HOOK() {}
#endif #endif
/** /**
* @brief Threads descriptor structure extension. * @brief Threads descriptor structure extension.
* @details User fields added to the end of the @p thread_t structure. * @details User fields added to the end of the @p thread_t structure.
*/ */
#if !defined(NIL_CFG_THREAD_EXT_FIELDS) || defined(__DOXYGEN__) #if !defined(CH_CFG_THREAD_EXT_FIELDS) || defined(__DOXYGEN__)
#define NIL_CFG_THREAD_EXT_FIELDS #define CH_CFG_THREAD_EXT_FIELDS
#endif #endif
/** /**
* @brief Threads initialization hook. * @brief Threads initialization hook.
*/ */
#if !defined(NIL_CFG_THREAD_EXT_INIT_HOOK) || defined(__DOXYGEN__) #if !defined(CH_CFG_THREAD_EXT_INIT_HOOK) || defined(__DOXYGEN__)
#define NIL_CFG_THREAD_EXT_INIT_HOOK(tr) {} #define CH_CFG_THREAD_EXT_INIT_HOOK(tr) {}
#endif #endif
/** /**
@ -236,8 +328,8 @@ typedef struct nil_thread thread_t;
* should be invoked from here. * should be invoked from here.
* @note This macro can be used to activate a power saving mode. * @note This macro can be used to activate a power saving mode.
*/ */
#if !defined(NIL_CFG_IDLE_ENTER_HOOK) || defined(__DOXYGEN__) #if !defined(CH_CFG_IDLE_ENTER_HOOK) || defined(__DOXYGEN__)
#define NIL_CFG_IDLE_ENTER_HOOK() {} #define CH_CFG_IDLE_ENTER_HOOK() {}
#endif #endif
/** /**
@ -246,44 +338,59 @@ typedef struct nil_thread thread_t;
* should be invoked from here. * should be invoked from here.
* @note This macro can be used to deactivate a power saving mode. * @note This macro can be used to deactivate a power saving mode.
*/ */
#if !defined(NIL_CFG_IDLE_LEAVE_HOOK) || defined(__DOXYGEN__) #if !defined(CH_CFG_IDLE_LEAVE_HOOK) || defined(__DOXYGEN__)
#define NIL_CFG_IDLE_LEAVE_HOOK() {} #define CH_CFG_IDLE_LEAVE_HOOK() {}
#endif #endif
/** /**
* @brief System halt hook. * @brief System halt hook.
*/ */
#if !defined(NIL_CFG_SYSTEM_HALT_HOOK) || defined(__DOXYGEN__) #if !defined(CH_CFG_SYSTEM_HALT_HOOK) || defined(__DOXYGEN__)
#define NIL_CFG_SYSTEM_HALT_HOOK(reason) {} #define CH_CFG_SYSTEM_HALT_HOOK(reason) {}
#endif #endif
/*===========================================================================*/ /*===========================================================================*/
/* Derived constants and error checks. */ /* 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" #error "at least one thread must be defined"
#endif #endif
#if NIL_CFG_NUM_THREADS > 12 #if CH_CFG_NUM_THREADS > 16
#error "Nil is not recommended for thread-intensive applications, consider" \ #error "ChibiOS/NIL is not recommended for thread-intensive applications," \
"ChibiOS/RT instead" "consider ChibiOS/RT instead"
#endif #endif
#if (NIL_CFG_ST_RESOLUTION != 16) && (NIL_CFG_ST_RESOLUTION != 32) #if (CH_CFG_ST_RESOLUTION != 16) && (CH_CFG_ST_RESOLUTION != 32)
#error "invalid NIL_CFG_ST_RESOLUTION specified, must be 16 or 32" #error "invalid CH_CFG_ST_RESOLUTION specified, must be 16 or 32"
#endif #endif
#if NIL_CFG_ST_FREQUENCY <= 0 #if CH_CFG_ST_FREQUENCY <= 0
#error "invalid NIL_CFG_ST_FREQUENCY specified, must be greated than zero" #error "invalid CH_CFG_ST_FREQUENCY specified, must be greated than zero"
#endif #endif
#if (NIL_CFG_ST_TIMEDELTA < 0) || (NIL_CFG_ST_TIMEDELTA == 1) #if (CH_CFG_ST_TIMEDELTA < 0) || (CH_CFG_ST_TIMEDELTA == 1)
#error "invalid NIL_CFG_ST_TIMEDELTA specified, must " \ #error "invalid CH_CFG_ST_TIMEDELTA specified, must " \
"be zero or greater than one" "be zero or greater than one"
#endif #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 #define NIL_DBG_ENABLED TRUE
#else #else
#define NIL_DBG_ENABLED FALSE #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 /** Boundaries of the idle thread boundaries, only required if stack checking
is enabled.*/ is enabled.*/
#if (NIL_CFG_ENABLE_STACK_CHECK == TRUE) || defined(__DOXYGEN__) #if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || defined(__DOXYGEN__)
extern stkalign_t __main_thread_stack_base__, __main_thread_stack_end__;
#define THD_IDLE_BASE (&__main_thread_stack_base__) #define THD_IDLE_BASE (&__main_thread_stack_base__)
#define THD_IDLE_END (&__main_thread_stack_end__) #define THD_IDLE_END (&__main_thread_stack_end__)
#else #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. * @brief Type of a structure representing a semaphore.
*/ */
@ -321,6 +439,7 @@ typedef struct nil_semaphore semaphore_t;
struct nil_semaphore { struct nil_semaphore {
volatile cnt_t cnt; /**< @brief Semaphore counter. */ volatile cnt_t cnt; /**< @brief Semaphore counter. */
}; };
#endif /* CH_CFG_USE_SEMAPHORES == TRUE */
/** /**
* @brief Thread function. * @brief Thread function.
@ -352,29 +471,31 @@ typedef thread_t * thread_reference_t;
* @brief Structure representing a thread. * @brief Structure representing a thread.
*/ */
struct nil_thread { struct nil_thread {
intctx_t *ctxp; /**< @brief Pointer to internal context. */ struct port_context ctx; /**< @brief Processor context. */
tstate_t state; /**< @brief Thread state. */ tstate_t state; /**< @brief Thread state. */
/* Note, the following union contains a pointer while the thread is in a /* 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.*/ sleeping state (!NIL_THD_IS_READY()) else contains the wake-up message.*/
union { union {
msg_t msg; /**< @brief Wake-up message. */ msg_t msg; /**< @brief Wake-up message. */
void *p; /**< @brief Generic pointer. */ void *p; /**< @brief Generic pointer. */
thread_reference_t *trp; /**< @brief Pointer to thread reference. */ thread_reference_t *trp; /**< @brief Pointer to thread reference.*/
#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__)
semaphore_t *semp; /**< @brief Pointer to semaphore. */ semaphore_t *semp; /**< @brief Pointer to semaphore. */
#if (NIL_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__) #endif
#if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__)
eventmask_t ewmask; /**< @brief Enabled events mask. */ eventmask_t ewmask; /**< @brief Enabled events mask. */
#endif #endif
} u1; } u1;
volatile systime_t timeout;/**< @brief Timeout counter, zero volatile systime_t timeout; /**< @brief Timeout counter, zero
if disabled. */ if disabled. */
#if (NIL_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__) #if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__)
eventmask_t epmask; /**< @brief Pending events mask. */ eventmask_t epmask; /**< @brief Pending events mask. */
#endif #endif
#if (NIL_CFG_ENABLE_STACK_CHECK == TRUE) || defined(__DOXYGEN__) #if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || defined(__DOXYGEN__)
stkalign_t *stklim;/**< @brief Thread stack boundary. */ stkalign_t *stklimit; /**< @brief Thread stack boundary. */
#endif #endif
/* Optional extra fields.*/ /* 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. * or to an higher priority thread if a switch is required.
*/ */
thread_t *next; thread_t *next;
#if (NIL_CFG_ST_TIMEDELTA == 0) || defined(__DOXYGEN__) #if (CH_CFG_ST_TIMEDELTA == 0) || defined(__DOXYGEN__)
/** /**
* @brief System time. * @brief System time.
*/ */
volatile systime_t systime; volatile systime_t systime;
#endif #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. * @brief System time of the last tick event.
*/ */
@ -414,10 +535,16 @@ struct nil_system {
*/ */
systime_t nexttime; systime_t nexttime;
#endif #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__) #if (NIL_DBG_ENABLED == TRUE) || defined(__DOXYGEN__)
/** /**
* @brief Panic message. * @brief Panic message.
@ -428,12 +555,21 @@ struct nil_system {
*/ */
const char * volatile dbg_panic_msg; const char * volatile dbg_panic_msg;
#endif #endif
/**
* @brief Thread structures for all the defined threads.
*/
thread_t threads[CH_CFG_NUM_THREADS + 1];
}; };
/*===========================================================================*/ /*===========================================================================*/
/* Module macros. */ /* 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 * @name Threads tables definition macros
* @{ * @{
@ -442,7 +578,7 @@ struct nil_system {
* @brief Start of user threads table. * @brief Start of user threads table.
*/ */
#define THD_TABLE_BEGIN \ #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 * @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 * @param[in] a alignment, must be a power of two
* alignment boundary
* @return The aligned stack size.
*
* @api
*/ */
#define THD_ALIGN_STACK_SIZE(n) \ #define MEM_ALIGN_MASK(a) ((size_t)(a) - 1U)
((((n) - 1U) | (sizeof(stkalign_t) - 1U)) + 1U)
/**
* @brief Aligns to the previous aligned memory address.
*
* @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 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. * @brief Calculates the total Working Area size.
* *
@ -482,8 +651,8 @@ struct nil_system {
* *
* @api * @api
*/ */
#define THD_WORKING_AREA_SIZE(n) \ #define THD_WORKING_AREA_SIZE(n) MEM_ALIGN_NEXT(PORT_WA_SIZE(n), \
THD_ALIGN_STACK_SIZE(PORT_WA_SIZE(n)) PORT_STACK_ALIGN)
/** /**
* @brief Static working area allocation. * @brief Static working area allocation.
@ -495,8 +664,7 @@ struct nil_system {
* *
* @api * @api
*/ */
#define THD_WORKING_AREA(s, n) \ #define THD_WORKING_AREA(s, n) PORT_WORKING_AREA(s, n)
stkalign_t s[THD_WORKING_AREA_SIZE(n) / sizeof(stkalign_t)]
/** @} */ /** @} */
/** /**
@ -556,7 +724,9 @@ struct nil_system {
* *
* @special * @special
*/ */
#define CH_IRQ_PROLOGUE() PORT_IRQ_PROLOGUE() #define CH_IRQ_PROLOGUE() \
PORT_IRQ_PROLOGUE(); \
_dbg_check_enter_isr()
/** /**
* @brief IRQ handler exit code. * @brief IRQ handler exit code.
@ -564,7 +734,9 @@ struct nil_system {
* *
* @special * @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. * @brief Standard normal IRQ handler declaration.
@ -605,7 +777,7 @@ struct nil_system {
* @api * @api
*/ */
#define S2ST(sec) \ #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. * @brief Milliseconds to system ticks.
@ -619,7 +791,7 @@ struct nil_system {
*/ */
#define MS2ST(msec) \ #define MS2ST(msec) \
((systime_t)(((((uint32_t)(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. * @brief Microseconds to system ticks.
@ -633,7 +805,7 @@ struct nil_system {
*/ */
#define US2ST(usec) \ #define US2ST(usec) \
((systime_t)(((((uint32_t)(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 #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 * @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 * @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. * @brief Enters the kernel lock state.
* *
* @special * @special
*/ */
#define chSysLock() port_lock() #define chSysLock() { \
port_lock(); \
_dbg_check_lock(); \
}
/** /**
* @brief Leaves the kernel lock state. * @brief Leaves the kernel lock state.
* *
* @special * @special
*/ */
#define chSysUnlock() port_unlock() #define chSysUnlock() { \
_dbg_check_unlock(); \
port_unlock(); \
}
/** /**
* @brief Enters the kernel lock state from within an interrupt handler. * @brief Enters the kernel lock state from within an interrupt handler.
@ -740,7 +947,10 @@ struct nil_system {
* *
* @special * @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. * @brief Leaves the kernel lock state from within an interrupt handler.
@ -755,7 +965,10 @@ struct nil_system {
* *
* @special * @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. * @brief Evaluates if a reschedule is required.
@ -834,6 +1047,7 @@ struct nil_system {
(void) chSchGoSleepTimeoutS(NIL_STATE_SLEEPING, (abstime) - \ (void) chSchGoSleepTimeoutS(NIL_STATE_SLEEPING, (abstime) - \
chVTGetSystemTimeX()) chVTGetSystemTimeX())
#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__)
/** /**
* @brief Initializes a semaphore with the specified counter value. * @brief Initializes a semaphore with the specified counter value.
* *
@ -873,12 +1087,34 @@ struct nil_system {
*/ */
#define chSemWaitS(sp) chSemWaitTimeoutS(sp, TIME_INFINITE) #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. * @brief Returns the semaphore counter current value.
* *
* @iclass * @iclass
*/ */
#define chSemGetCounterI(sp) ((sp)->cnt) #define chSemGetCounterI(sp) ((sp)->cnt)
#endif /* CH_CFG_USE_SEMAPHORES == TRUE */
/** /**
* @brief Current system time. * @brief Current system time.
@ -893,7 +1129,7 @@ struct nil_system {
* *
* @xclass * @xclass
*/ */
#if (NIL_CFG_ST_TIMEDELTA == 0) || defined(__DOXYGEN__) #if (CH_CFG_ST_TIMEDELTA == 0) || defined(__DOXYGEN__)
#define chVTGetSystemTimeX() (nil.systime) #define chVTGetSystemTimeX() (nil.systime)
#else #else
#define chVTGetSystemTimeX() port_timer_get_time() #define chVTGetSystemTimeX() port_timer_get_time()
@ -927,12 +1163,34 @@ struct nil_system {
#define chVTIsTimeWithinX(time, start, end) \ #define chVTIsTimeWithinX(time, start, end) \
((bool)((systime_t)((time) - (start)) < (systime_t)((end) - (start)))) ((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. * @brief Condition assertion.
* @details If the condition check fails then the kernel panics with a * @details If the condition check fails then the kernel panics with a
* message and halts. * message and halts.
* @note The condition is tested only if the @p NIL_CFG_ENABLE_ASSERTS * @note The condition is tested only if the @p CH_DBG_ENABLE_ASSERTS
* switch is specified in @p nilconf.h else the macro does nothing. * switch is specified in @p chconf.h else the macro does nothing.
* @note The remark string is not currently used except for putting a * @note The remark string is not currently used except for putting a
* comment in the code about the assertion. * comment in the code about the assertion.
* *
@ -944,7 +1202,7 @@ struct nil_system {
#if !defined(chDbgAssert) #if !defined(chDbgAssert)
#define chDbgAssert(c, r) do { \ #define chDbgAssert(c, r) do { \
/*lint -save -e506 -e774 [2.1, 14.3] Can be a constant by design.*/ \ /*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)) { \ if (!(c)) { \
/*lint -restore*/ \ /*lint -restore*/ \
chSysHalt(__func__); \ chSysHalt(__func__); \
@ -954,13 +1212,33 @@ struct nil_system {
#endif /* !defined(chDbgAssert) */ #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. */ /* External declarations. */
/*===========================================================================*/ /*===========================================================================*/
#if !defined(__DOXYGEN__) #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 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 #endif
#ifdef __cplusplus #ifdef __cplusplus
@ -976,28 +1254,50 @@ extern "C" {
void chSysPolledDelayX(rtcnt_t cycles); void chSysPolledDelayX(rtcnt_t cycles);
void chSysRestoreStatusX(syssts_t sts); void chSysRestoreStatusX(syssts_t sts);
thread_t *chSchReadyI(thread_t *tp, msg_t msg); thread_t *chSchReadyI(thread_t *tp, msg_t msg);
bool chSchIsPreemptionRequired(void);
void chSchDoReschedule(void);
void chSchRescheduleS(void); void chSchRescheduleS(void);
msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t timeout); msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t timeout);
msg_t chThdSuspendTimeoutS(thread_reference_t *trp, systime_t timeout); msg_t chThdSuspendTimeoutS(thread_reference_t *trp, systime_t timeout);
void chThdResumeI(thread_reference_t *trp, msg_t msg); void chThdResumeI(thread_reference_t *trp, msg_t msg);
void chThdSleep(systime_t timeout); void chThdSleep(systime_t timeout);
void chThdSleepUntil(systime_t abstime); void chThdSleepUntil(systime_t abstime);
#if CH_CFG_USE_SEMAPHORES == TRUE
msg_t chSemWaitTimeout(semaphore_t *sp, systime_t timeout); msg_t chSemWaitTimeout(semaphore_t *sp, systime_t timeout);
msg_t chSemWaitTimeoutS(semaphore_t *sp, systime_t timeout); msg_t chSemWaitTimeoutS(semaphore_t *sp, systime_t timeout);
void chSemSignal(semaphore_t *sp); void chSemSignal(semaphore_t *sp);
void chSemSignalI(semaphore_t *sp); void chSemSignalI(semaphore_t *sp);
void chSemReset(semaphore_t *sp, cnt_t n); void chSemReset(semaphore_t *sp, cnt_t n);
void chSemResetI(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 chEvtSignal(thread_t *tp, eventmask_t mask);
void chEvtSignalI(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 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 #endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* _NIL_H_ */ /* Optional subsystems.*/
#include "chmboxes.h"
#include "chmemcore.h"
#include "chmempools.h"
#include "chheap.h"
#endif /* _CH_H_ */
/** @} */ /** @} */

View File

@ -1,5 +1,28 @@
# List of all the ChibiOS/NIL kernel files. # List of all the ChibiOS/NIL kernel files, there is no need to remove the files
KERNSRC = ${CHIBIOS}/os/nil/src/nil.c # 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 # Required include directories
KERNINC = ${CHIBIOS}/os/nil/include KERNINC := ${CHIBIOS}/os/nil/include \
${CHIBIOS}/os/common/oslib/include

View File

@ -18,14 +18,14 @@
*/ */
/** /**
* @file nil.c * @file ch.c
* @brief Nil RTOS main source file. * @brief Nil RTOS main source file.
* *
* @addtogroup NIL_KERNEL * @addtogroup NIL_KERNEL
* @{ * @{
*/ */
#include "nil.h" #include "ch.h"
/*===========================================================================*/ /*===========================================================================*/
/* Module local definitions. */ /* Module local definitions. */
@ -56,6 +56,156 @@ nil_system_t nil;
/* Module exported functions. */ /* 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. * @brief Initializes the kernel.
* @details Initializes the kernel structures, the current instructions flow * @details Initializes the kernel structures, the current instructions flow
@ -71,43 +221,59 @@ void chSysInit(void) {
thread_t *tp; thread_t *tp;
const thread_config_t *tcp; const thread_config_t *tcp;
/* Port layer initialization.*/ #if CH_DBG_SYSTEM_STATE_CHECK == TRUE
port_init(); nil.isr_cnt = (cnt_t)0;
nil.lock_cnt = (cnt_t)0;
#endif
/* System initialization hook.*/ /* System initialization hook.*/
NIL_CFG_SYSTEM_INIT_HOOK(); CH_CFG_SYSTEM_INIT_HOOK();
/* Iterates through the list of defined threads.*/ /* Iterates through the list of defined threads.*/
tp = &nil.threads[0]; tp = &nil.threads[0];
tcp = nil_thd_configs; tcp = nil_thd_configs;
while (tp < &nil.threads[NIL_CFG_NUM_THREADS]) { while (tp < &nil.threads[CH_CFG_NUM_THREADS]) {
#if NIL_CFG_ENABLE_STACK_CHECK #if CH_DBG_ENABLE_STACK_CHECK
tp->stklim = (stkalign_t *)tcp->wbase; tp->stklimit = (stkalign_t *)tcp->wbase;
#endif #endif
/* Port dependent thread initialization.*/ /* 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.*/ /* Initialization hook.*/
NIL_CFG_THREAD_EXT_INIT_HOOK(tp); CH_CFG_THREAD_EXT_INIT_HOOK(tp);
tp++; tp++;
tcp++; 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 /* The idle thread is a special case because its stack is set up by the
runtime environment.*/ runtime environment.*/
tp->stklim = THD_IDLE_BASE; tp->stklimit = THD_IDLE_BASE;
#endif #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 /* Runs the highest priority thread, the current one becomes the idle
thread.*/ thread.*/
nil.current = nil.next = nil.threads; nil.current = nil.next = nil.threads;
port_switch(nil.current, tp); port_switch(nil.current, tp);
chSysUnlock();
/* Interrupts enabled for the idle thread.*/
chSysEnable();
} }
/** /**
@ -132,7 +298,7 @@ void chSysHalt(const char *reason) {
(void)reason; (void)reason;
#endif #endif
NIL_CFG_SYSTEM_HALT_HOOK(reason); CH_CFG_SYSTEM_HALT_HOOK(reason);
/* Harmless infinite loop.*/ /* Harmless infinite loop.*/
while (true) { while (true) {
@ -148,7 +314,9 @@ void chSysHalt(const char *reason) {
*/ */
void chSysTimerHandlerI(void) { void chSysTimerHandlerI(void) {
#if NIL_CFG_ST_TIMEDELTA == 0 chDbgCheckClassI();
#if CH_CFG_ST_TIMEDELTA == 0
thread_t *tp = &nil.threads[0]; thread_t *tp = &nil.threads[0];
nil.systime++; nil.systime++;
do { do {
@ -177,7 +345,7 @@ void chSysTimerHandlerI(void) {
chSysUnlockFromISR(); chSysUnlockFromISR();
tp++; tp++;
chSysLockFromISR(); chSysLockFromISR();
} while (tp < &nil.threads[NIL_CFG_NUM_THREADS]); } while (tp < &nil.threads[CH_CFG_NUM_THREADS]);
#else #else
thread_t *tp = &nil.threads[0]; thread_t *tp = &nil.threads[0];
systime_t next = (systime_t)0; systime_t next = (systime_t)0;
@ -193,16 +361,20 @@ void chSysTimerHandlerI(void) {
tp->timeout -= nil.nexttime - nil.lasttime; tp->timeout -= nil.nexttime - nil.lasttime;
if (tp->timeout == (systime_t)0) { if (tp->timeout == (systime_t)0) {
#if CH_CFG_USE_SEMAPHORES == TRUE
/* Timeout on semaphores requires a special handling because the /* Timeout on semaphores requires a special handling because the
semaphore counter must be incremented.*/ 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++; tp->u1.semp->cnt++;
} }
else if (NIL_THD_IS_SUSP(tp)) { else {
#endif
if (NIL_THD_IS_SUSP(tp)) {
*tp->u1.trp = NULL; *tp->u1.trp = NULL;
} }
/*lint -restore*/ #if CH_CFG_USE_SEMAPHORES == TRUE
}
#endif
(void) chSchReadyI(tp, MSG_TIMEOUT); (void) chSchReadyI(tp, MSG_TIMEOUT);
} }
else { else {
@ -216,7 +388,7 @@ void chSysTimerHandlerI(void) {
chSysUnlockFromISR(); chSysUnlockFromISR();
tp++; tp++;
chSysLockFromISR(); chSysLockFromISR();
} while (tp < &nil.threads[NIL_CFG_NUM_THREADS]); } while (tp < &nil.threads[CH_CFG_NUM_THREADS]);
nil.lasttime = nil.nexttime; nil.lasttime = nil.nexttime;
if (next > (systime_t)0) { if (next > (systime_t)0) {
nil.nexttime += next; nil.nexttime += next;
@ -360,9 +532,8 @@ void chSysPolledDelayX(rtcnt_t cycles) {
*/ */
thread_t *chSchReadyI(thread_t *tp, msg_t msg) { thread_t *chSchReadyI(thread_t *tp, msg_t msg) {
chDbgAssert((tp >= nil.threads) && chDbgCheckClassI();
(tp < &nil.threads[NIL_CFG_NUM_THREADS]), chDbgCheck((tp >= nil.threads) && (tp < &nil.threads[CH_CFG_NUM_THREADS]));
"pointer out of range");
chDbgAssert(!NIL_THD_IS_READY(tp), "already ready"); chDbgAssert(!NIL_THD_IS_READY(tp), "already ready");
chDbgAssert(nil.next <= nil.current, "priority ordering"); chDbgAssert(nil.next <= nil.current, "priority ordering");
@ -375,6 +546,41 @@ thread_t *chSchReadyI(thread_t *tp, msg_t msg) {
return tp; 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. * @brief Reschedules if needed.
* *
@ -382,14 +588,10 @@ thread_t *chSchReadyI(thread_t *tp, msg_t msg) {
*/ */
void chSchRescheduleS(void) { void chSchRescheduleS(void) {
if (chSchIsRescRequiredI()) { chDbgCheckClassS();
thread_t *otp = nil.current;
nil.current = nil.next; if (chSchIsRescRequiredI()) {
if (otp == &nil.threads[NIL_CFG_NUM_THREADS]) { chSchDoReschedule();
NIL_CFG_IDLE_LEAVE_HOOK();
}
port_switch(nil.next, otp);
} }
} }
@ -413,20 +615,22 @@ void chSchRescheduleS(void) {
msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t timeout) { msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t timeout) {
thread_t *ntp, *otp = nil.current; 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"); "idle cannot sleep");
/* Storing the wait object for the current thread.*/ /* Storing the wait object for the current thread.*/
otp->state = newstate; otp->state = newstate;
#if NIL_CFG_ST_TIMEDELTA > 0 #if CH_CFG_ST_TIMEDELTA > 0
if (timeout != TIME_INFINITE) { if (timeout != TIME_INFINITE) {
systime_t abstime; systime_t abstime;
/* TIMEDELTA makes sure to have enough time to reprogram the timer /* TIMEDELTA makes sure to have enough time to reprogram the timer
before the free-running timer counter reaches the selected timeout.*/ before the free-running timer counter reaches the selected timeout.*/
if (timeout < (systime_t)NIL_CFG_ST_TIMEDELTA) { if (timeout < (systime_t)CH_CFG_ST_TIMEDELTA) {
timeout = (systime_t)NIL_CFG_ST_TIMEDELTA; timeout = (systime_t)CH_CFG_ST_TIMEDELTA;
} }
/* Absolute time of the timeout event.*/ /* 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?*/ /* Is this thread ready to execute?*/
if (NIL_THD_IS_READY(ntp)) { if (NIL_THD_IS_READY(ntp)) {
nil.current = nil.next = ntp; nil.current = nil.next = ntp;
if (ntp == &nil.threads[NIL_CFG_NUM_THREADS]) { if (ntp == &nil.threads[CH_CFG_NUM_THREADS]) {
NIL_CFG_IDLE_ENTER_HOOK(); CH_CFG_IDLE_ENTER_HOOK();
} }
port_switch(ntp, otp); port_switch(ntp, otp);
return nil.current->u1.msg; 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.*/ /* Points to the next thread in lowering priority order.*/
ntp++; ntp++;
chDbgAssert(ntp <= &nil.threads[NIL_CFG_NUM_THREADS], chDbgAssert(ntp <= &nil.threads[CH_CFG_NUM_THREADS],
"pointer out of range"); "pointer out of range");
} }
} }
@ -549,6 +753,7 @@ void chThdSleepUntil(systime_t abstime) {
chSysUnlock(); chSysUnlock();
} }
#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__)
/** /**
* @brief Performs a wait operation on a semaphore with timeout specification. * @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) { msg_t chSemWaitTimeoutS(semaphore_t *sp, systime_t timeout) {
chDbgCheckClassS();
chDbgCheck(sp != NULL);
/* Note, the semaphore counter is a volatile variable so accesses are /* Note, the semaphore counter is a volatile variable so accesses are
manually optimized.*/ manually optimized.*/
cnt_t cnt = sp->cnt; cnt_t cnt = sp->cnt;
@ -646,6 +854,9 @@ void chSemSignal(semaphore_t *sp) {
*/ */
void chSemSignalI(semaphore_t *sp) { void chSemSignalI(semaphore_t *sp) {
chDbgCheckClassI();
chDbgCheck(sp != NULL);
if (++sp->cnt <= (cnt_t)0) { if (++sp->cnt <= (cnt_t)0) {
thread_reference_t tr = nil.threads; thread_reference_t tr = nil.threads;
while (true) { while (true) {
@ -659,7 +870,7 @@ void chSemSignalI(semaphore_t *sp) {
} }
tr++; tr++;
chDbgAssert(tr < &nil.threads[NIL_CFG_NUM_THREADS], chDbgAssert(tr < &nil.threads[CH_CFG_NUM_THREADS],
"pointer out of range"); "pointer out of range");
} }
} }
@ -709,12 +920,15 @@ void chSemResetI(semaphore_t *sp, cnt_t n) {
thread_t *tp; thread_t *tp;
cnt_t cnt; cnt_t cnt;
chDbgCheckClassI();
chDbgCheck((sp != NULL) && (n >= (cnt_t)0));
cnt = sp->cnt; cnt = sp->cnt;
sp->cnt = n; sp->cnt = n;
tp = nil.threads; tp = nil.threads;
while (cnt < (cnt_t)0) { 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"); "pointer out of range");
/* Is this thread waiting on this semaphore?*/ /* 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. * @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(); chSchRescheduleS();
chSysUnlock(); 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. * @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 * @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) { void chEvtSignalI(thread_t *tp, eventmask_t mask) {
chDbgCheckClassI();
chDbgCheck(tp != NULL);
tp->epmask |= mask; tp->epmask |= mask;
if (NIL_THD_IS_WTOREVT(tp) && if (NIL_THD_IS_WTOREVT(tp) &&
((tp->epmask & tp->u1.ewmask) != (eventmask_t)0)) { ((tp->epmask & tp->u1.ewmask) != (eventmask_t)0)) {
@ -786,37 +1004,10 @@ void chEvtSignalI(thread_t *tp, eventmask_t mask) {
* @api * @api
*/ */
eventmask_t chEvtWaitAnyTimeout(eventmask_t mask, systime_t timeout) { 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; thread_t *ctp = nil.current;
eventmask_t m; eventmask_t m;
chSysLock();
if ((m = (ctp->epmask & mask)) == (eventmask_t)0) { if ((m = (ctp->epmask & mask)) == (eventmask_t)0) {
if (TIME_IMMEDIATE == timeout) { if (TIME_IMMEDIATE == timeout) {
chSysUnlock(); chSysUnlock();
@ -832,9 +1023,10 @@ eventmask_t chEvtWaitAnyTimeoutS(eventmask_t mask, systime_t timeout) {
m = ctp->epmask & mask; m = ctp->epmask & mask;
} }
ctp->epmask &= ~m; ctp->epmask &= ~m;
chSysUnlock();
return m; return m;
} }
#endif /* NIL_CFG_USE_EVENTS == TRUE */ #endif /* CH_CFG_USE_EVENTS == TRUE */
/** @} */ /** @} */

View File

@ -48,17 +48,17 @@
/** /**
* @brief Kernel version string. * @brief Kernel version string.
*/ */
#define CH_KERNEL_VERSION "3.2.0" #define CH_KERNEL_VERSION "4.0.0"
/** /**
* @brief Kernel version major number. * @brief Kernel version major number.
*/ */
#define CH_KERNEL_MAJOR 3 #define CH_KERNEL_MAJOR 4
/** /**
* @brief Kernel version minor number. * @brief Kernel version minor number.
*/ */
#define CH_KERNEL_MINOR 2 #define CH_KERNEL_MINOR 0
/** /**
* @brief Kernel version patch number. * @brief Kernel version patch number.
@ -69,8 +69,14 @@
/* Core headers.*/ /* Core headers.*/
#include "chtypes.h" #include "chtypes.h"
#include "chconf.h" #include "chconf.h"
#if !defined(_CHIBIOS_RT_CONF_)
#error "invalid configuration file"
#endif
#include "chlicense.h" #include "chlicense.h"
#include "chsystypes.h" #include "chsystypes.h"
#include "chalign.h"
#include "chcore.h" #include "chcore.h"
#include "chdebug.h" #include "chdebug.h"
#include "chtm.h" #include "chtm.h"
@ -92,10 +98,13 @@
#include "chmemcore.h" #include "chmemcore.h"
#include "chheap.h" #include "chheap.h"
#include "chmempools.h" #include "chmempools.h"
#include "chdynamic.h"
#include "chqueues.h" #include "chqueues.h"
#include "chstreams.h" #include "chstreams.h"
#if !defined(_CHIBIOS_RT_CONF_)
#error "missing or wrong configuration file"
#endif
#endif /* _CH_H_ */ #endif /* _CH_H_ */
/** @} */ /** @} */

View File

@ -18,17 +18,15 @@
*/ */
/** /**
* @file chmemcore.h * @file chmem.h
* @brief Core memory manager macros and structures. * @brief Memory alignment macros and structures.
* *
* @addtogroup memcore * @addtogroup mem
* @{ * @{
*/ */
#ifndef _CHMEMCORE_H_ #ifndef _CHALIGN_H_
#define _CHMEMCORE_H_ #define _CHALIGN_H_
#if (CH_CFG_USE_MEMCORE == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/ /*===========================================================================*/
/* Module constants. */ /* Module constants. */
@ -46,43 +44,53 @@
/* Module data structures and types. */ /* Module data structures and types. */
/*===========================================================================*/ /*===========================================================================*/
/**
* @brief Memory get function.
*/
typedef void *(*memgetfunc_t)(size_t size);
/*===========================================================================*/ /*===========================================================================*/
/* Module macros. */ /* Module macros. */
/*===========================================================================*/ /*===========================================================================*/
/** /**
* @name Alignment support macros * @name Memory alignment support macros
*/ */
/**
* @brief Alignment size constant.
*/
#define MEM_ALIGN_SIZE sizeof(stkalign_t)
/** /**
* @brief Alignment mask constant. * @brief Alignment mask constant.
*
* @param[in] a alignment, must be a power of two
*/ */
#define MEM_ALIGN_MASK (MEM_ALIGN_SIZE - 1U) #define MEM_ALIGN_MASK(a) ((size_t)(a) - 1U)
/** /**
* @brief Alignment helper macro. * @brief Aligns to the previous aligned memory address.
*
* @param[in] p variable to be aligned
* @param[in] a alignment, must be a power of two
*/ */
#define MEM_ALIGN_PREV(p) ((size_t)(p) & ~MEM_ALIGN_MASK) #define MEM_ALIGN_PREV(p, a) ((size_t)(p) & ~MEM_ALIGN_MASK(a))
/** /**
* @brief Alignment helper macro. * @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) MEM_ALIGN_PREV((size_t)(p) + MEM_ALIGN_MASK) #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 to * @brief Returns whatever a pointer or memory size is aligned.
* the type @p stkalign_t. *
* @param[in] p variable to be aligned
* @param[in] a alignment, must be a power of two
*/ */
#define MEM_IS_ALIGNED(p) (((size_t)(p) & MEM_ALIGN_MASK) == 0U) #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 MEM_IS_VALID_ALIGNMENT(a) \
(((size_t)(a) != 0U) && (((size_t)(a) & ((size_t)(a) - 1U)) == 0U))
/** @} */ /** @} */
/*===========================================================================*/ /*===========================================================================*/
@ -92,10 +100,7 @@ typedef void *(*memgetfunc_t)(size_t size);
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
void _core_init(void);
void *chCoreAlloc(size_t size);
void *chCoreAllocI(size_t size);
size_t chCoreGetStatusX(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
@ -104,8 +109,6 @@ extern "C" {
/* Module inline functions. */ /* Module inline functions. */
/*===========================================================================*/ /*===========================================================================*/
#endif /* CH_CFG_USE_MEMCORE == TRUE */ #endif /* _CHALIGN_H_ */
#endif /* _CHMEMCORE_H_ */
/** @} */ /** @} */

View File

@ -1,311 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file chbsem.h
* @brief Binary semaphores structures and macros.
*
* @addtogroup binary_semaphores
* @details Binary semaphores related APIs and services.
* <h2>Operation mode</h2>
* Binary semaphores are implemented as a set of inline functions
* that use the existing counting semaphores primitives. The
* difference between counting and binary semaphores is that the
* counter of binary semaphores is not allowed to grow above the
* value 1. Repeated signal operation are ignored. A binary
* semaphore can thus have only two defined states:
* - <b>Taken</b>, when its counter has a value of zero or lower
* than zero. A negative number represent the number of threads
* queued on the binary semaphore.
* - <b>Not taken</b>, when its counter has a value of one.
* .
* Binary semaphores are different from mutexes because there is no
* concept of ownership, a binary semaphore can be taken by a
* thread and signaled by another thread or an interrupt handler,
* mutexes can only be taken and released by the same thread. Another
* difference is that binary semaphores, unlike mutexes, do not
* implement the priority inheritance protocol.<br>
* In order to use the binary semaphores APIs the
* @p CH_CFG_USE_SEMAPHORES option must be enabled in @p chconf.h.
* @{
*/
#ifndef _CHBSEM_H_
#define _CHBSEM_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. */
/*===========================================================================*/
/**
* @extends semaphore_t
*
* @brief Binary semaphore type.
*/
typedef struct {
semaphore_t bs_sem;
} binary_semaphore_t;
/*===========================================================================*/
/* Module macros. */
/*===========================================================================*/
/**
* @brief Data part of a static semaphore initializer.
* @details This macro should be used when statically initializing a semaphore
* that is part of a bigger structure.
*
* @param[in] name the name of the semaphore variable
* @param[in] taken the semaphore initial state
*/
#define _BSEMAPHORE_DATA(name, taken) \
{_SEMAPHORE_DATA(name.bs_sem, ((taken) ? 0 : 1))}
/**
* @brief Static semaphore initializer.
* @details Statically initialized semaphores require no explicit
* initialization using @p chBSemInit().
*
* @param[in] name the name of the semaphore variable
* @param[in] taken the semaphore initial state
*/
#define BSEMAPHORE_DECL(name, taken) \
binary_semaphore_t name = _BSEMAPHORE_DATA(name, taken)
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
/*===========================================================================*/
/* Module inline functions. */
/*===========================================================================*/
/**
* @brief Initializes a binary semaphore.
*
* @param[out] bsp pointer to a @p binary_semaphore_t structure
* @param[in] taken initial state of the binary semaphore:
* - @a false, the initial state is not taken.
* - @a true, the initial state is taken.
* .
*
* @init
*/
static inline void chBSemObjectInit(binary_semaphore_t *bsp, bool taken) {
chSemObjectInit(&bsp->bs_sem, taken ? (cnt_t)0 : (cnt_t)1);
}
/**
* @brief Wait operation on the binary semaphore.
*
* @param[in] bsp pointer to a @p binary_semaphore_t structure
* @return A message specifying how the invoking thread has been
* released from the semaphore.
* @retval MSG_OK if the binary semaphore has been successfully taken.
* @retval MSG_RESET if the binary semaphore has been reset using
* @p bsemReset().
*
* @api
*/
static inline msg_t chBSemWait(binary_semaphore_t *bsp) {
return chSemWait(&bsp->bs_sem);
}
/**
* @brief Wait operation on the binary semaphore.
*
* @param[in] bsp pointer to a @p binary_semaphore_t structure
* @return A message specifying how the invoking thread has been
* released from the semaphore.
* @retval MSG_OK if the binary semaphore has been successfully taken.
* @retval MSG_RESET if the binary semaphore has been reset using
* @p bsemReset().
*
* @sclass
*/
static inline msg_t chBSemWaitS(binary_semaphore_t *bsp) {
chDbgCheckClassS();
return chSemWaitS(&bsp->bs_sem);
}
/**
* @brief Wait operation on the binary semaphore.
*
* @param[in] bsp pointer to a @p binary_semaphore_t structure
* @param[in] time 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 MSG_OK if the binary semaphore has been successfully taken.
* @retval MSG_RESET if the binary semaphore has been reset using
* @p bsemReset().
* @retval MSG_TIMEOUT if the binary semaphore has not been signaled or reset
* within the specified timeout.
*
* @sclass
*/
static inline msg_t chBSemWaitTimeoutS(binary_semaphore_t *bsp,
systime_t time) {
chDbgCheckClassS();
return chSemWaitTimeoutS(&bsp->bs_sem, time);
}
/**
* @brief Wait operation on the binary semaphore.
*
* @param[in] bsp pointer to a @p binary_semaphore_t structure
* @param[in] time 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 MSG_OK if the binary semaphore has been successfully taken.
* @retval MSG_RESET if the binary semaphore has been reset using
* @p bsemReset().
* @retval MSG_TIMEOUT if the binary semaphore has not been signaled or reset
* within the specified timeout.
*
* @api
*/
static inline msg_t chBSemWaitTimeout(binary_semaphore_t *bsp,
systime_t time) {
return chSemWaitTimeout(&bsp->bs_sem, time);
}
/**
* @brief Reset operation on the binary semaphore.
* @note The released threads can recognize they were waked up by a reset
* rather than a signal because the @p bsemWait() will return
* @p MSG_RESET instead of @p MSG_OK.
* @note This function does not reschedule.
*
* @param[in] bsp pointer to a @p binary_semaphore_t structure
* @param[in] taken new state of the binary semaphore
* - @a false, the new state is not taken.
* - @a true, the new state is taken.
* .
*
* @iclass
*/
static inline void chBSemResetI(binary_semaphore_t *bsp, bool taken) {
chDbgCheckClassI();
chSemResetI(&bsp->bs_sem, taken ? (cnt_t)0 : (cnt_t)1);
}
/**
* @brief Reset operation on the binary semaphore.
* @note The released threads can recognize they were waked up by a reset
* rather than a signal because the @p bsemWait() will return
* @p MSG_RESET instead of @p MSG_OK.
*
* @param[in] bsp pointer to a @p binary_semaphore_t structure
* @param[in] taken new state of the binary semaphore
* - @a false, the new state is not taken.
* - @a true, the new state is taken.
* .
*
* @api
*/
static inline void chBSemReset(binary_semaphore_t *bsp, bool taken) {
chSemReset(&bsp->bs_sem, taken ? (cnt_t)0 : (cnt_t)1);
}
/**
* @brief Performs a signal operation on a binary semaphore.
* @note This function does not reschedule.
*
* @param[in] bsp pointer to a @p binary_semaphore_t structure
*
* @iclass
*/
static inline void chBSemSignalI(binary_semaphore_t *bsp) {
chDbgCheckClassI();
if (bsp->bs_sem.s_cnt < (cnt_t)1) {
chSemSignalI(&bsp->bs_sem);
}
}
/**
* @brief Performs a signal operation on a binary semaphore.
*
* @param[in] bsp pointer to a @p binary_semaphore_t structure
*
* @api
*/
static inline void chBSemSignal(binary_semaphore_t *bsp) {
chSysLock();
chBSemSignalI(bsp);
chSchRescheduleS();
chSysUnlock();
}
/**
* @brief Returns the binary semaphore current state.
*
* @param[in] bsp pointer to a @p binary_semaphore_t structure
* @return The binary semaphore current state.
* @retval false if the binary semaphore is not taken.
* @retval true if the binary semaphore is taken.
*
* @iclass
*/
static inline bool chBSemGetStateI(binary_semaphore_t *bsp) {
chDbgCheckClassI();
return (bsp->bs_sem.s_cnt > (cnt_t)0) ? false : true;
}
#endif /* CH_CFG_USE_SEMAPHORES == TRUE */
#endif /* _CHBSEM_H_ */
/** @} */

View File

@ -57,7 +57,7 @@
* @brief condition_variable_t structure. * @brief condition_variable_t structure.
*/ */
typedef struct condition_variable { typedef struct condition_variable {
threads_queue_t c_queue; /**< @brief Condition variable threads_queue_t queue; /**< @brief Condition variable
threads queue. */ threads queue. */
} condition_variable_t; } condition_variable_t;
@ -72,7 +72,7 @@ typedef struct condition_variable {
* *
* @param[in] name the name of the condition variable * @param[in] name the name of the condition variable
*/ */
#define _CONDVAR_DATA(name) {_THREADS_QUEUE_DATA(name.c_queue)} #define _CONDVAR_DATA(name) {_THREADS_QUEUE_DATA(name.queue)}
/** /**
* @brief Static condition variable initializer. * @brief Static condition variable initializer.

View File

@ -32,6 +32,51 @@
/* Module constants. */ /* Module constants. */
/*===========================================================================*/ /*===========================================================================*/
/**
* @name Trace record types
* @{
*/
#define CH_TRACE_TYPE_UNUSED 0U
#define CH_TRACE_TYPE_SWITCH 1U
#define CH_TRACE_TYPE_ISR_ENTER 2U
#define CH_TRACE_TYPE_ISR_LEAVE 3U
#define CH_TRACE_TYPE_HALT 4U
#define CH_TRACE_TYPE_USER 5U
/** @} */
/**
* @name Trace suspend masks
* @{
*/
#define CH_TRACE_SUSPEND_NONE 0U
#define CH_TRACE_SUSPEND_SWITCH (1U << CH_TRACE_TYPE_SWITCH)
#define CH_TRACE_SUSPEND_ISR_ENTER (1U << CH_TRACE_TYPE_ISR_ENTER)
#define CH_TRACE_SUSPEND_ISR_LEAVE (1U << CH_TRACE_TYPE_ISR_LEAVE)
#define CH_TRACE_SUSPEND_HALT (1U << CH_TRACE_TYPE_HALT)
#define CH_TRACE_SUSPEND_USER (1U << CH_TRACE_TYPE_USER)
#define CH_TRACE_SUSPEND_ALL (CH_TRACE_SUSPEND_SWITCH | \
CH_TRACE_SUSPEND_ISR_ENTER | \
CH_TRACE_SUSPEND_ISR_LEAVE | \
CH_TRACE_SUSPEND_HALT | \
CH_TRACE_SUSPEND_USER)
/** @} */
/**
* @name Events to trace
* @{
*/
#define CH_DBG_TRACE_MASK_NONE 0U
#define CH_DBG_TRACE_MASK_SWITCH 1U
#define CH_DBG_TRACE_MASK_ISR 2U
#define CH_DBG_TRACE_MASK_HALT 4U
#define CH_DBG_TRACE_MASK_USER 8U
#define CH_DBG_TRACE_MASK_ALL (CH_DBG_TRACE_MASK_SWITCH | \
CH_DBG_TRACE_MASK_ISR | \
CH_DBG_TRACE_MASK_HALT | \
CH_DBG_TRACE_MASK_USER)
/** @} */
/*===========================================================================*/ /*===========================================================================*/
/* Module pre-compile time settings. */ /* Module pre-compile time settings. */
/*===========================================================================*/ /*===========================================================================*/
@ -43,8 +88,17 @@
/** /**
* @brief Trace buffer entries. * @brief Trace buffer entries.
*/ */
#if !defined(CH_DBG_TRACE_MASK) || defined(__DOXYGEN__)
#define CH_DBG_TRACE_MASK CH_DBG_TRACE_MASK_ALL
#endif
/**
* @brief Trace buffer entries.
* @note The trace buffer is only allocated if @p CH_DBG_TRACE_MASK is
* different from @p CH_DBG_TRACE_MASK_NONE.
*/
#if !defined(CH_DBG_TRACE_BUFFER_SIZE) || defined(__DOXYGEN__) #if !defined(CH_DBG_TRACE_BUFFER_SIZE) || defined(__DOXYGEN__)
#define CH_DBG_TRACE_BUFFER_SIZE 64 #define CH_DBG_TRACE_BUFFER_SIZE 128
#endif #endif
/** /**
@ -53,68 +107,113 @@
#if !defined(CH_DBG_STACK_FILL_VALUE) || defined(__DOXYGEN__) #if !defined(CH_DBG_STACK_FILL_VALUE) || defined(__DOXYGEN__)
#define CH_DBG_STACK_FILL_VALUE 0x55 #define CH_DBG_STACK_FILL_VALUE 0x55
#endif #endif
/**
* @brief Fill value for thread area in debug mode.
* @note The chosen default value is 0xFF in order to make evident which
* thread fields were not initialized when inspecting the memory with
* a debugger. A uninitialized field is not an error in itself but it
* better to know it.
*/
#if !defined(CH_DBG_THREAD_FILL_VALUE) || defined(__DOXYGEN__)
#define CH_DBG_THREAD_FILL_VALUE 0xFF
#endif
/** @} */ /** @} */
/*===========================================================================*/ /*===========================================================================*/
/* Derived constants and error checks. */ /* Derived constants and error checks. */
/*===========================================================================*/ /*===========================================================================*/
#if !defined(CH_CFG_TRACE_HOOK)
#error "CH_CFG_TRACE_HOOK not defined in chconf.h"
#endif
/*===========================================================================*/ /*===========================================================================*/
/* Module data structures and types. */ /* Module data structures and types. */
/*===========================================================================*/ /*===========================================================================*/
#if (CH_DBG_ENABLE_TRACE == TRUE) || defined(__DOXYGEN__) #if (CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_NONE) || defined(__DOXYGEN__)
/** /**
* @brief Trace buffer record. * @brief Trace buffer record.
*/ */
typedef struct { typedef struct {
/** /**
* @brief Time of the switch event. * @brief Record type.
*/ */
systime_t se_time; uint32_t type:3;
/**
* @brief Switched in thread.
*/
thread_t *se_tp;
/**
* @brief Object where going to sleep.
*/
void *se_wtobjp;
/** /**
* @brief Switched out thread state. * @brief Switched out thread state.
*/ */
uint8_t se_state; uint32_t state:5;
} ch_swc_event_t; /**
* @brief Accurate time stamp.
* @note This field only available if the post supports
* @p PORT_SUPPORTS_RT else it is set to zero.
*/
uint32_t rtstamp:24;
/**
* @brief System time stamp of the switch event.
*/
systime_t time;
union {
/**
* @brief Structure representing a context switch.
*/
struct {
/**
* @brief Switched in thread.
*/
thread_t *ntp;
/**
* @brief Object where going to sleep.
*/
void *wtobjp;
} sw;
/**
* @brief Structure representing an ISR enter.
*/
struct {
/**
* @brief ISR function name taken using @p __func__.
*/
const char *name;
} isr;
/**
* @brief Structure representing an halt.
*/
struct {
/**
* @brief Halt error string.
*/
const char *reason;
} halt;
/**
* @brief User trace structure.
*/
struct {
/**
* @brief Trace user parameter 1.
*/
void *up1;
/**
* @brief Trace user parameter 2.
*/
void *up2;
} user;
} u;
} ch_trace_event_t;
/** /**
* @brief Trace buffer header. * @brief Trace buffer header.
*/ */
typedef struct { typedef struct {
/**
* @brief Suspended trace sources mask.
*/
uint16_t suspended;
/** /**
* @brief Trace buffer size (entries). * @brief Trace buffer size (entries).
*/ */
unsigned tb_size; uint16_t size;
/** /**
* @brief Pointer to the buffer front. * @brief Pointer to the buffer front.
*/ */
ch_swc_event_t *tb_ptr; ch_trace_event_t *ptr;
/** /**
* @brief Ring buffer. * @brief Ring buffer.
*/ */
ch_swc_event_t tb_buffer[CH_DBG_TRACE_BUFFER_SIZE]; ch_trace_event_t buffer[CH_DBG_TRACE_BUFFER_SIZE];
} ch_trace_buffer_t; } ch_trace_buffer_t;
#endif /* CH_DBG_ENABLE_TRACE */ #endif /* CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_NONE */
/*===========================================================================*/ /*===========================================================================*/
/* Module macros. */ /* Module macros. */
@ -143,10 +242,21 @@ typedef struct {
#define chDbgCheckClassS() #define chDbgCheckClassS()
#endif #endif
/* When the trace feature is disabled this function is replaced by an empty /* When a trace feature is disabled the associated functions are replaced by
macro.*/ an empty macro.*/
#if CH_DBG_ENABLE_TRACE == FALSE #if (CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_SWITCH) == 0
#define _dbg_trace(otp) #define _dbg_trace_switch(otp)
#endif
#if (CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_ISR) == 0
#define _dbg_trace_isr_enter(isr)
#define _dbg_trace_isr_leave(isr)
#endif
#if (CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_HALT) == 0
#define _dbg_trace_halt(reason)
#endif
#if (CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_USER) == 0
#define chDbgWriteTraceI(up1, up2)
#define chDbgWriteTrace(up1, up2)
#endif #endif
/** /**
@ -222,10 +332,27 @@ extern "C" {
void chDbgCheckClassI(void); void chDbgCheckClassI(void);
void chDbgCheckClassS(void); void chDbgCheckClassS(void);
#endif #endif
#if (CH_DBG_ENABLE_TRACE == TRUE) || defined(__DOXYGEN__) #if (CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_NONE) || defined(__DOXYGEN__)
void _dbg_trace_init(void); void _dbg_trace_init(void);
void _dbg_trace(thread_t *otp); #if (CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_SWITCH) != 0
void _dbg_trace_switch(thread_t *otp);
#endif #endif
#if (CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_ISR) != 0
void _dbg_trace_isr_enter(const char *isr);
void _dbg_trace_isr_leave(const char *isr);
#endif
#if (CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_HALT) != 0
void _dbg_trace_halt(const char *reason);
#endif
#if (CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_USER) != 0
void chDbgWriteTraceI(void *up1, void *up2);
void chDbgWriteTrace(void *up1, void *up2);
void chDbgSuspendTraceI(uint16_t mask);
void chDbgSuspendTrace(uint16_t mask);
void chDbgResumeTraceI(uint16_t mask);
void chDbgResumeTrace(uint16_t mask);
#endif
#endif /* CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_NONE */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -1,96 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file chdynamic.h
* @brief Dynamic threads macros and structures.
*
* @addtogroup dynamic_threads
* @{
*/
#ifndef _CHDYNAMIC_H_
#define _CHDYNAMIC_H_
#if (CH_CFG_USE_DYNAMIC == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Module constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Module pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*
* Module dependencies check.
*/
#if CH_CFG_USE_WAITEXIT == FALSE
#error "CH_CFG_USE_DYNAMIC requires CH_CFG_USE_WAITEXIT"
#endif
#if (CH_CFG_USE_HEAP == FALSE) && (CH_CFG_USE_MEMPOOLS == FALSE)
#error "CH_CFG_USE_DYNAMIC requires CH_CFG_USE_HEAP and/or CH_CFG_USE_MEMPOOLS"
#endif
/*===========================================================================*/
/* Module data structures and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
/*
* Dynamic threads APIs.
*/
#ifdef __cplusplus
extern "C" {
#endif
thread_t *chThdAddRef(thread_t *tp);
void chThdRelease(thread_t *tp);
#if CH_CFG_USE_HEAP == TRUE
thread_t *chThdCreateFromHeap(memory_heap_t *heapp, size_t size,
tprio_t prio, tfunc_t pf, void *arg);
#endif
#if CH_CFG_USE_MEMPOOLS == TRUE
thread_t *chThdCreateFromMemoryPool(memory_pool_t *mp, tprio_t prio,
tfunc_t pf, void *arg);
#endif
#ifdef __cplusplus
}
#endif
/*===========================================================================*/
/* Module inline functions. */
/*===========================================================================*/
#endif /* CH_CFG_USE_DYNAMIC == TRUE */
#endif /* _CHDYNAMIC_H_ */
/** @} */

View File

@ -55,16 +55,16 @@ typedef struct event_listener event_listener_t;
* @brief Event Listener structure. * @brief Event Listener structure.
*/ */
struct event_listener { struct event_listener {
event_listener_t *el_next; /**< @brief Next Event Listener event_listener_t *next; /**< @brief Next Event Listener
registered on the event registered on the event
source. */ source. */
thread_t *el_listener; /**< @brief Thread interested in the thread_t *listener; /**< @brief Thread interested in the
event source. */ event source. */
eventmask_t el_events; /**< @brief Events to be set in eventmask_t events; /**< @brief Events to be set in
the listening thread. */ the listening thread. */
eventflags_t el_flags; /**< @brief Flags added to the listener eventflags_t flags; /**< @brief Flags added to the listener
by the event source. */ by the event source. */
eventflags_t el_wflags; /**< @brief Flags that this listener eventflags_t wflags; /**< @brief Flags that this listener
interested in. */ interested in. */
}; };
@ -72,7 +72,7 @@ struct event_listener {
* @brief Event Source structure. * @brief Event Source structure.
*/ */
typedef struct event_source { typedef struct event_source {
event_listener_t *es_next; /**< @brief First Event Listener event_listener_t *next; /**< @brief First Event Listener
registered on the Event registered on the Event
Source. */ Source. */
} event_source_t; } event_source_t;
@ -169,7 +169,7 @@ extern "C" {
*/ */
static inline void chEvtObjectInit(event_source_t *esp) { static inline void chEvtObjectInit(event_source_t *esp) {
esp->es_next = (event_listener_t *)esp; esp->next = (event_listener_t *)esp;
} }
/** /**
@ -223,7 +223,7 @@ static inline void chEvtRegister(event_source_t *esp,
*/ */
static inline bool chEvtIsListeningI(event_source_t *esp) { static inline bool chEvtIsListeningI(event_source_t *esp) {
return (bool)(esp != (event_source_t *)esp->es_next); return (bool)(esp != (event_source_t *)esp->next);
} }
/** /**

View File

@ -1,118 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file chheap.h
* @brief Heaps macros and structures.
*
* @addtogroup heaps
* @{
*/
#ifndef _CHHEAP_H_
#define _CHHEAP_H_
#if (CH_CFG_USE_HEAP == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Module constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Module pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if CH_CFG_USE_MEMCORE == FALSE
#error "CH_CFG_USE_HEAP requires CH_CFG_USE_MEMCORE"
#endif
#if (CH_CFG_USE_MUTEXES == FALSE) && (CH_CFG_USE_SEMAPHORES == FALSE)
#error "CH_CFG_USE_HEAP requires CH_CFG_USE_MUTEXES and/or CH_CFG_USE_SEMAPHORES"
#endif
/*===========================================================================*/
/* Module data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a memory heap.
*/
typedef struct memory_heap memory_heap_t;
/**
* @brief Memory heap block header.
*/
union heap_header {
stkalign_t align;
struct {
union {
union heap_header *next; /**< @brief Next block in free list. */
memory_heap_t *heap; /**< @brief Block owner heap. */
} u; /**< @brief Overlapped fields. */
size_t size; /**< @brief Size of the memory block. */
} h;
};
/**
* @brief Structure describing a memory heap.
*/
struct memory_heap {
memgetfunc_t h_provider; /**< @brief Memory blocks provider for
this heap. */
union heap_header h_free; /**< @brief Free blocks list header. */
#if CH_CFG_USE_MUTEXES == TRUE
mutex_t h_mtx; /**< @brief Heap access mutex. */
#else
semaphore_t h_sem; /**< @brief Heap access semaphore. */
#endif
};
/*===========================================================================*/
/* Module macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void _heap_init(void);
void chHeapObjectInit(memory_heap_t *heapp, void *buf, size_t size);
void *chHeapAlloc(memory_heap_t *heapp, size_t size);
void chHeapFree(void *p);
size_t chHeapStatus(memory_heap_t *heapp, size_t *sizep);
#ifdef __cplusplus
}
#endif
/*===========================================================================*/
/* Module inline functions. */
/*===========================================================================*/
#endif /* CH_CFG_USE_HEAP == TRUE */
#endif /* _CHHEAP_H_ */
/** @} */

View File

@ -207,17 +207,14 @@
#error "CH_CFG_USE_TM == TRUE, Time Measurement functionality restricted" #error "CH_CFG_USE_TM == TRUE, Time Measurement functionality restricted"
#endif #endif
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE #if CH_CFG_USE_MUTEXES == TRUE
#error "CH_CFG_USE_MUTEXES_RECURSIVE == TRUE, Recursive Mutexes functionality restricted" #error "CH_CFG_USE_MUTEXES == TRUE, Recursive Mutexes functionality restricted"
#endif #endif
#if CH_CFG_USE_CONDVARS == TRUE #if CH_CFG_USE_CONDVARS == TRUE
#error "CH_CFG_USE_CONDVARS == TRUE, Condition Variables functionality restricted" #error "CH_CFG_USE_CONDVARS == TRUE, Condition Variables functionality restricted"
#endif #endif
#if CH_CFG_USE_DYNAMIC == TRUE
#error "CH_CFG_USE_DYNAMIC == TRUE, Dynamic Threads functionality restricted"
#endif
#endif /* CH_LICENSE_FEATURES == CH_FEATURES_BASIC */ #endif /* CH_LICENSE_FEATURES == CH_FEATURES_BASIC */
#else #else

View File

@ -1,207 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file chmboxes.h
* @brief Mailboxes macros and structures.
*
* @addtogroup mailboxes
* @{
*/
#ifndef _CHMBOXES_H_
#define _CHMBOXES_H_
#if (CH_CFG_USE_MAILBOXES == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Module constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Module pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if CH_CFG_USE_SEMAPHORES == FALSE
#error "CH_CFG_USE_MAILBOXES requires CH_CFG_USE_SEMAPHORES"
#endif
/*===========================================================================*/
/* Module data structures and types. */
/*===========================================================================*/
/**
* @brief Structure representing a mailbox object.
*/
typedef struct {
msg_t *mb_buffer; /**< @brief Pointer to the mailbox
buffer. */
msg_t *mb_top; /**< @brief Pointer to the location
after the buffer. */
msg_t *mb_wrptr; /**< @brief Write pointer. */
msg_t *mb_rdptr; /**< @brief Read pointer. */
semaphore_t mb_fullsem; /**< @brief Full counter
@p semaphore_t. */
semaphore_t mb_emptysem; /**< @brief Empty counter
@p semaphore_t. */
} mailbox_t;
/*===========================================================================*/
/* Module macros. */
/*===========================================================================*/
/**
* @brief Data part of a static mailbox initializer.
* @details This macro should be used when statically initializing a
* mailbox that is part of a bigger structure.
*
* @param[in] name the name of the mailbox variable
* @param[in] buffer pointer to the mailbox buffer area
* @param[in] size size of the mailbox buffer area
*/
#define _MAILBOX_DATA(name, buffer, size) { \
(msg_t *)(buffer), \
(msg_t *)(buffer) + size, \
(msg_t *)(buffer), \
(msg_t *)(buffer), \
_SEMAPHORE_DATA(name.mb_fullsem, 0), \
_SEMAPHORE_DATA(name.mb_emptysem, size), \
}
/**
* @brief Static mailbox initializer.
* @details Statically initialized mailboxes require no explicit
* initialization using @p chMBInit().
*
* @param[in] name the name of the mailbox variable
* @param[in] buffer pointer to the mailbox buffer area
* @param[in] size size of the mailbox buffer area
*/
#define MAILBOX_DECL(name, buffer, size) \
mailbox_t name = _MAILBOX_DATA(name, buffer, size)
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void chMBObjectInit(mailbox_t *mbp, msg_t *buf, cnt_t n);
void chMBReset(mailbox_t *mbp);
void chMBResetI(mailbox_t *mbp);
msg_t chMBPost(mailbox_t *mbp, msg_t msg, systime_t timeout);
msg_t chMBPostS(mailbox_t *mbp, msg_t msg, systime_t timeout);
msg_t chMBPostI(mailbox_t *mbp, msg_t msg);
msg_t chMBPostAhead(mailbox_t *mbp, msg_t msg, systime_t timeout);
msg_t chMBPostAheadS(mailbox_t *mbp, msg_t msg, systime_t timeout);
msg_t chMBPostAheadI(mailbox_t *mbp, msg_t msg);
msg_t chMBFetch(mailbox_t *mbp, msg_t *msgp, systime_t timeout);
msg_t chMBFetchS(mailbox_t *mbp, msg_t *msgp, systime_t timeout);
msg_t chMBFetchI(mailbox_t *mbp, msg_t *msgp);
#ifdef __cplusplus
}
#endif
/*===========================================================================*/
/* Module inline functions. */
/*===========================================================================*/
/**
* @brief Returns the mailbox buffer size.
*
* @param[in] mbp the pointer to an initialized mailbox_t object
* @return The size of the mailbox.
*
* @iclass
*/
static inline size_t chMBGetSizeI(mailbox_t *mbp) {
/*lint -save -e9033 [10.8] Perfectly safe pointers
arithmetic.*/
return (size_t)(mbp->mb_top - mbp->mb_buffer);
/*lint -restore*/
}
/**
* @brief Returns the number of free message slots into a mailbox.
* @note Can be invoked in any system state but if invoked out of a locked
* state then the returned value may change after reading.
* @note The returned value can be less than zero when there are waiting
* threads on the internal semaphore.
*
* @param[in] mbp the pointer to an initialized mailbox_t object
* @return The number of empty message slots.
*
* @iclass
*/
static inline cnt_t chMBGetFreeCountI(mailbox_t *mbp) {
chDbgCheckClassI();
return chSemGetCounterI(&mbp->mb_emptysem);
}
/**
* @brief Returns the number of used message slots into a mailbox.
* @note Can be invoked in any system state but if invoked out of a locked
* state then the returned value may change after reading.
* @note The returned value can be less than zero when there are waiting
* threads on the internal semaphore.
*
* @param[in] mbp the pointer to an initialized mailbox_t object
* @return The number of queued messages.
*
* @iclass
*/
static inline cnt_t chMBGetUsedCountI(mailbox_t *mbp) {
chDbgCheckClassI();
return chSemGetCounterI(&mbp->mb_fullsem);
}
/**
* @brief Returns the next message in the queue without removing it.
* @pre A message must be waiting in the queue for this function to work
* or it would return garbage. The correct way to use this macro is
* to use @p chMBGetFullCountI() and then use this macro, all within
* a lock state.
*
* @param[in] mbp the pointer to an initialized mailbox_t object
* @return The next message in queue.
*
* @iclass
*/
static inline msg_t chMBPeekI(mailbox_t *mbp) {
chDbgCheckClassI();
return *mbp->mb_rdptr;
}
#endif /* CH_CFG_USE_MAILBOXES == TRUE */
#endif /* _CHMBOXES_H_ */
/** @} */

View File

@ -1,168 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file chmempools.h
* @brief Memory Pools macros and structures.
*
* @addtogroup pools
* @{
*/
#ifndef _CHMEMPOOLS_H_
#define _CHMEMPOOLS_H_
#if (CH_CFG_USE_MEMPOOLS == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Module constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Module pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if CH_CFG_USE_MEMCORE == FALSE
#error "CH_CFG_USE_MEMPOOLS requires CH_CFG_USE_MEMCORE"
#endif
/*===========================================================================*/
/* Module data structures and types. */
/*===========================================================================*/
/**
* @brief Memory pool free object header.
*/
struct pool_header {
struct pool_header *ph_next; /**< @brief Pointer to the next pool
header in the list. */
};
/**
* @brief Memory pool descriptor.
*/
typedef struct {
struct pool_header *mp_next; /**< @brief Pointer to the header. */
size_t mp_object_size; /**< @brief Memory pool objects
size. */
memgetfunc_t mp_provider; /**< @brief Memory blocks provider
for this pool. */
} memory_pool_t;
/*===========================================================================*/
/* Module macros. */
/*===========================================================================*/
/**
* @brief Data part of a static memory pool initializer.
* @details This macro should be used when statically initializing a
* memory pool that is part of a bigger structure.
*
* @param[in] name the name of the memory pool variable
* @param[in] size size of the memory pool contained objects
* @param[in] provider memory provider function for the memory pool
*/
#define _MEMORYPOOL_DATA(name, size, provider) \
{NULL, size, provider}
/**
* @brief Static memory pool initializer in hungry mode.
* @details Statically initialized memory pools require no explicit
* initialization using @p chPoolInit().
*
* @param[in] name the name of the memory pool variable
* @param[in] size size of the memory pool contained objects
* @param[in] provider memory provider function for the memory pool or @p NULL
* if the pool is not allowed to grow automatically
*/
#define MEMORYPOOL_DECL(name, size, provider) \
memory_pool_t name = _MEMORYPOOL_DATA(name, size, provider)
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void chPoolObjectInit(memory_pool_t *mp, size_t size, memgetfunc_t provider);
void chPoolLoadArray(memory_pool_t *mp, void *p, size_t n);
void *chPoolAllocI(memory_pool_t *mp);
void *chPoolAlloc(memory_pool_t *mp);
void chPoolFreeI(memory_pool_t *mp, void *objp);
void chPoolFree(memory_pool_t *mp, void *objp);
#ifdef __cplusplus
}
#endif
/*===========================================================================*/
/* Module inline functions. */
/*===========================================================================*/
/**
* @brief Adds an object to a memory pool.
* @pre The memory pool must be already been initialized.
* @pre The added object must be of the right size for the specified
* memory pool.
* @pre The added object must be memory aligned to the size of
* @p stkalign_t type.
* @note This function is just an alias for @p chPoolFree() and has been
* added for clarity.
*
* @param[in] mp pointer to a @p memory_pool_t structure
* @param[in] objp the pointer to the object to be added
*
* @api
*/
static inline void chPoolAdd(memory_pool_t *mp, void *objp) {
chPoolFree(mp, objp);
}
/**
* @brief Adds an object to a memory pool.
* @pre The memory pool must be already been initialized.
* @pre The added object must be of the right size for the specified
* memory pool.
* @pre The added object must be memory aligned to the size of
* @p stkalign_t type.
* @note This function is just an alias for @p chPoolFree() and has been
* added for clarity.
*
* @param[in] mp pointer to a @p memory_pool_t structure
* @param[in] objp the pointer to the object to be added
*
* @iclass
*/
static inline void chPoolAddI(memory_pool_t *mp, void *objp) {
chDbgCheckClassI();
chPoolFreeI(mp, objp);
}
#endif /* CH_CFG_USE_MEMPOOLS == TRUE */
#endif /* _CHMEMPOOLS_H_ */
/** @} */

View File

@ -80,7 +80,7 @@ static inline bool chMsgIsPendingI(thread_t *tp) {
chDbgCheckClassI(); chDbgCheckClassI();
return (bool)(tp->p_msgqueue.p_next != (thread_t *)&tp->p_msgqueue); return (bool)(tp->msgqueue.next != (thread_t *)&tp->msgqueue);
} }
/** /**
@ -95,9 +95,9 @@ static inline bool chMsgIsPendingI(thread_t *tp) {
*/ */
static inline msg_t chMsgGet(thread_t *tp) { static inline msg_t chMsgGet(thread_t *tp) {
chDbgAssert(tp->p_state == CH_STATE_SNDMSG, "invalid state"); chDbgAssert(tp->state == CH_STATE_SNDMSG, "invalid state");
return tp->p_u.sentmsg; return tp->u.sentmsg;
} }
/** /**

View File

@ -55,14 +55,14 @@ typedef struct ch_mutex mutex_t;
* @brief Mutex structure. * @brief Mutex structure.
*/ */
struct ch_mutex { struct ch_mutex {
threads_queue_t m_queue; /**< @brief Queue of the threads sleeping threads_queue_t queue; /**< @brief Queue of the threads sleeping
on this mutex. */ on this mutex. */
thread_t *m_owner; /**< @brief Owner @p thread_t pointer or thread_t *owner; /**< @brief Owner @p thread_t pointer or
@p NULL. */ @p NULL. */
mutex_t *m_next; /**< @brief Next @p mutex_t into an mutex_t *next; /**< @brief Next @p mutex_t into an
owner-list or @p NULL. */ owner-list or @p NULL. */
#if (CH_CFG_USE_MUTEXES_RECURSIVE == TRUE) || defined(__DOXYGEN__) #if (CH_CFG_USE_MUTEXES_RECURSIVE == TRUE) || defined(__DOXYGEN__)
cnt_t m_cnt; /**< @brief Mutex recursion counter. */ cnt_t cnt; /**< @brief Mutex recursion counter. */
#endif #endif
}; };
@ -78,9 +78,9 @@ struct ch_mutex {
* @param[in] name the name of the mutex variable * @param[in] name the name of the mutex variable
*/ */
#if (CH_CFG_USE_MUTEXES_RECURSIVE == TRUE) || defined(__DOXYGEN__) #if (CH_CFG_USE_MUTEXES_RECURSIVE == TRUE) || defined(__DOXYGEN__)
#define _MUTEX_DATA(name) {_THREADS_QUEUE_DATA(name.m_queue), NULL, NULL, 0} #define _MUTEX_DATA(name) {_THREADS_QUEUE_DATA(name.queue), NULL, NULL, 0}
#else #else
#define _MUTEX_DATA(name) {_THREADS_QUEUE_DATA(name.m_queue), NULL, NULL} #define _MUTEX_DATA(name) {_THREADS_QUEUE_DATA(name.queue), NULL, NULL}
#endif #endif
/** /**
@ -130,7 +130,7 @@ static inline bool chMtxQueueNotEmptyS(mutex_t *mp) {
chDbgCheckClassS(); chDbgCheckClassS();
return queue_notempty(&mp->m_queue); return queue_notempty(&mp->queue);
} }
/** /**
@ -143,7 +143,7 @@ static inline bool chMtxQueueNotEmptyS(mutex_t *mp) {
*/ */
static inline mutex_t *chMtxGetNextMutexS(void) { static inline mutex_t *chMtxGetNextMutexS(void) {
return chThdGetSelfX()->p_mtxlist; return chThdGetSelfX()->mtxlist;
} }
#endif /* CH_CFG_USE_MUTEXES == TRUE */ #endif /* CH_CFG_USE_MUTEXES == TRUE */

View File

@ -75,15 +75,15 @@ typedef void (*qnotify_t)(io_queue_t *qp);
* @ref system_states) and is non-blocking. * @ref system_states) and is non-blocking.
*/ */
struct io_queue { struct io_queue {
threads_queue_t q_waiting; /**< @brief Queue of waiting threads. */ threads_queue_t waiting; /**< @brief Queue of waiting threads. */
volatile size_t q_counter; /**< @brief Resources counter. */ volatile size_t counter; /**< @brief Resources counter. */
uint8_t *q_buffer; /**< @brief Pointer to the queue buffer.*/ uint8_t *buffer; /**< @brief Pointer to the queue buffer.*/
uint8_t *q_top; /**< @brief Pointer to the first location uint8_t *top; /**< @brief Pointer to the first location
after the buffer. */ after the buffer. */
uint8_t *q_wrptr; /**< @brief Write pointer. */ uint8_t *wrptr; /**< @brief Write pointer. */
uint8_t *q_rdptr; /**< @brief Read pointer. */ uint8_t *rdptr; /**< @brief Read pointer. */
qnotify_t q_notify; /**< @brief Data notification callback. */ qnotify_t notify; /**< @brief Data notification callback. */
void *q_link; /**< @brief Application defined field. */ void *link; /**< @brief Application defined field. */
}; };
/** /**
@ -202,7 +202,7 @@ typedef io_queue_t output_queue_t;
*/ */
#define chQSizeX(qp) \ #define chQSizeX(qp) \
/*lint -save -e9033 [10.8] The cast is safe.*/ \ /*lint -save -e9033 [10.8] The cast is safe.*/ \
((size_t)((qp)->q_top - (qp)->q_buffer)) \ ((size_t)((qp)->top - (qp)->buffer)) \
/*lint -restore*/ /*lint -restore*/
/** /**
@ -215,7 +215,7 @@ typedef io_queue_t output_queue_t;
* *
* @iclass * @iclass
*/ */
#define chQSpaceI(qp) ((qp)->q_counter) #define chQSpaceI(qp) ((qp)->counter)
/** /**
* @brief Returns the queue application-defined link. * @brief Returns the queue application-defined link.
@ -225,7 +225,7 @@ typedef io_queue_t output_queue_t;
* *
* @xclass * @xclass
*/ */
#define chQGetLinkX(qp) ((qp)->q_link) #define chQGetLinkX(qp) ((qp)->link)
/** @} */ /** @} */
/*===========================================================================*/ /*===========================================================================*/
@ -322,7 +322,7 @@ static inline bool chIQIsFullI(input_queue_t *iqp) {
chDbgCheckClassI(); chDbgCheckClassI();
/*lint -save -e9007 [13.5] No side effects.*/ /*lint -save -e9007 [13.5] No side effects.*/
return (bool)((iqp->q_wrptr == iqp->q_rdptr) && (iqp->q_counter != 0U)); return (bool)((iqp->wrptr == iqp->rdptr) && (iqp->counter != 0U));
/*lint -restore*/ /*lint -restore*/
} }
@ -390,7 +390,7 @@ static inline bool chOQIsEmptyI(output_queue_t *oqp) {
chDbgCheckClassI(); chDbgCheckClassI();
/*lint -save -e9007 [13.5] No side effects.*/ /*lint -save -e9007 [13.5] No side effects.*/
return (bool)((oqp->q_wrptr == oqp->q_rdptr) && (oqp->q_counter != 0U)); return (bool)((oqp->wrptr == oqp->rdptr) && (oqp->counter != 0U));
/*lint -restore*/ /*lint -restore*/
} }

View File

@ -50,26 +50,24 @@
* @brief ChibiOS/RT memory signature record. * @brief ChibiOS/RT memory signature record.
*/ */
typedef struct { typedef struct {
char ch_identifier[4]; /**< @brief Always set to "main". */ char identifier[4]; /**< @brief Always set to "main". */
uint8_t ch_zero; /**< @brief Must be zero. */ uint8_t zero; /**< @brief Must be zero. */
uint8_t ch_size; /**< @brief Size of this structure. */ uint8_t size; /**< @brief Size of this structure. */
uint16_t ch_version; /**< @brief Encoded ChibiOS/RT version. */ uint16_t version; /**< @brief Encoded ChibiOS/RT version. */
uint8_t ch_ptrsize; /**< @brief Size of a pointer. */ uint8_t ptrsize; /**< @brief Size of a pointer. */
uint8_t ch_timesize; /**< @brief Size of a @p systime_t. */ uint8_t timesize; /**< @brief Size of a @p systime_t. */
uint8_t ch_threadsize; /**< @brief Size of a @p thread_t. */ uint8_t threadsize; /**< @brief Size of a @p thread_t. */
uint8_t cf_off_prio; /**< @brief Offset of @p p_prio field. */ uint8_t off_prio; /**< @brief Offset of @p prio field. */
uint8_t cf_off_ctx; /**< @brief Offset of @p p_ctx field. */ uint8_t off_ctx; /**< @brief Offset of @p ctx field. */
uint8_t cf_off_newer; /**< @brief Offset of @p p_newer field. */ uint8_t off_newer; /**< @brief Offset of @p newer field. */
uint8_t cf_off_older; /**< @brief Offset of @p p_older field. */ uint8_t off_older; /**< @brief Offset of @p older field. */
uint8_t cf_off_name; /**< @brief Offset of @p p_name field. */ uint8_t off_name; /**< @brief Offset of @p name field. */
uint8_t cf_off_stklimit; /**< @brief Offset of @p p_stklimit uint8_t off_stklimit; /**< @brief Offset of @p stklimit field.*/
field. */ uint8_t off_state; /**< @brief Offset of @p state field. */
uint8_t cf_off_state; /**< @brief Offset of @p p_state field. */ uint8_t off_flags; /**< @brief Offset of @p flags field. */
uint8_t cf_off_flags; /**< @brief Offset of @p p_flags field. */ uint8_t off_refs; /**< @brief Offset of @p refs field. */
uint8_t cf_off_refs; /**< @brief Offset of @p p_refs field. */ uint8_t off_preempt; /**< @brief Offset of @p preempt field. */
uint8_t cf_off_preempt; /**< @brief Offset of @p p_preempt uint8_t off_time; /**< @brief Offset of @p time field. */
field. */
uint8_t cf_off_time; /**< @brief Offset of @p p_time field. */
} chdebug_t; } chdebug_t;
/*===========================================================================*/ /*===========================================================================*/
@ -83,8 +81,8 @@ typedef struct {
* @param[in] tp thread to remove from the registry * @param[in] tp thread to remove from the registry
*/ */
#define REG_REMOVE(tp) { \ #define REG_REMOVE(tp) { \
(tp)->p_older->p_newer = (tp)->p_newer; \ (tp)->older->newer = (tp)->newer; \
(tp)->p_newer->p_older = (tp)->p_older; \ (tp)->newer->older = (tp)->older; \
} }
/** /**
@ -94,10 +92,10 @@ typedef struct {
* @param[in] tp thread to add to the registry * @param[in] tp thread to add to the registry
*/ */
#define REG_INSERT(tp) { \ #define REG_INSERT(tp) { \
(tp)->p_newer = (thread_t *)&ch.rlist; \ (tp)->newer = (thread_t *)&ch.rlist; \
(tp)->p_older = ch.rlist.r_older; \ (tp)->older = ch.rlist.older; \
(tp)->p_older->p_newer = (tp); \ (tp)->older->newer = (tp); \
ch.rlist.r_older = (tp); \ ch.rlist.older = (tp); \
} }
/*===========================================================================*/ /*===========================================================================*/
@ -132,7 +130,7 @@ extern "C" {
static inline void chRegSetThreadName(const char *name) { static inline void chRegSetThreadName(const char *name) {
#if CH_CFG_USE_REGISTRY == TRUE #if CH_CFG_USE_REGISTRY == TRUE
ch.rlist.r_current->p_name = name; ch.rlist.current->name = name;
#else #else
(void)name; (void)name;
#endif #endif
@ -152,7 +150,7 @@ static inline void chRegSetThreadName(const char *name) {
static inline const char *chRegGetThreadNameX(thread_t *tp) { static inline const char *chRegGetThreadNameX(thread_t *tp) {
#if CH_CFG_USE_REGISTRY == TRUE #if CH_CFG_USE_REGISTRY == TRUE
return tp->p_name; return tp->name;
#else #else
(void)tp; (void)tp;
return NULL; return NULL;
@ -172,7 +170,7 @@ static inline const char *chRegGetThreadNameX(thread_t *tp) {
static inline void chRegSetThreadNameX(thread_t *tp, const char *name) { static inline void chRegSetThreadNameX(thread_t *tp, const char *name) {
#if CH_CFG_USE_REGISTRY == TRUE #if CH_CFG_USE_REGISTRY == TRUE
tp->p_name = name; tp->name = name;
#else #else
(void)tp; (void)tp;
(void)name; (void)name;

View File

@ -108,20 +108,8 @@
/** @} */ /** @} */
/** /**
* @name Working Areas and Alignment * @name Working Areas
*/ */
/**
* @brief Enforces a correct alignment for a stack area size value.
*
* @param[in] n the stack size to be aligned to the next stack
* alignment boundary
* @return The aligned stack size.
*
* @api
*/
#define THD_ALIGN_STACK_SIZE(n) \
(((((size_t)(n)) - 1U) | (sizeof(stkalign_t) - 1U)) + 1U)
/** /**
* @brief Calculates the total Working Area size. * @brief Calculates the total Working Area size.
* *
@ -131,7 +119,7 @@
* @api * @api
*/ */
#define THD_WORKING_AREA_SIZE(n) \ #define THD_WORKING_AREA_SIZE(n) \
THD_ALIGN_STACK_SIZE(sizeof(thread_t) + PORT_WA_SIZE(n)) MEM_ALIGN_NEXT(sizeof(thread_t) + PORT_WA_SIZE(n), PORT_STACK_ALIGN)
/** /**
* @brief Static working area allocation. * @brief Static working area allocation.
@ -143,8 +131,22 @@
* *
* @api * @api
*/ */
#define THD_WORKING_AREA(s, n) \ #define THD_WORKING_AREA(s, n) PORT_WORKING_AREA(s, n)
stkalign_t s[THD_WORKING_AREA_SIZE(n) / sizeof(stkalign_t)]
/**
* @brief Base of a working area casted to the correct type.
*
* @param[in] s name of the working area
*/
#define THD_WORKING_AREA_BASE(s) ((stkalign_t *)(s))
/**
* @brief End of a working area casted to the correct type.
*
* @param[in] s name of the working area
*/
#define THD_WORKING_AREA_END(s) (THD_WORKING_AREA_BASE(s) + \
(sizeof (s) / sizeof (stkalign_t)))
/** @} */ /** @} */
/** /**
@ -166,6 +168,18 @@
/* Derived constants and error checks. */ /* Derived constants and error checks. */
/*===========================================================================*/ /*===========================================================================*/
#if !defined(CH_CFG_IDLE_ENTER_HOOK)
#error "CH_CFG_IDLE_ENTER_HOOK not defined in chconf.h"
#endif
#if !defined(CH_CFG_IDLE_LEAVE_HOOK)
#error "CH_CFG_IDLE_LEAVE_HOOK not defined in chconf.h"
#endif
#if !defined(CH_CFG_IDLE_LOOP_HOOK)
#error "CH_CFG_IDLE_LOOP_HOOK not defined in chconf.h"
#endif
/*===========================================================================*/ /*===========================================================================*/
/* Module data structures and types. */ /* Module data structures and types. */
/*===========================================================================*/ /*===========================================================================*/
@ -174,15 +188,15 @@
* @brief Generic threads single link list, it works like a stack. * @brief Generic threads single link list, it works like a stack.
*/ */
struct ch_threads_list { struct ch_threads_list {
thread_t *p_next; /**< @brief Next in the list/queue. */ thread_t *next; /**< @brief Next in the list/queue. */
}; };
/** /**
* @brief Generic threads bidirectional linked list header and element. * @brief Generic threads bidirectional linked list header and element.
*/ */
struct ch_threads_queue { struct ch_threads_queue {
thread_t *p_next; /**< @brief Next in the list/queue. */ thread_t *next; /**< @brief Next in the list/queue. */
thread_t *p_prev; /**< @brief Previous in the queue. */ thread_t *prev; /**< @brief Previous in the queue. */
}; };
/** /**
@ -192,55 +206,44 @@ struct ch_threads_queue {
* by shrinking this structure. * by shrinking this structure.
*/ */
struct ch_thread { struct ch_thread {
thread_t *p_next; /**< @brief Next in the list/queue. */ thread_t *next; /**< @brief Next in the list/queue. */
/* End of the fields shared with the threads_list_t structure.*/ /* End of the fields shared with the threads_list_t structure.*/
thread_t *p_prev; /**< @brief Previous in the queue. */ thread_t *prev; /**< @brief Previous in the queue. */
/* End of the fields shared with the threads_queue_t structure.*/ /* End of the fields shared with the threads_queue_t structure.*/
tprio_t p_prio; /**< @brief Thread priority. */ tprio_t prio; /**< @brief Thread priority. */
struct context p_ctx; /**< @brief Processor context. */ struct port_context ctx; /**< @brief Processor context. */
#if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__) #if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__)
thread_t *p_newer; /**< @brief Newer registry element. */ thread_t *newer; /**< @brief Newer registry element. */
thread_t *p_older; /**< @brief Older registry element. */ thread_t *older; /**< @brief Older registry element. */
#endif #endif
/* End of the fields shared with the ReadyList structure. */ /* End of the fields shared with the ReadyList structure. */
#if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__) #if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__)
/** /**
* @brief Thread name or @p NULL. * @brief Thread name or @p NULL.
*/ */
const char *p_name; const char *name;
#endif #endif
#if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || defined(__DOXYGEN__)
/** /**
* @brief Thread stack boundary. * @brief Thread stack boundary.
* @note This pointer matches with the working area base address.
*/ */
stkalign_t *p_stklimit; stkalign_t *stklimit;
#endif
/** /**
* @brief Current thread state. * @brief Current thread state.
*/ */
tstate_t p_state; tstate_t state;
/**
* @brief Various thread flags.
*/
tmode_t p_flags;
#if (CH_CFG_USE_DYNAMIC == TRUE) || defined(__DOXYGEN__)
/**
* @brief References to this thread.
*/
trefs_t p_refs;
#endif
/** /**
* @brief Number of ticks remaining to this thread. * @brief Number of ticks remaining to this thread.
*/ */
#if (CH_CFG_TIME_QUANTUM > 0) || defined(__DOXYGEN__) #if (CH_CFG_TIME_QUANTUM > 0) || defined(__DOXYGEN__)
tslices_t p_preempt; tslices_t preempt;
#endif #endif
#if (CH_DBG_THREADS_PROFILING == TRUE) || defined(__DOXYGEN__) #if (CH_DBG_THREADS_PROFILING == TRUE) || defined(__DOXYGEN__)
/** /**
* @brief Thread consumed time in ticks. * @brief Thread consumed time in ticks.
* @note This field can overflow. * @note This field can overflow.
*/ */
volatile systime_t p_time; volatile systime_t time;
#endif #endif
/** /**
* @brief State-specific fields. * @brief State-specific fields.
@ -308,48 +311,41 @@ struct ch_thread {
*/ */
eventmask_t ewmask; eventmask_t ewmask;
#endif #endif
} p_u; } u;
#if (CH_CFG_USE_WAITEXIT == TRUE) || defined(__DOXYGEN__) #if (CH_CFG_USE_WAITEXIT == TRUE) || defined(__DOXYGEN__)
/** /**
* @brief Termination waiting list. * @brief Termination waiting list.
*/ */
threads_list_t p_waiting; threads_list_t waiting;
#endif #endif
#if (CH_CFG_USE_MESSAGES == TRUE) || defined(__DOXYGEN__) #if (CH_CFG_USE_MESSAGES == TRUE) || defined(__DOXYGEN__)
/** /**
* @brief Messages queue. * @brief Messages queue.
*/ */
threads_queue_t p_msgqueue; threads_queue_t msgqueue;
#endif #endif
#if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__) #if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__)
/** /**
* @brief Pending events mask. * @brief Pending events mask.
*/ */
eventmask_t p_epending; eventmask_t epending;
#endif #endif
#if (CH_CFG_USE_MUTEXES == TRUE) || defined(__DOXYGEN__) #if (CH_CFG_USE_MUTEXES == TRUE) || defined(__DOXYGEN__)
/** /**
* @brief List of the mutexes owned by this thread. * @brief List of the mutexes owned by this thread.
* @note The list is terminated by a @p NULL in this field. * @note The list is terminated by a @p NULL in this field.
*/ */
struct ch_mutex *p_mtxlist; struct ch_mutex *mtxlist;
/** /**
* @brief Thread's own, non-inherited, priority. * @brief Thread's own, non-inherited, priority.
*/ */
tprio_t p_realprio; tprio_t realprio;
#endif
#if ((CH_CFG_USE_DYNAMIC == TRUE) && (CH_CFG_USE_MEMPOOLS == TRUE)) || \
defined(__DOXYGEN__)
/**
* @brief Memory Pool where the thread workspace is returned.
*/
void *p_mpool;
#endif #endif
#if (CH_DBG_STATISTICS == TRUE) || defined(__DOXYGEN__) #if (CH_DBG_STATISTICS == TRUE) || defined(__DOXYGEN__)
/** /**
* @brief Thread statistics. * @brief Thread statistics.
*/ */
time_measurement_t p_stats; time_measurement_t stats;
#endif #endif
#if defined(CH_CFG_THREAD_EXTRA_FIELDS) #if defined(CH_CFG_THREAD_EXTRA_FIELDS)
/* Extra fields defined in chconf.h.*/ /* Extra fields defined in chconf.h.*/
@ -363,12 +359,12 @@ struct ch_thread {
* @brief Virtual Timer descriptor structure. * @brief Virtual Timer descriptor structure.
*/ */
struct ch_virtual_timer { struct ch_virtual_timer {
virtual_timer_t *vt_next; /**< @brief Next timer in the list. */ virtual_timer_t *next; /**< @brief Next timer in the list. */
virtual_timer_t *vt_prev; /**< @brief Previous timer in the list. */ virtual_timer_t *prev; /**< @brief Previous timer in the list. */
systime_t vt_delta; /**< @brief Time delta before timeout. */ systime_t delta; /**< @brief Time delta before timeout. */
vtfunc_t vt_func; /**< @brief Timer callback function vtfunc_t func; /**< @brief Timer callback function
pointer. */ pointer. */
void *vt_par; /**< @brief Timer callback function void *par; /**< @brief Timer callback function
parameter. */ parameter. */
}; };
@ -379,19 +375,19 @@ struct ch_virtual_timer {
* timer is often used in the code. * timer is often used in the code.
*/ */
struct ch_virtual_timers_list { struct ch_virtual_timers_list {
virtual_timer_t *vt_next; /**< @brief Next timer in the delta virtual_timer_t *next; /**< @brief Next timer in the delta
list. */ list. */
virtual_timer_t *vt_prev; /**< @brief Last timer in the delta virtual_timer_t *prev; /**< @brief Last timer in the delta
list. */ list. */
systime_t vt_delta; /**< @brief Must be initialized to -1. */ systime_t delta; /**< @brief Must be initialized to -1. */
#if (CH_CFG_ST_TIMEDELTA == 0) || defined(__DOXYGEN__) #if (CH_CFG_ST_TIMEDELTA == 0) || defined(__DOXYGEN__)
volatile systime_t vt_systime; /**< @brief System Time counter. */ volatile systime_t systime; /**< @brief System Time counter. */
#endif #endif
#if (CH_CFG_ST_TIMEDELTA > 0) || defined(__DOXYGEN__) #if (CH_CFG_ST_TIMEDELTA > 0) || defined(__DOXYGEN__)
/** /**
* @brief System time of the last tick event. * @brief System time of the last tick event.
*/ */
systime_t vt_lasttime;/**< @brief System time of the last systime_t lasttime; /**< @brief System time of the last
tick event. */ tick event. */
#endif #endif
}; };
@ -400,17 +396,17 @@ struct ch_virtual_timers_list {
* @extends threads_queue_t * @extends threads_queue_t
*/ */
struct ch_ready_list { struct ch_ready_list {
threads_queue_t r_queue; /**< @brief Threads queue. */ threads_queue_t queue; /**< @brief Threads queue. */
tprio_t r_prio; /**< @brief This field must be tprio_t prio; /**< @brief This field must be
initialized to zero. */ initialized to zero. */
struct context r_ctx; /**< @brief Not used, present because struct port_context ctx; /**< @brief Not used, present because
offsets. */ offsets. */
#if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__) #if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__)
thread_t *r_newer; /**< @brief Newer registry element. */ thread_t *newer; /**< @brief Newer registry element. */
thread_t *r_older; /**< @brief Older registry element. */ thread_t *older; /**< @brief Older registry element. */
#endif #endif
/* End of the fields shared with the thread_t structure.*/ /* End of the fields shared with the thread_t structure.*/
thread_t *r_current; /**< @brief The currently running thread_t *current; /**< @brief The currently running
thread. */ thread. */
}; };
@ -436,7 +432,7 @@ struct ch_system_debug {
*/ */
cnt_t lock_cnt; cnt_t lock_cnt;
#endif #endif
#if (CH_DBG_ENABLE_TRACE == TRUE) || defined(__DOXYGEN__) #if (CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_NONE) || defined(__DOXYGEN__)
/** /**
* @brief Public trace buffer. * @brief Public trace buffer.
*/ */
@ -478,7 +474,7 @@ struct ch_system {
*/ */
kernel_stats_t kernel_stats; kernel_stats_t kernel_stats;
#endif #endif
#if (CH_CFG_NO_IDLE_THREAD == FALSE) || defined(__DOXYGEN__) #if CH_CFG_NO_IDLE_THREAD == FALSE
/** /**
* @brief Idle thread working area. * @brief Idle thread working area.
*/ */
@ -495,25 +491,14 @@ struct ch_system {
* *
* @notapi * @notapi
*/ */
#define firstprio(rlp) ((rlp)->p_next->p_prio) #define firstprio(rlp) ((rlp)->next->prio)
/** /**
* @brief Current thread pointer access macro. * @brief Current thread pointer access macro.
* @note This macro is not meant to be used in the application code but * @note This macro is not meant to be used in the application code but
* only from within the kernel, use the @p chThdSelf() API instead. * only from within the kernel, use @p chThdGetSelfX() instead.
* @note It is forbidden to use this macro in order to change the pointer
* (currp = something), use @p setcurrp() instead.
*/ */
#define currp ch.rlist.r_current #define currp ch.rlist.current
/**
* @brief Current thread pointer change macro.
* @note This macro is not meant to be used in the application code but
* only from within the kernel.
*
* @notapi
*/
#define setcurrp(tp) (currp = (tp))
/*===========================================================================*/ /*===========================================================================*/
/* External declarations. */ /* External declarations. */
@ -531,6 +516,7 @@ extern "C" {
#endif #endif
void _scheduler_init(void); void _scheduler_init(void);
thread_t *chSchReadyI(thread_t *tp); thread_t *chSchReadyI(thread_t *tp);
thread_t *chSchReadyAheadI(thread_t *tp);
void chSchGoSleepS(tstate_t newstate); void chSchGoSleepS(tstate_t newstate);
msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time); msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time);
void chSchWakeupS(thread_t *ntp, msg_t msg); void chSchWakeupS(thread_t *ntp, msg_t msg);
@ -565,7 +551,7 @@ extern "C" {
*/ */
static inline void list_init(threads_list_t *tlp) { static inline void list_init(threads_list_t *tlp) {
tlp->p_next = (thread_t *)tlp; tlp->next = (thread_t *)tlp;
} }
/** /**
@ -578,7 +564,7 @@ static inline void list_init(threads_list_t *tlp) {
*/ */
static inline bool list_isempty(threads_list_t *tlp) { static inline bool list_isempty(threads_list_t *tlp) {
return (bool)(tlp->p_next == (thread_t *)tlp); return (bool)(tlp->next == (thread_t *)tlp);
} }
/** /**
@ -591,7 +577,7 @@ static inline bool list_isempty(threads_list_t *tlp) {
*/ */
static inline bool list_notempty(threads_list_t *tlp) { static inline bool list_notempty(threads_list_t *tlp) {
return (bool)(tlp->p_next != (thread_t *)tlp); return (bool)(tlp->next != (thread_t *)tlp);
} }
/** /**
@ -603,8 +589,8 @@ static inline bool list_notempty(threads_list_t *tlp) {
*/ */
static inline void queue_init(threads_queue_t *tqp) { static inline void queue_init(threads_queue_t *tqp) {
tqp->p_next = (thread_t *)tqp; tqp->next = (thread_t *)tqp;
tqp->p_prev = (thread_t *)tqp; tqp->prev = (thread_t *)tqp;
} }
/** /**
@ -617,7 +603,7 @@ static inline void queue_init(threads_queue_t *tqp) {
*/ */
static inline bool queue_isempty(const threads_queue_t *tqp) { static inline bool queue_isempty(const threads_queue_t *tqp) {
return (bool)(tqp->p_next == (const thread_t *)tqp); return (bool)(tqp->next == (const thread_t *)tqp);
} }
/** /**
@ -630,7 +616,7 @@ static inline bool queue_isempty(const threads_queue_t *tqp) {
*/ */
static inline bool queue_notempty(const threads_queue_t *tqp) { static inline bool queue_notempty(const threads_queue_t *tqp) {
return (bool)(tqp->p_next != (const thread_t *)tqp); return (bool)(tqp->next != (const thread_t *)tqp);
} }
/* If the performance code path has been chosen then all the following /* If the performance code path has been chosen then all the following
@ -638,14 +624,14 @@ static inline bool queue_notempty(const threads_queue_t *tqp) {
#if CH_CFG_OPTIMIZE_SPEED == TRUE #if CH_CFG_OPTIMIZE_SPEED == TRUE
static inline void list_insert(thread_t *tp, threads_list_t *tlp) { static inline void list_insert(thread_t *tp, threads_list_t *tlp) {
tp->p_next = tlp->p_next; tp->next = tlp->next;
tlp->p_next = tp; tlp->next = tp;
} }
static inline thread_t *list_remove(threads_list_t *tlp) { static inline thread_t *list_remove(threads_list_t *tlp) {
thread_t *tp = tlp->p_next; thread_t *tp = tlp->next;
tlp->p_next = tp->p_next; tlp->next = tp->next;
return tp; return tp;
} }
@ -654,44 +640,44 @@ static inline void queue_prio_insert(thread_t *tp, threads_queue_t *tqp) {
thread_t *cp = (thread_t *)tqp; thread_t *cp = (thread_t *)tqp;
do { do {
cp = cp->p_next; cp = cp->next;
} while ((cp != (thread_t *)tqp) && (cp->p_prio >= tp->p_prio)); } while ((cp != (thread_t *)tqp) && (cp->prio >= tp->prio));
tp->p_next = cp; tp->next = cp;
tp->p_prev = cp->p_prev; tp->prev = cp->prev;
tp->p_prev->p_next = tp; tp->prev->next = tp;
cp->p_prev = tp; cp->prev = tp;
} }
static inline void queue_insert(thread_t *tp, threads_queue_t *tqp) { static inline void queue_insert(thread_t *tp, threads_queue_t *tqp) {
tp->p_next = (thread_t *)tqp; tp->next = (thread_t *)tqp;
tp->p_prev = tqp->p_prev; tp->prev = tqp->prev;
tp->p_prev->p_next = tp; tp->prev->next = tp;
tqp->p_prev = tp; tqp->prev = tp;
} }
static inline thread_t *queue_fifo_remove(threads_queue_t *tqp) { static inline thread_t *queue_fifo_remove(threads_queue_t *tqp) {
thread_t *tp = tqp->p_next; thread_t *tp = tqp->next;
tqp->p_next = tp->p_next; tqp->next = tp->next;
tqp->p_next->p_prev = (thread_t *)tqp; tqp->next->prev = (thread_t *)tqp;
return tp; return tp;
} }
static inline thread_t *queue_lifo_remove(threads_queue_t *tqp) { static inline thread_t *queue_lifo_remove(threads_queue_t *tqp) {
thread_t *tp = tqp->p_prev; thread_t *tp = tqp->prev;
tqp->p_prev = tp->p_prev; tqp->prev = tp->prev;
tqp->p_prev->p_next = (thread_t *)tqp; tqp->prev->next = (thread_t *)tqp;
return tp; return tp;
} }
static inline thread_t *queue_dequeue(thread_t *tp) { static inline thread_t *queue_dequeue(thread_t *tp) {
tp->p_prev->p_next = tp->p_next; tp->prev->next = tp->next;
tp->p_next->p_prev = tp->p_prev; tp->next->prev = tp->prev;
return tp; return tp;
} }
@ -712,7 +698,7 @@ static inline bool chSchIsRescRequiredI(void) {
chDbgCheckClassI(); chDbgCheckClassI();
return firstprio(&ch.rlist.r_queue) > currp->p_prio; return firstprio(&ch.rlist.queue) > currp->prio;
} }
/** /**
@ -730,7 +716,7 @@ static inline bool chSchCanYieldS(void) {
chDbgCheckClassS(); chDbgCheckClassS();
return firstprio(&ch.rlist.r_queue) >= currp->p_prio; return firstprio(&ch.rlist.queue) >= currp->prio;
} }
/** /**
@ -757,11 +743,11 @@ static inline void chSchDoYieldS(void) {
* @special * @special
*/ */
static inline void chSchPreemption(void) { static inline void chSchPreemption(void) {
tprio_t p1 = firstprio(&ch.rlist.r_queue); tprio_t p1 = firstprio(&ch.rlist.queue);
tprio_t p2 = currp->p_prio; tprio_t p2 = currp->prio;
#if CH_CFG_TIME_QUANTUM > 0 #if CH_CFG_TIME_QUANTUM > 0
if (currp->p_preempt > (tslices_t)0) { if (currp->preempt > (tslices_t)0) {
if (p1 > p2) { if (p1 > p2) {
chSchDoRescheduleAhead(); chSchDoRescheduleAhead();
} }

View File

@ -50,9 +50,9 @@
* @brief Semaphore structure. * @brief Semaphore structure.
*/ */
typedef struct ch_semaphore { typedef struct ch_semaphore {
threads_queue_t s_queue; /**< @brief Queue of the threads sleeping threads_queue_t queue; /**< @brief Queue of the threads sleeping
on this semaphore. */ on this semaphore. */
cnt_t s_cnt; /**< @brief The semaphore counter. */ cnt_t cnt; /**< @brief The semaphore counter. */
} semaphore_t; } semaphore_t;
/*===========================================================================*/ /*===========================================================================*/
@ -68,7 +68,7 @@ typedef struct ch_semaphore {
* @param[in] n the counter initial value, this value must be * @param[in] n the counter initial value, this value must be
* non-negative * non-negative
*/ */
#define _SEMAPHORE_DATA(name, n) {_THREADS_QUEUE_DATA(name.s_queue), n} #define _SEMAPHORE_DATA(name, n) {_THREADS_QUEUE_DATA(name.queue), n}
/** /**
* @brief Static semaphore initializer. * @brief Static semaphore initializer.
@ -119,7 +119,7 @@ static inline void chSemFastWaitI(semaphore_t *sp) {
chDbgCheckClassI(); chDbgCheckClassI();
sp->s_cnt--; sp->cnt--;
} }
/** /**
@ -135,7 +135,7 @@ static inline void chSemFastSignalI(semaphore_t *sp) {
chDbgCheckClassI(); chDbgCheckClassI();
sp->s_cnt++; sp->cnt++;
} }
/** /**
@ -150,7 +150,7 @@ static inline cnt_t chSemGetCounterI(semaphore_t *sp) {
chDbgCheckClassI(); chDbgCheckClassI();
return sp->s_cnt; return sp->cnt;
} }
#endif /* CH_CFG_USE_SEMAPHORES == TRUE */ #endif /* CH_CFG_USE_SEMAPHORES == TRUE */

View File

@ -52,6 +52,26 @@
/* Derived constants and error checks. */ /* Derived constants and error checks. */
/*===========================================================================*/ /*===========================================================================*/
#if !defined(CH_CFG_IRQ_PROLOGUE_HOOK)
#error "CH_CFG_IRQ_PROLOGUE_HOOK not defined in chconf.h"
#endif
#if !defined(CH_CFG_IRQ_EPILOGUE_HOOK)
#error "CH_CFG_IRQ_EPILOGUE_HOOK not defined in chconf.h"
#endif
#if !defined(CH_CFG_CONTEXT_SWITCH_HOOK)
#error "CH_CFG_CONTEXT_SWITCH_HOOK not defined in chconf.h"
#endif
#if !defined(CH_CFG_SYSTEM_TICK_HOOK)
#error "CH_CFG_SYSTEM_TICK_HOOK not defined in chconf.h"
#endif
#if !defined(CH_CFG_SYSTEM_HALT_HOOK)
#error "CH_CFG_SYSTEM_HALT_HOOK not defined in chconf.h"
#endif
/*===========================================================================*/ /*===========================================================================*/
/* Module data structures and types. */ /* Module data structures and types. */
/*===========================================================================*/ /*===========================================================================*/
@ -108,7 +128,9 @@
*/ */
#define CH_IRQ_PROLOGUE() \ #define CH_IRQ_PROLOGUE() \
PORT_IRQ_PROLOGUE(); \ PORT_IRQ_PROLOGUE(); \
CH_CFG_IRQ_PROLOGUE_HOOK(); \
_stats_increase_irq(); \ _stats_increase_irq(); \
_dbg_trace_isr_enter(__func__); \
_dbg_check_enter_isr() _dbg_check_enter_isr()
/** /**
@ -121,6 +143,8 @@
*/ */
#define CH_IRQ_EPILOGUE() \ #define CH_IRQ_EPILOGUE() \
_dbg_check_leave_isr(); \ _dbg_check_leave_isr(); \
_dbg_trace_isr_leave(__func__); \
CH_CFG_IRQ_EPILOGUE_HOOK(); \
PORT_IRQ_EPILOGUE() PORT_IRQ_EPILOGUE()
/** /**
@ -261,7 +285,7 @@
*/ */
#define chSysSwitch(ntp, otp) { \ #define chSysSwitch(ntp, otp) { \
\ \
_dbg_trace(otp); \ _dbg_trace_switch(otp); \
_stats_ctxswc(ntp, otp); \ _stats_ctxswc(ntp, otp); \
CH_CFG_CONTEXT_SWITCH_HOOK(ntp, otp); \ CH_CFG_CONTEXT_SWITCH_HOOK(ntp, otp); \
port_switch(ntp, otp); \ port_switch(ntp, otp); \
@ -280,7 +304,7 @@ extern "C" {
void chSysTimerHandlerI(void); void chSysTimerHandlerI(void);
syssts_t chSysGetStatusAndLockX(void); syssts_t chSysGetStatusAndLockX(void);
void chSysRestoreStatusX(syssts_t sts); void chSysRestoreStatusX(syssts_t sts);
#if PORT_SUPPORTS_RT #if PORT_SUPPORTS_RT == TRUE
bool chSysIsCounterWithinX(rtcnt_t cnt, rtcnt_t start, rtcnt_t end); bool chSysIsCounterWithinX(rtcnt_t cnt, rtcnt_t start, rtcnt_t end);
void chSysPolledDelayX(rtcnt_t cycles); void chSysPolledDelayX(rtcnt_t cycles);
#endif #endif
@ -364,8 +388,8 @@ static inline void chSysUnlock(void) {
in a critical section not followed by a chSchResceduleS(), this means in a critical section not followed by a chSchResceduleS(), this means
that the current thread has a lower priority than the next thread in that the current thread has a lower priority than the next thread in
the ready list.*/ the ready list.*/
chDbgAssert((ch.rlist.r_queue.p_next == (thread_t *)&ch.rlist.r_queue) || chDbgAssert((ch.rlist.queue.next == (thread_t *)&ch.rlist.queue) ||
(ch.rlist.r_current->p_prio >= ch.rlist.r_queue.p_next->p_prio), (ch.rlist.current->prio >= ch.rlist.queue.next->prio),
"priority order violation"); "priority order violation");
port_unlock(); port_unlock();
@ -453,7 +477,7 @@ static inline void chSysUnconditionalUnlock(void) {
*/ */
static inline thread_t *chSysGetIdleThreadX(void) { static inline thread_t *chSysGetIdleThreadX(void) {
return ch.rlist.r_queue.p_prev; return ch.rlist.queue.prev;
} }
#endif /* CH_CFG_NO_IDLE_THREAD == FALSE */ #endif /* CH_CFG_NO_IDLE_THREAD == FALSE */

View File

@ -38,6 +38,18 @@
/* Module pre-compile time settings. */ /* Module pre-compile time settings. */
/*===========================================================================*/ /*===========================================================================*/
#if !defined(CH_CFG_THREAD_EXTRA_FIELDS)
#error "CH_CFG_THREAD_EXTRA_FIELDS not defined in chconf.h"
#endif
#if !defined(CH_CFG_THREAD_INIT_HOOK)
#error "CH_CFG_THREAD_INIT_HOOK not defined in chconf.h"
#endif
#if !defined(CH_CFG_THREAD_EXIT_HOOK)
#error "CH_CFG_THREAD_EXIT_HOOK not defined in chconf.h"
#endif
/*===========================================================================*/ /*===========================================================================*/
/* Derived constants and error checks. */ /* Derived constants and error checks. */
/*===========================================================================*/ /*===========================================================================*/
@ -51,6 +63,36 @@
*/ */
typedef void (*tfunc_t)(void *p); typedef void (*tfunc_t)(void *p);
/**
* @brief Type of a thread descriptor.
*/
typedef struct {
/**
* @brief Thread name.
*/
const char *name;
/**
* @brief Pointer to the working area base.
*/
stkalign_t *wbase;
/**
* @brief End of the working area.
*/
stkalign_t *wend;
/**
* @brief Thread priority.
*/
tprio_t prio;
/**
* @brief Thread function pointer.
*/
tfunc_t funcp;
/**
* @brief Thread argument.
*/
void *arg;
} thread_descriptor_t;
/*===========================================================================*/ /*===========================================================================*/
/* Module macros. */ /* Module macros. */
/*===========================================================================*/ /*===========================================================================*/
@ -128,12 +170,14 @@ typedef void (*tfunc_t)(void *p);
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
thread_t *_thread_init(thread_t *tp, tprio_t prio); thread_t *_thread_init(thread_t *tp, const char *name, tprio_t prio);
#if CH_DBG_FILL_THREADS == TRUE #if CH_DBG_FILL_THREADS == TRUE
void _thread_memfill(uint8_t *startp, uint8_t *endp, uint8_t v); void _thread_memfill(uint8_t *startp, uint8_t *endp, uint8_t v);
#endif #endif
thread_t *chThdCreateI(void *wsp, size_t size, thread_t *chThdCreateSuspendedI(const thread_descriptor_t *tdp);
tprio_t prio, tfunc_t pf, void *arg); thread_t *chThdCreateSuspended(const thread_descriptor_t *tdp);
thread_t *chThdCreateI(const thread_descriptor_t *tdp);
thread_t *chThdCreate(const thread_descriptor_t *tdp);
thread_t *chThdCreateStatic(void *wsp, size_t size, thread_t *chThdCreateStatic(void *wsp, size_t size,
tprio_t prio, tfunc_t pf, void *arg); tprio_t prio, tfunc_t pf, void *arg);
thread_t *chThdStart(thread_t *tp); thread_t *chThdStart(thread_t *tp);
@ -146,7 +190,6 @@ extern "C" {
msg_t chThdEnqueueTimeoutS(threads_queue_t *tqp, systime_t timeout); msg_t chThdEnqueueTimeoutS(threads_queue_t *tqp, systime_t timeout);
void chThdDequeueNextI(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); void chThdDequeueAllI(threads_queue_t *tqp, msg_t msg);
void chThdTerminate(thread_t *tp);
void chThdSleep(systime_t time); void chThdSleep(systime_t time);
void chThdSleepUntil(systime_t time); void chThdSleepUntil(systime_t time);
systime_t chThdSleepUntilWindowed(systime_t prev, systime_t next); systime_t chThdSleepUntilWindowed(systime_t prev, systime_t next);
@ -173,7 +216,7 @@ extern "C" {
*/ */
static inline thread_t *chThdGetSelfX(void) { static inline thread_t *chThdGetSelfX(void) {
return ch.rlist.r_current; return ch.rlist.current;
} }
/** /**
@ -186,7 +229,7 @@ static inline thread_t *chThdGetSelfX(void) {
*/ */
static inline tprio_t chThdGetPriorityX(void) { static inline tprio_t chThdGetPriorityX(void) {
return chThdGetSelfX()->p_prio; return chThdGetSelfX()->prio;
} }
/** /**
@ -202,10 +245,23 @@ static inline tprio_t chThdGetPriorityX(void) {
#if (CH_DBG_THREADS_PROFILING == TRUE) || defined(__DOXYGEN__) #if (CH_DBG_THREADS_PROFILING == TRUE) || defined(__DOXYGEN__)
static inline systime_t chThdGetTicksX(thread_t *tp) { static inline systime_t chThdGetTicksX(thread_t *tp) {
return tp->p_time; return tp->time;
} }
#endif #endif
/**
* @brief Returns the stack limit of the specified thread.
*
* @param[in] tp pointer to the thread
* @return The stack limit pointer.
*
* @xclass
*/
static inline stkalign_t *chthdGetStackLimitX(thread_t *tp) {
return tp->stklimit;
}
/** /**
* @brief Verifies if the specified thread is in the @p CH_STATE_FINAL state. * @brief Verifies if the specified thread is in the @p CH_STATE_FINAL state.
* *
@ -217,20 +273,7 @@ static inline systime_t chThdGetTicksX(thread_t *tp) {
*/ */
static inline bool chThdTerminatedX(thread_t *tp) { static inline bool chThdTerminatedX(thread_t *tp) {
return (bool)(tp->p_state == CH_STATE_FINAL); return (bool)(tp->state == CH_STATE_FINAL);
}
/**
* @brief Verifies if the current thread has a termination request pending.
*
* @retval true termination request pending.
* @retval false termination request not pending.
*
* @xclass
*/
static inline bool chThdShouldTerminateX(void) {
return (bool)((chThdGetSelfX()->p_flags & CH_FLAG_TERMINATE) != (tmode_t)0);
} }
/** /**
@ -244,7 +287,7 @@ static inline bool chThdShouldTerminateX(void) {
*/ */
static inline thread_t *chThdStartI(thread_t *tp) { static inline thread_t *chThdStartI(thread_t *tp) {
chDbgAssert(tp->p_state == CH_STATE_WTSTART, "wrong state"); chDbgAssert(tp->state == CH_STATE_WTSTART, "wrong state");
return chSchReadyI(tp); return chSchReadyI(tp);
} }
@ -316,9 +359,9 @@ static inline void chThdDoDequeueNextI(threads_queue_t *tqp, msg_t msg) {
tp = queue_fifo_remove(tqp); tp = queue_fifo_remove(tqp);
chDbgAssert(tp->p_state == CH_STATE_QUEUED, "invalid state"); chDbgAssert(tp->state == CH_STATE_QUEUED, "invalid state");
tp->p_u.rdymsg = msg; tp->u.rdymsg = msg;
(void) chSchReadyI(tp); (void) chSchReadyI(tp);
} }

View File

@ -209,7 +209,7 @@ extern "C" {
*/ */
static inline void chVTObjectInit(virtual_timer_t *vtp) { static inline void chVTObjectInit(virtual_timer_t *vtp) {
vtp->vt_func = NULL; vtp->func = NULL;
} }
/** /**
@ -228,7 +228,7 @@ static inline void chVTObjectInit(virtual_timer_t *vtp) {
static inline systime_t chVTGetSystemTimeX(void) { static inline systime_t chVTGetSystemTimeX(void) {
#if CH_CFG_ST_TIMEDELTA == 0 #if CH_CFG_ST_TIMEDELTA == 0
return ch.vtlist.vt_systime; return ch.vtlist.systime;
#else /* CH_CFG_ST_TIMEDELTA > 0 */ #else /* CH_CFG_ST_TIMEDELTA > 0 */
return port_timer_get_time(); return port_timer_get_time();
#endif /* CH_CFG_ST_TIMEDELTA > 0 */ #endif /* CH_CFG_ST_TIMEDELTA > 0 */
@ -344,15 +344,15 @@ static inline bool chVTGetTimersStateI(systime_t *timep) {
chDbgCheckClassI(); chDbgCheckClassI();
if (&ch.vtlist == (virtual_timers_list_t *)ch.vtlist.vt_next) { if (&ch.vtlist == (virtual_timers_list_t *)ch.vtlist.next) {
return false; return false;
} }
if (timep != NULL) { if (timep != NULL) {
#if CH_CFG_ST_TIMEDELTA == 0 #if CH_CFG_ST_TIMEDELTA == 0
*timep = ch.vtlist.vt_next->vt_delta; *timep = ch.vtlist.next->delta;
#else #else
*timep = ch.vtlist.vt_lasttime + ch.vtlist.vt_next->vt_delta + *timep = ch.vtlist.lasttime + ch.vtlist.next->delta +
CH_CFG_ST_TIMEDELTA - chVTGetSystemTimeX(); CH_CFG_ST_TIMEDELTA - chVTGetSystemTimeX();
#endif #endif
} }
@ -374,7 +374,7 @@ static inline bool chVTIsArmedI(virtual_timer_t *vtp) {
chDbgCheckClassI(); chDbgCheckClassI();
return (bool)(vtp->vt_func != NULL); return (bool)(vtp->func != NULL);
} }
/** /**
@ -504,21 +504,21 @@ static inline void chVTDoTickI(void) {
chDbgCheckClassI(); chDbgCheckClassI();
#if CH_CFG_ST_TIMEDELTA == 0 #if CH_CFG_ST_TIMEDELTA == 0
ch.vtlist.vt_systime++; ch.vtlist.systime++;
if (&ch.vtlist != (virtual_timers_list_t *)ch.vtlist.vt_next) { if (&ch.vtlist != (virtual_timers_list_t *)ch.vtlist.next) {
/* The list is not empty, processing elements on top.*/ /* The list is not empty, processing elements on top.*/
--ch.vtlist.vt_next->vt_delta; --ch.vtlist.next->delta;
while (ch.vtlist.vt_next->vt_delta == (systime_t)0) { while (ch.vtlist.next->delta == (systime_t)0) {
virtual_timer_t *vtp; virtual_timer_t *vtp;
vtfunc_t fn; vtfunc_t fn;
vtp = ch.vtlist.vt_next; vtp = ch.vtlist.next;
fn = vtp->vt_func; fn = vtp->func;
vtp->vt_func = NULL; vtp->func = NULL;
vtp->vt_next->vt_prev = (virtual_timer_t *)&ch.vtlist; vtp->next->prev = (virtual_timer_t *)&ch.vtlist;
ch.vtlist.vt_next = vtp->vt_next; ch.vtlist.next = vtp->next;
chSysUnlockFromISR(); chSysUnlockFromISR();
fn(vtp->vt_par); fn(vtp->par);
chSysLockFromISR(); chSysLockFromISR();
} }
} }
@ -527,26 +527,26 @@ static inline void chVTDoTickI(void) {
systime_t now, delta; systime_t now, delta;
/* First timer to be processed.*/ /* First timer to be processed.*/
vtp = ch.vtlist.vt_next; vtp = ch.vtlist.next;
now = chVTGetSystemTimeX(); now = chVTGetSystemTimeX();
/* All timers within the time window are triggered and removed, /* All timers within the time window are triggered and removed,
note that the loop is stopped by the timers header having note that the loop is stopped by the timers header having
"ch.vtlist.vt_delta == (systime_t)-1" which is greater than "ch.vtlist.vt_delta == (systime_t)-1" which is greater than
all deltas.*/ all deltas.*/
while (vtp->vt_delta <= (systime_t)(now - ch.vtlist.vt_lasttime)) { while (vtp->delta <= (systime_t)(now - ch.vtlist.lasttime)) {
vtfunc_t fn; vtfunc_t fn;
/* The "last time" becomes this timer's expiration time.*/ /* The "last time" becomes this timer's expiration time.*/
ch.vtlist.vt_lasttime += vtp->vt_delta; ch.vtlist.lasttime += vtp->delta;
vtp->vt_next->vt_prev = (virtual_timer_t *)&ch.vtlist; vtp->next->prev = (virtual_timer_t *)&ch.vtlist;
ch.vtlist.vt_next = vtp->vt_next; ch.vtlist.next = vtp->next;
fn = vtp->vt_func; fn = vtp->func;
vtp->vt_func = NULL; vtp->func = NULL;
/* if the list becomes empty then the timer is stopped.*/ /* if the list becomes empty then the timer is stopped.*/
if (ch.vtlist.vt_next == (virtual_timer_t *)&ch.vtlist) { if (ch.vtlist.next == (virtual_timer_t *)&ch.vtlist) {
port_timer_stop_alarm(); port_timer_stop_alarm();
} }
@ -556,7 +556,7 @@ static inline void chVTDoTickI(void) {
chSysUnlockFromISR(); chSysUnlockFromISR();
/* The callback is invoked outside the kernel critical zone.*/ /* The callback is invoked outside the kernel critical zone.*/
fn(vtp->vt_par); fn(vtp->par);
/* Re-entering the critical zone in order to continue the exploration /* Re-entering the critical zone in order to continue the exploration
of the list.*/ of the list.*/
@ -564,24 +564,24 @@ static inline void chVTDoTickI(void) {
/* Next element in the list, the current time could have advanced so /* Next element in the list, the current time could have advanced so
recalculating the time window.*/ recalculating the time window.*/
vtp = ch.vtlist.vt_next; vtp = ch.vtlist.next;
now = chVTGetSystemTimeX(); now = chVTGetSystemTimeX();
} }
/* if the list is empty, nothing else to do.*/ /* if the list is empty, nothing else to do.*/
if (ch.vtlist.vt_next == (virtual_timer_t *)&ch.vtlist) { if (ch.vtlist.next == (virtual_timer_t *)&ch.vtlist) {
return; return;
} }
/* Recalculating the next alarm time.*/ /* Recalculating the next alarm time.*/
delta = ch.vtlist.vt_lasttime + vtp->vt_delta - now; delta = ch.vtlist.lasttime + vtp->delta - now;
if (delta < (systime_t)CH_CFG_ST_TIMEDELTA) { if (delta < (systime_t)CH_CFG_ST_TIMEDELTA) {
delta = (systime_t)CH_CFG_ST_TIMEDELTA; delta = (systime_t)CH_CFG_ST_TIMEDELTA;
} }
port_timer_set_alarm(now + delta); port_timer_set_alarm(now + delta);
chDbgAssert((chVTGetSystemTimeX() - ch.vtlist.vt_lasttime) <= chDbgAssert((chVTGetSystemTimeX() - ch.vtlist.lasttime) <=
(now + delta - ch.vtlist.vt_lasttime), (now + delta - ch.vtlist.lasttime),
"exceeding delta"); "exceeding delta");
#endif /* CH_CFG_ST_TIMEDELTA > 0 */ #endif /* CH_CFG_ST_TIMEDELTA > 0 */
} }

View File

@ -1,54 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file ARM/chcore.c
* @brief ARM port code.
*
* @addtogroup ARM_CORE
* @{
*/
#include "ch.h"
/*===========================================================================*/
/* Module local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported functions. */
/*===========================================================================*/
/** @} */

View File

@ -1,531 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file ARM/chcore.h
* @brief ARM7/9 architecture port macros and structures.
*
* @addtogroup ARM_CORE
* @{
*/
#ifndef _CHCORE_H_
#define _CHCORE_H_
/*===========================================================================*/
/* Module constants. */
/*===========================================================================*/
/**
* @name Architecture and Compiler
* @{
*/
/**
* @brief Macro defining a generic ARM architecture.
*/
#define PORT_ARCHITECTURE_ARM
/* The following code is not processed when the file is included from an
asm module because those intrinsic macros are not necessarily defined
by the assembler too.*/
#if !defined(_FROM_ASM_)
/**
* @brief Compiler name and version.
*/
#if defined(__GNUC__) || defined(__DOXYGEN__)
#define PORT_COMPILER_NAME "GCC " __VERSION__
#else
#error "unsupported compiler"
#endif
#endif /* !defined(_FROM_ASM_) */
/** @} */
/**
* @name ARM variants
* @{
*/
#define ARM_CORE_ARM7TDMI 7
#define ARM_CORE_ARM9 9
#define ARM_CORE_CORTEX_A8 108
#define ARM_CORE_CORTEX_A9 109
/** @} */
/* Inclusion of the ARM implementation specific parameters.*/
#include "armparams.h"
/**
* @brief This port supports a realtime counter.
*/
#define PORT_SUPPORTS_RT FALSE
/*===========================================================================*/
/* Module pre-compile time settings. */
/*===========================================================================*/
/**
* @brief Enables an alternative timer implementation.
* @details Usually the port uses a timer interface defined in the file
* @p chcore_timer.h, if this option is enabled then the file
* @p chcore_timer_alt.h is included instead.
*/
#if !defined(PORT_USE_ALT_TIMER)
#define PORT_USE_ALT_TIMER FALSE
#endif
/**
* @brief Stack size for the system idle thread.
* @details This size depends on the idle thread implementation, usually
* the idle thread should take no more space than those reserved
* by @p PORT_INT_REQUIRED_STACK.
* @note In this port it is set to 32 because the idle thread does have
* a stack frame when compiling without optimizations. You may
* reduce this value to zero when compiling with optimizations.
*/
#if !defined(PORT_IDLE_THREAD_STACK_SIZE) || defined(__DOXYGEN__)
#define PORT_IDLE_THREAD_STACK_SIZE 32
#endif
/**
* @brief Per-thread stack overhead for interrupts servicing.
* @details This constant is used in the calculation of the correct working
* area size.
*/
#if !defined(PORT_INT_REQUIRED_STACK) || defined(__DOXYGEN__)
#define PORT_INT_REQUIRED_STACK 32
#endif
/**
* @brief If enabled allows the idle thread to enter a low power mode.
*/
#ifndef ARM_ENABLE_WFI_IDLE
#define ARM_ENABLE_WFI_IDLE FALSE
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/* The following code is not processed when the file is included from an
asm module.*/
#if !defined(_FROM_ASM_)
/* ARM core check.*/
#if (ARM_CORE == ARM_CORE_ARM7TDMI) || defined(__DOXYGEN__)
#define PORT_ARCHITECTURE_ARM_ARM7
#define PORT_ARCHITECTURE_NAME "ARMv4T"
#define PORT_CORE_VARIANT_NAME "ARM7"
#elif ARM_CORE == ARM_CORE_ARM9
#define PORT_ARCHITECTURE_ARM_ARM9
#define PORT_ARCHITECTURE_NAME "ARMv5T"
#define PORT_CORE_VARIANT_NAME "ARM9"
#elif ARM_CORE == ARM_CORE_CORTEX_A8
#define PORT_ARCHITECTURE_ARM_CORTEXA8
#define PORT_ARCHITECTURE_NAME "ARMv7"
#define PORT_CORE_VARIANT_NAME "ARM Cortex-A8"
#elif ARM_CORE == ARM_CORE_CORTEX_A9
#define PORT_ARCHITECTURE_ARM_CORTEXA9
#define PORT_ARCHITECTURE_NAME "ARMv7"
#define PORT_CORE_VARIANT_NAME "ARM Cortex-A9"
#else
#error "unknown or unsupported ARM core"
#endif
#if defined(THUMB_PRESENT)
#if defined(THUMB_NO_INTERWORKING)
#define PORT_INFO "Pure THUMB mode"
#else
#define PORT_INFO "Interworking mode"
#endif
#else
#define PORT_INFO "Pure ARM mode"
#endif
#endif /* !defined(_FROM_ASM_) */
/*===========================================================================*/
/* Module data structures and types. */
/*===========================================================================*/
/* The following code is not processed when the file is included from an
asm module.*/
#if !defined(_FROM_ASM_)
/**
* @brief Type of stack and memory alignment enforcement.
* @note In this architecture the stack alignment is enforced to 64 bits.
*/
typedef uint64_t stkalign_t;
/**
* @brief Generic ARM register.
*/
typedef void *regarm_t;
/**
* @brief Interrupt saved context.
* @details This structure represents the stack frame saved during an
* interrupt handler.
*/
struct port_extctx {
regarm_t spsr_irq;
regarm_t lr_irq;
regarm_t r0;
regarm_t r1;
regarm_t r2;
regarm_t r3;
regarm_t r12;
regarm_t lr_usr;
};
/**
* @brief System saved context.
* @details This structure represents the inner stack frame during a context
* switch.
*/
struct port_intctx {
regarm_t r4;
regarm_t r5;
regarm_t r6;
regarm_t r7;
regarm_t r8;
regarm_t r9;
regarm_t r10;
regarm_t r11;
regarm_t lr;
};
/**
* @brief Platform dependent part of the @p thread_t structure.
* @details In this port the structure just holds a pointer to the
* @p port_intctx structure representing the stack pointer
* at context switch time.
*/
struct context {
struct port_intctx *r13;
};
/*===========================================================================*/
/* Module macros. */
/*===========================================================================*/
/**
* @brief Platform dependent part of the @p chThdCreateI() API.
* @details This code usually setup the context switching frame represented
* by an @p port_intctx structure.
*/
#define PORT_SETUP_CONTEXT(tp, workspace, wsize, pf, arg) { \
(tp)->p_ctx.r13 = (struct port_intctx *)((uint8_t *)(workspace) + \
(wsize) - \
sizeof(struct port_intctx)); \
(tp)->p_ctx.r13->r4 = (regarm_t)(pf); \
(tp)->p_ctx.r13->r5 = (regarm_t)(arg); \
(tp)->p_ctx.r13->lr = (regarm_t)(_port_thread_start); \
}
/**
* @brief Computes the thread working area global size.
* @note There is no need to perform alignments in this macro.
*/
#define PORT_WA_SIZE(n) (sizeof(struct port_intctx) + \
sizeof(struct port_extctx) + \
((size_t)(n)) + ((size_t)(PORT_INT_REQUIRED_STACK)))
/**
* @brief Priority level verification macro.
* @todo Add the required parameters to armparams.h.
*/
#define PORT_IRQ_IS_VALID_PRIORITY(n) false
/**
* @brief IRQ prologue code.
* @details This macro must be inserted at the start of all IRQ handlers
* enabled to invoke system APIs.
*/
#define PORT_IRQ_PROLOGUE()
/**
* @brief IRQ epilogue code.
* @details This macro must be inserted at the end of all IRQ handlers
* enabled to invoke system APIs.
*/
#define PORT_IRQ_EPILOGUE() return chSchIsPreemptionRequired()
/**
* @brief IRQ handler function declaration.
* @note @p id can be a function name or a vector number depending on the
* port implementation.
*/
#define PORT_IRQ_HANDLER(id) bool id(void)
/**
* @brief Fast IRQ handler function declaration.
* @note @p id can be a function name or a vector number depending on the
* port implementation.
*/
#define PORT_FAST_IRQ_HANDLER(id) \
__attribute__((interrupt("FIQ"))) void id(void)
/**
* @brief Performs a context switch between two threads.
* @details This is the most critical code in any port, this function
* is responsible for the context switch between 2 threads.
* @note The implementation of this code affects <b>directly</b> the context
* switch performance so optimize here as much as you can.
* @note Implemented as inlined code for performance reasons.
*
* @param[in] ntp the thread to be switched in
* @param[in] otp the thread to be switched out
*/
#if defined(THUMB)
#if CH_DBG_ENABLE_STACK_CHECK == TRUE
#define port_switch(ntp, otp) { \
register struct port_intctx *r13 asm ("r13"); \
if ((stkalign_t *)(r13 - 1) < otp->p_stklimit) \
chSysHalt("stack overflow"); \
_port_switch_thumb(ntp, otp); \
}
#else
#define port_switch(ntp, otp) _port_switch_thumb(ntp, otp)
#endif
#else /* !defined(THUMB) */
#if CH_DBG_ENABLE_STACK_CHECK == TRUE
#define port_switch(ntp, otp) { \
register struct port_intctx *r13 asm ("r13"); \
if ((stkalign_t *)(r13 - 1) < otp->p_stklimit) \
chSysHalt("stack overflow"); \
_port_switch_arm(ntp, otp); \
}
#else
#define port_switch(ntp, otp) _port_switch_arm(ntp, otp)
#endif
#endif /* !defined(THUMB) */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
#if defined(THUMB_PRESENT)
syssts_t _port_get_cpsr(void);
#endif
#if defined(THUMB)
void _port_switch_thumb(thread_t *ntp, thread_t *otp);
#else
void _port_switch_arm(thread_t *ntp, thread_t *otp);
#endif
void _port_thread_start(void);
#ifdef __cplusplus
}
#endif
/*===========================================================================*/
/* Module inline functions. */
/*===========================================================================*/
/**
* @brief Port-related initialization code.
*/
static inline void port_init(void) {
}
/**
* @brief Returns a word encoding the current interrupts status.
*
* @return The interrupts status.
*/
static inline syssts_t port_get_irq_status(void) {
syssts_t sts;
#if defined(THUMB)
sts = _port_get_cpsr();
#else
__asm volatile ("mrs %[p0], CPSR" : [p0] "=r" (sts) :);
#endif
/*lint -save -e530 [9.1] Asm instruction not seen by lint.*/
return sts;
/*lint -restore*/
}
/**
* @brief Checks the interrupt status.
*
* @param[in] sts the interrupt status word
*
* @return The interrupt status.
* @retvel false the word specified a disabled interrupts status.
* @retvel true the word specified an enabled interrupts status.
*/
static inline bool port_irq_enabled(syssts_t sts) {
return (sts & (syssts_t)0x80) == (syssts_t)0;
}
/**
* @brief Determines the current execution context.
*
* @return The execution context.
* @retval false not running in ISR mode.
* @retval true running in ISR mode.
*/
static inline bool port_is_isr_context(void) {
syssts_t sts;
#if defined(THUMB)
sts = _port_get_cpsr();
#else
__asm volatile ("mrs %[p0], CPSR" : [p0] "=r" (sts) :);
#endif
/*lint -save -e530 [9.1] Asm instruction not seen by lint.*/
return (sts & (syssts_t)0x1F) == (syssts_t)0x12;
/*lint -restore*/
}
/**
* @brief Kernel-lock action.
* @details In this port it disables the IRQ sources and keeps FIQ sources
* enabled.
*/
static inline void port_lock(void) {
#if defined(THUMB)
__asm volatile ("bl _port_lock_thumb" : : : "r3", "lr", "memory");
#else
__asm volatile ("msr CPSR_c, #0x9F" : : : "memory");
#endif
}
/**
* @brief Kernel-unlock action.
* @details In this port it enables both the IRQ and FIQ sources.
*/
static inline void port_unlock(void) {
#if defined(THUMB)
__asm volatile ("bl _port_unlock_thumb" : : : "r3", "lr", "memory");
#else
__asm volatile ("msr CPSR_c, #0x1F" : : : "memory");
#endif
}
/**
* @brief Kernel-lock action from an interrupt handler.
* @note Empty in this port.
*/
static inline void port_lock_from_isr(void) {
}
/**
* @brief Kernel-unlock action from an interrupt handler.
* @note Empty in this port.
*/
static inline void port_unlock_from_isr(void) {
}
/**
* @brief Disables all the interrupt sources.
* @details In this port it disables both the IRQ and FIQ sources.
* @note Implements a workaround for spurious interrupts taken from the NXP
* LPC214x datasheet.
*/
static inline void port_disable(void) {
#if defined(THUMB)
__asm volatile ("bl _port_disable_thumb" : : : "r3", "lr", "memory");
#else
__asm volatile ("mrs r3, CPSR \n\t"
"orr r3, #0x80 \n\t"
"msr CPSR_c, r3 \n\t"
"orr r3, #0x40 \n\t"
"msr CPSR_c, r3" : : : "r3", "memory");
#endif
}
/**
* @brief Disables the interrupt sources below kernel-level priority.
* @note Interrupt sources above kernel level remains enabled.
* @note In this port it disables the IRQ sources and enables the
* FIQ sources.
*/
static inline void port_suspend(void) {
#if defined(THUMB)
__asm volatile ("bl _port_suspend_thumb" : : : "r3", "lr", "memory");
#else
__asm volatile ("msr CPSR_c, #0x9F" : : : "memory");
#endif
}
/**
* @brief Enables all the interrupt sources.
* @note In this port it enables both the IRQ and FIQ sources.
*/
static inline void port_enable(void) {
#if defined(THUMB)
__asm volatile ("bl _port_enable_thumb" : : : "r3", "lr", "memory");
#else
__asm volatile ("msr CPSR_c, #0x1F" : : : "memory");
#endif
}
/**
* @brief Enters an architecture-dependent IRQ-waiting mode.
* @details The function is meant to return when an interrupt becomes pending.
* The simplest implementation is an empty function or macro but this
* would not take advantage of architecture-specific power saving
* modes.
* @note Implemented as an inlined @p WFI instruction.
*/
static inline void port_wait_for_interrupt(void) {
#if ARM_ENABLE_WFI_IDLE == TRUE
ARM_WFI_IMPL;
#endif
}
#if CH_CFG_ST_TIMEDELTA > 0
#if PORT_USE_ALT_TIMER == FALSE
#include "chcore_timer.h"
#else /* PORT_USE_ALT_TIMER */
#include "chcore_timer_alt.h"
#endif /* PORT_USE_ALT_TIMER */
#endif /* CH_CFG_ST_TIMEDELTA > 0 */
#endif /* !defined(_FROM_ASM_) */
#endif /* _CHCORE_H_ */
/** @} */

View File

@ -1,124 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file chcore_timer.h
* @brief System timer header file.
*
* @addtogroup ARM_TIMER
* @{
*/
#ifndef _CHCORE_TIMER_H_
#define _CHCORE_TIMER_H_
/* This is the only header in the HAL designed to be include-able alone.*/
#include "st.h"
/*===========================================================================*/
/* Module constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Module pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Module data structures and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
/*===========================================================================*/
/* Module inline functions. */
/*===========================================================================*/
/**
* @brief Starts the alarm.
* @note Makes sure that no spurious alarms are triggered after
* this call.
*
* @param[in] time the time to be set for the first alarm
*
* @notapi
*/
static inline void port_timer_start_alarm(systime_t time) {
stStartAlarm(time);
}
/**
* @brief Stops the alarm interrupt.
*
* @notapi
*/
static inline void port_timer_stop_alarm(void) {
stStopAlarm();
}
/**
* @brief Sets the alarm time.
*
* @param[in] time the time to be set for the next alarm
*
* @notapi
*/
static inline void port_timer_set_alarm(systime_t time) {
stSetAlarm(time);
}
/**
* @brief Returns the system time.
*
* @return The system time.
*
* @notapi
*/
static inline systime_t port_timer_get_time(void) {
return stGetCounter();
}
/**
* @brief Returns the current alarm time.
*
* @return The currently set alarm time.
*
* @notapi
*/
static inline systime_t port_timer_get_alarm(void) {
return stGetAlarm();
}
#endif /* _CHCORE_TIMER_H_ */
/** @} */

View File

@ -1,278 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file ARM/compilers/GCC/chcoreasm.s
* @brief ARM architecture port low level code.
*
* @addtogroup ARM_CORE
* @{
*/
#define _FROM_ASM_
#include "chconf.h"
#include "armparams.h"
#define FALSE 0
#define TRUE 1
#if !defined(__DOXYGEN__)
.set MODE_USR, 0x10
.set MODE_FIQ, 0x11
.set MODE_IRQ, 0x12
.set MODE_SVC, 0x13
.set MODE_ABT, 0x17
.set MODE_UND, 0x1B
.set MODE_SYS, 0x1F
.equ I_BIT, 0x80
.equ F_BIT, 0x40
.text
/*
* The following functions are only present if there is THUMB code in
* the system.
*/
#if defined(THUMB_PRESENT)
.balign 16
.code 16
.thumb_func
.global _port_get_cpsr
_port_get_cpsr:
mov r0, pc
bx r0
.code 32
mrs r0, CPSR
bx lr
.balign 16
.code 16
.thumb_func
.global _port_disable_thumb
_port_disable_thumb:
mov r3, pc
bx r3
.code 32
mrs r3, CPSR
orr r3, #I_BIT
msr CPSR_c, r3
orr r3, #F_BIT
msr CPSR_c, r3
bx lr
.balign 16
.code 16
.thumb_func
.global _port_suspend_thumb
_port_suspend_thumb:
// Goes into _port_unlock_thumb
.code 16
.global _port_lock_thumb
_port_lock_thumb:
mov r3, pc
bx r3
.code 32
msr CPSR_c, #MODE_SYS | I_BIT
bx lr
.balign 16
.code 16
.thumb_func
.global _port_enable_thumb
_port_enable_thumb:
// Goes into _port_unlock_thumb
.code 16
.global _port_unlock_thumb
_port_unlock_thumb:
mov r3, pc
bx r3
.code 32
msr CPSR_c, #MODE_SYS
bx lr
#endif /* defined(THUMB_PRESENT) */
.balign 16
#if defined(THUMB_PRESENT)
.code 16
.thumb_func
.global _port_switch_thumb
_port_switch_thumb:
mov r2, pc
bx r2
// Goes into _port_switch_arm in ARM mode
#endif /* defined(THUMB_PRESENT) */
.code 32
.global _port_switch_arm
_port_switch_arm:
stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}
str sp, [r1, #12]
ldr sp, [r0, #12]
#if defined(THUMB_PRESENT)
ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}
bx lr
#else /* !defined(THUMB_PRESENT)T */
ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}
#endif /* !defined(THUMB_PRESENT) */
/*
* Common IRQ code. It expects a macro ARM_IRQ_VECTOR_REG with the address
* of a register holding the address of the ISR to be invoked, the ISR
* then returns in the common epilogue code where the context switch will
* be performed, if required.
* System stack frame structure after a context switch in the
* interrupt handler:
*
* High +------------+
* | LR_USR | -+
* | r12 | |
* | r3 | |
* | r2 | | External context: IRQ handler frame
* | r1 | |
* | r0 | |
* | LR_IRQ | | (user code return address)
* | PSR_USR | -+ (user code status)
* | .... | <- chSchDoReschedule() stack frame, optimize it for space
* | LR | -+ (system code return address)
* | r11 | |
* | r10 | |
* | r9 | |
* | r8 | | Internal context: chSysSwitch() frame
* | r7 | |
* | r6 | |
* | r5 | |
* SP-> | r4 | -+
* Low +------------+
*/
.balign 16
.code 32
.global Irq_Handler
Irq_Handler:
stmfd sp!, {r0-r3, r12, lr}
ldr r0, =ARM_IRQ_VECTOR_REG
ldr r0, [r0]
#if !defined(THUMB_NO_INTERWORKING)
ldr lr, =_irq_ret_arm // ISR return point.
bx r0 // Calling the ISR.
_irq_ret_arm:
#else /* defined(THUMB_NO_INTERWORKING) */
add r1, pc, #1
bx r1
.code 16
bl _bxr0 // Calling the ISR.
mov lr, pc
bx lr
.code 32
#endif /* defined(THUMB_NO_INTERWORKING) */
cmp r0, #0
ldmfd sp!, {r0-r3, r12, lr}
subeqs pc, lr, #4 // No reschedule, returns.
// Now the frame is created in the system stack, the IRQ
// stack is empty.
msr CPSR_c, #MODE_SYS | I_BIT
stmfd sp!, {r0-r3, r12, lr}
msr CPSR_c, #MODE_IRQ | I_BIT
mrs r0, SPSR
mov r1, lr
msr CPSR_c, #MODE_SYS | I_BIT
stmfd sp!, {r0, r1} // Push R0=SPSR, R1=LR_IRQ.
// Context switch.
#if defined(THUMB_NO_INTERWORKING)
add r0, pc, #1
bx r0
.code 16
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_lock
#endif
bl chSchDoReschedule
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_unlock
#endif
mov lr, pc
bx lr
.code 32
#else /* !defined(THUMB_NO_INTERWORKING) */
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_lock
#endif
bl chSchDoReschedule
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_unlock
#endif
#endif /* !defined(THUMB_NO_INTERWORKING) */
// Re-establish the IRQ conditions again.
ldmfd sp!, {r0, r1} // Pop R0=SPSR, R1=LR_IRQ.
msr CPSR_c, #MODE_IRQ | I_BIT
msr SPSR_fsxc, r0
mov lr, r1
msr CPSR_c, #MODE_SYS | I_BIT
ldmfd sp!, {r0-r3, r12, lr}
msr CPSR_c, #MODE_IRQ | I_BIT
subs pc, lr, #4
#if defined(THUMB_NO_INTERWORKING)
.code 16
_bxr0: bx r0
#endif
/*
* Threads trampoline code.
* NOTE: The threads always start in ARM mode and then switches to the
* thread-function mode.
*/
.balign 16
.code 32
.globl _port_thread_start
_port_thread_start:
#if defined(THUMB_NO_INTERWORKING)
add r0, pc, #1
bx r0
.code 16
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_unlock
#endif
bl _port_unlock_thumb
mov r0, r5
bl _bxr4
bl chThdExit
_zombies: b _zombies
_bxr4: bx r4
#else /* !defined(THUMB_NO_INTERWORKING) */
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_unlock
#endif
msr CPSR_c, #MODE_SYS
mov r0, r5
mov lr, pc
bx r4
mov r0, #0 /* MSG_OK */
bl chThdExit
_zombies: b _zombies
#endif /* !defined(THUMB_NO_INTERWORKING) */
#endif /* !defined(__DOXYGEN__) */
/** @} */

View File

@ -1,98 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file ARM/compilers/GCC/chtypes.h
* @brief ARM port system types.
*
* @addtogroup ARM_GCC_CORE
* @{
*/
#ifndef _CHTYPES_H_
#define _CHTYPES_H_
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
/**
* @name Common constants
*/
/**
* @brief Generic 'false' boolean constant.
*/
#if !defined(FALSE) || defined(__DOXYGEN__)
#define FALSE 0
#endif
/**
* @brief Generic 'true' boolean constant.
*/
#if !defined(TRUE) || defined(__DOXYGEN__)
#define TRUE 1
#endif
/** @} */
/**
* @name Kernel types
* @{
*/
typedef uint32_t rtcnt_t; /**< Realtime counter. */
typedef uint64_t rttime_t; /**< Realtime accumulator. */
typedef uint32_t syssts_t; /**< System status word. */
typedef uint8_t tmode_t; /**< Thread flags. */
typedef uint8_t tstate_t; /**< Thread state. */
typedef uint8_t trefs_t; /**< Thread references counter. */
typedef uint8_t tslices_t; /**< Thread time slices counter.*/
typedef uint32_t tprio_t; /**< Thread priority. */
typedef int32_t msg_t; /**< Inter-thread message. */
typedef int32_t eventid_t; /**< Numeric event identifier. */
typedef uint32_t eventmask_t; /**< Mask of event identifiers. */
typedef uint32_t eventflags_t; /**< Mask of event flags. */
typedef int32_t cnt_t; /**< Generic signed counter. */
typedef uint32_t ucnt_t; /**< Generic unsigned counter. */
/** @} */
/**
* @brief ROM constant modifier.
* @note It is set to use the "const" keyword in this port.
*/
#define ROMCONST const
/**
* @brief Makes functions not inlineable.
* @note If the compiler does not support such attribute then the
* realtime counter precision could be degraded.
*/
#define NOINLINE __attribute__((noinline))
/**
* @brief Optimized thread function declaration macro.
*/
#define PORT_THD_FUNCTION(tname, arg) void tname(void *arg)
/**
* @brief Packed variable specifier.
*/
#define PACKED_VAR __attribute__((packed))
#endif /* _CHTYPES_H_ */
/** @} */

View File

@ -1,7 +0,0 @@
# List of the ChibiOS/RT ARM generic port files.
PORTSRC = ${CHIBIOS}/os/rt/ports/ARM/chcore.c
PORTASM = $(CHIBIOS)/os/rt/ports/ARM/compilers/GCC/chcoreasm.s
PORTINC = ${CHIBIOS}/os/rt/ports/ARM \
${CHIBIOS}/os/rt/ports/ARM/compilers/GCC

View File

@ -1,54 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file ARMCMx/chcore.c
* @brief ARM Cortex-Mx port code.
*
* @addtogroup ARMCMx_CORE
* @{
*/
#include "ch.h"
/*===========================================================================*/
/* Module local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported functions. */
/*===========================================================================*/
/** @} */

View File

@ -1,214 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file ARMCMx/chcore.h
* @brief ARM Cortex-Mx port macros and structures.
*
* @addtogroup ARMCMx_CORE
* @{
*/
#ifndef _CHCORE_H_
#define _CHCORE_H_
/*===========================================================================*/
/* Module constants. */
/*===========================================================================*/
/**
* @name Architecture and Compiler
* @{
*/
/**
* @brief Macro defining a generic ARM architecture.
*/
#define PORT_ARCHITECTURE_ARM
/* The following code is not processed when the file is included from an
asm module because those intrinsic macros are not necessarily defined
by the assembler too.*/
#if !defined(_FROM_ASM_)
/**
* @brief Compiler name and version.
*/
#if defined(__GNUC__) || defined(__DOXYGEN__)
#define PORT_COMPILER_NAME "GCC " __VERSION__
#elif defined(__ICCARM__)
#define PORT_COMPILER_NAME "IAR"
#elif defined(__CC_ARM)
#define PORT_COMPILER_NAME "RVCT"
#else
#error "unsupported compiler"
#endif
#endif /* !defined(_FROM_ASM_) */
/** @} */
/* Inclusion of the Cortex-Mx implementation specific parameters.*/
#include "cmparams.h"
/*===========================================================================*/
/* Module pre-compile time settings. */
/*===========================================================================*/
/**
* @brief Enables an alternative timer implementation.
* @details Usually the port uses a timer interface defined in the file
* @p chcore_timer.h, if this option is enabled then the file
* @p chcore_timer_alt.h is included instead.
*/
#if !defined(PORT_USE_ALT_TIMER)
#define PORT_USE_ALT_TIMER FALSE
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Module data structures and types. */
/*===========================================================================*/
/* The following code is not processed when the file is included from an
asm module.*/
#if !defined(_FROM_ASM_)
/**
* @brief Type of a generic ARM register.
*/
typedef void *regarm_t;
/**
* @brief Type of stack and memory alignment enforcement.
* @note In this architecture the stack alignment is enforced to 64 bits,
* 32 bits alignment is supported by hardware but deprecated by ARM,
* the implementation choice is to not offer the option.
*/
typedef uint64_t stkalign_t;
/* The following declarations are there just for Doxygen documentation, the
real declarations are inside the sub-headers being specific for the
sub-architectures.*/
#if defined(__DOXYGEN__)
/**
* @brief Interrupt saved context.
* @details This structure represents the stack frame saved during a
* preemption-capable interrupt handler.
* @note It is implemented to match the Cortex-Mx exception context.
*/
struct port_extctx {};
/**
* @brief System saved context.
* @details This structure represents the inner stack frame during a context
* switch.
*/
struct port_intctx {};
#endif /* defined(__DOXYGEN__) */
/**
* @brief Platform dependent part of the @p thread_t structure.
* @details In this port the structure just holds a pointer to the
* @p port_intctx structure representing the stack pointer
* at context switch time.
*/
struct context {
struct port_intctx *r13;
};
#endif /* !defined(_FROM_ASM_) */
/*===========================================================================*/
/* Module macros. */
/*===========================================================================*/
/**
* @brief Total priority levels.
*/
#define CORTEX_PRIORITY_LEVELS (1U << CORTEX_PRIORITY_BITS)
/**
* @brief Minimum priority level.
* @details This minimum priority level is calculated from the number of
* priority bits supported by the specific Cortex-Mx implementation.
*/
#define CORTEX_MINIMUM_PRIORITY (CORTEX_PRIORITY_LEVELS - 1)
/**
* @brief Maximum priority level.
* @details The maximum allowed priority level is always zero.
*/
#define CORTEX_MAXIMUM_PRIORITY 0U
/**
* @brief Priority level to priority mask conversion macro.
*/
#define CORTEX_PRIO_MASK(n) \
((n) << (8U - (unsigned)CORTEX_PRIORITY_BITS))
/**
* @brief Priority level verification macro.
*/
#define PORT_IRQ_IS_VALID_PRIORITY(n) \
(((n) >= 0U) && ((n) < CORTEX_PRIORITY_LEVELS))
/**
* @brief Priority level verification macro.
*/
#define PORT_IRQ_IS_VALID_KERNEL_PRIORITY(n) \
(((n) >= CORTEX_MAX_KERNEL_PRIORITY) && ((n) < CORTEX_PRIORITY_LEVELS))
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
/*===========================================================================*/
/* Module inline functions. */
/*===========================================================================*/
/* Includes the sub-architecture-specific part.*/
#if (CORTEX_MODEL == 0) || (CORTEX_MODEL == 1)
#include "chcore_v6m.h"
#elif (CORTEX_MODEL == 3) || (CORTEX_MODEL == 4) || (CORTEX_MODEL == 7)
#include "chcore_v7m.h"
#else
#error "unknown Cortex-M variant"
#endif
#if !defined(_FROM_ASM_)
#if CH_CFG_ST_TIMEDELTA > 0
#if PORT_USE_ALT_TIMER == FALSE
#include "chcore_timer.h"
#else /* PORT_USE_ALT_TIMER != FALSE */
#include "chcore_timer_alt.h"
#endif /* PORT_USE_ALT_TIMER != FALSE */
#endif /* CH_CFG_ST_TIMEDELTA > 0 */
#endif /* !defined(_FROM_ASM_) */
#endif /* _CHCORE_H_ */
/** @} */

View File

@ -1,124 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file chcore_timer.h
* @brief System timer header file.
*
* @addtogroup ARMCMx_TIMER
* @{
*/
#ifndef _CHCORE_TIMER_H_
#define _CHCORE_TIMER_H_
/* This is the only header in the HAL designed to be include-able alone.*/
#include "st.h"
/*===========================================================================*/
/* Module constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Module pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Module data structures and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
/*===========================================================================*/
/* Module inline functions. */
/*===========================================================================*/
/**
* @brief Starts the alarm.
* @note Makes sure that no spurious alarms are triggered after
* this call.
*
* @param[in] time the time to be set for the first alarm
*
* @notapi
*/
static inline void port_timer_start_alarm(systime_t time) {
stStartAlarm(time);
}
/**
* @brief Stops the alarm interrupt.
*
* @notapi
*/
static inline void port_timer_stop_alarm(void) {
stStopAlarm();
}
/**
* @brief Sets the alarm time.
*
* @param[in] time the time to be set for the next alarm
*
* @notapi
*/
static inline void port_timer_set_alarm(systime_t time) {
stSetAlarm(time);
}
/**
* @brief Returns the system time.
*
* @return The system time.
*
* @notapi
*/
static inline systime_t port_timer_get_time(void) {
return stGetCounter();
}
/**
* @brief Returns the current alarm time.
*
* @return The currently set alarm time.
*
* @notapi
*/
static inline systime_t port_timer_get_alarm(void) {
return stGetAlarm();
}
#endif /* _CHCORE_TIMER_H_ */
/** @} */

View File

@ -1,147 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file chcore_v6m.c
* @brief ARMv6-M architecture port code.
*
* @addtogroup ARMCMx_V6M_CORE
* @{
*/
#include "ch.h"
/*===========================================================================*/
/* Module local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module interrupt handlers. */
/*===========================================================================*/
#if (CORTEX_ALTERNATE_SWITCH == FALSE) || defined(__DOXYGEN__)
/**
* @brief NMI vector.
* @details The NMI vector is used for exception mode re-entering after a
* context switch.
*/
/*lint -save -e9075 [8.4] All symbols are invoked from asm context.*/
void NMI_Handler(void) {
/*lint -restore*/
/* The port_extctx structure is pointed by the PSP register.*/
struct port_extctx *ctxp = (struct port_extctx *)__get_PSP();
/* Discarding the current exception context and positioning the stack to
point to the real one.*/
ctxp++;
/* Writing back the modified PSP value.*/
__set_PSP((uint32_t)ctxp);
/* Restoring the normal interrupts status.*/
port_unlock_from_isr();
}
#endif /* !CORTEX_ALTERNATE_SWITCH */
#if (CORTEX_ALTERNATE_SWITCH == TRUE) || defined(__DOXYGEN__)
/**
* @brief PendSV vector.
* @details The PendSV vector is used for exception mode re-entering after a
* context switch.
*/
/*lint -save -e9075 [8.4] All symbols are invoked from asm context.*/
void PendSV_Handler(void) {
/*lint -restore*/
/* The port_extctx structure is pointed by the PSP register.*/
struct port_extctx *ctxp = (struct port_extctx *)__get_PSP();
/* Discarding the current exception context and positioning the stack to
point to the real one.*/
ctxp++;
/* Writing back the modified PSP value.*/
__set_PSP((uint32_t)ctxp);
}
#endif /* CORTEX_ALTERNATE_SWITCH */
/*===========================================================================*/
/* Module exported functions. */
/*===========================================================================*/
/**
* @brief IRQ epilogue code.
*
* @param[in] lr value of the @p LR register on ISR entry
*/
void _port_irq_epilogue(regarm_t lr) {
if (lr != (regarm_t)0xFFFFFFF1U) {
struct port_extctx *ctxp;
port_lock_from_isr();
/* The extctx structure is pointed by the PSP register.*/
ctxp = (struct port_extctx *)__get_PSP();
/* Adding an artificial exception return context, there is no need to
populate it fully.*/
ctxp--;
/* Writing back the modified PSP value.*/
__set_PSP((uint32_t)ctxp);
/* Setting up a fake XPSR register value.*/
ctxp->xpsr = (regarm_t)0x01000000;
/* The exit sequence is different depending on if a preemption is
required or not.*/
if (chSchIsPreemptionRequired()) {
/* Preemption is required we need to enforce a context switch.*/
ctxp->pc = (regarm_t)_port_switch_from_isr;
}
else {
/* Preemption not required, we just need to exit the exception
atomically.*/
ctxp->pc = (regarm_t)_port_exit_from_isr;
}
/* Note, returning without unlocking is intentional, this is done in
order to keep the rest of the context switch atomic.*/
}
}
/** @} */

View File

@ -1,407 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file chcore_v6m.h
* @brief ARMv6-M architecture port macros and structures.
*
* @addtogroup ARMCMx_V6M_CORE
* @{
*/
#ifndef _CHCORE_V6M_H_
#define _CHCORE_V6M_H_
/*===========================================================================*/
/* Module constants. */
/*===========================================================================*/
/**
* @brief This port does not support a realtime counter.
*/
#define PORT_SUPPORTS_RT FALSE
/**
* @brief PendSV priority level.
* @note This priority is enforced to be equal to @p 0,
* this handler always has the highest priority that cannot preempt
* the kernel.
*/
#define CORTEX_PRIORITY_PENDSV 0
/*===========================================================================*/
/* Module pre-compile time settings. */
/*===========================================================================*/
/**
* @brief Stack size for the system idle thread.
* @details This size depends on the idle thread implementation, usually
* the idle thread should take no more space than those reserved
* by @p PORT_INT_REQUIRED_STACK.
* @note In this port it is set to 16 because the idle thread does have
* a stack frame when compiling without optimizations. You may
* reduce this value to zero when compiling with optimizations.
*/
#if !defined(PORT_IDLE_THREAD_STACK_SIZE)
#define PORT_IDLE_THREAD_STACK_SIZE 16
#endif
/**
* @brief Per-thread stack overhead for interrupts servicing.
* @details This constant is used in the calculation of the correct working
* area size.
* @note In this port this value is conservatively set to 64 because the
* function @p chSchDoReschedule() can have a stack frame, especially
* with compiler optimizations disabled. The value can be reduced
* when compiler optimizations are enabled.
*/
#if !defined(PORT_INT_REQUIRED_STACK)
#define PORT_INT_REQUIRED_STACK 64
#endif
/**
* @brief Enables the use of the WFI instruction in the idle thread loop.
*/
#if !defined(CORTEX_ENABLE_WFI_IDLE)
#define CORTEX_ENABLE_WFI_IDLE FALSE
#endif
/**
* @brief Alternate preemption method.
* @details Activating this option will make the Kernel use the PendSV
* handler for preemption instead of the NMI handler.
*/
#ifndef CORTEX_ALTERNATE_SWITCH
#define CORTEX_ALTERNATE_SWITCH FALSE
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/**
* @name Architecture and Compiler
* @{
*/
#if ((CORTEX_MODEL == 0) && !defined(__CORE_CM0PLUS_H_DEPENDANT)) || \
defined(__DOXYGEN__)
/**
* @brief Macro defining the specific ARM architecture.
*/
#define PORT_ARCHITECTURE_ARM_v6M
/**
* @brief Name of the implemented architecture.
*/
#define PORT_ARCHITECTURE_NAME "ARMv6-M"
/**
* @brief Name of the architecture variant.
*/
#define PORT_CORE_VARIANT_NAME "Cortex-M0"
#elif (CORTEX_MODEL == 0) && defined(__CORE_CM0PLUS_H_DEPENDANT)
#define PORT_ARCHITECTURE_ARM_v6M
#define PORT_ARCHITECTURE_NAME "ARMv6-M"
#define PORT_CORE_VARIANT_NAME "Cortex-M0+"
#endif
/**
* @brief Port-specific information string.
*/
#if (CORTEX_ALTERNATE_SWITCH == FALSE) || defined(__DOXYGEN__)
#define PORT_INFO "Preemption through NMI"
#else
#define PORT_INFO "Preemption through PendSV"
#endif
/** @} */
/**
* @brief Maximum usable priority for normal ISRs.
*/
#if (CORTEX_ALTERNATE_SWITCH == TRUE) || defined(__DOXYGEN__)
#define CORTEX_MAX_KERNEL_PRIORITY 1
#else
#define CORTEX_MAX_KERNEL_PRIORITY 0
#endif
/*===========================================================================*/
/* Module data structures and types. */
/*===========================================================================*/
#if !defined(_FROM_ASM_)
/* The documentation of the following declarations is in chconf.h in order
to not have duplicated structure names into the documentation.*/
#if !defined(__DOXYGEN__)
struct port_extctx {
regarm_t r0;
regarm_t r1;
regarm_t r2;
regarm_t r3;
regarm_t r12;
regarm_t lr_thd;
regarm_t pc;
regarm_t xpsr;
};
struct port_intctx {
regarm_t r8;
regarm_t r9;
regarm_t r10;
regarm_t r11;
regarm_t r4;
regarm_t r5;
regarm_t r6;
regarm_t r7;
regarm_t lr;
};
#endif /* !defined(__DOXYGEN__) */
/*===========================================================================*/
/* Module macros. */
/*===========================================================================*/
/**
* @brief Platform dependent part of the @p chThdCreateI() API.
* @details This code usually setup the context switching frame represented
* by an @p port_intctx structure.
*/
#define PORT_SETUP_CONTEXT(tp, workspace, wsize, pf, arg) { \
(tp)->p_ctx.r13 = (struct port_intctx *)((uint8_t *)(workspace) + \
(wsize) - \
sizeof(struct port_intctx)); \
(tp)->p_ctx.r13->r4 = (regarm_t)(pf); \
(tp)->p_ctx.r13->r5 = (regarm_t)(arg); \
(tp)->p_ctx.r13->lr = (regarm_t)_port_thread_start; \
}
/**
* @brief Computes the thread working area global size.
* @note There is no need to perform alignments in this macro.
*/
#define PORT_WA_SIZE(n) (sizeof(struct port_intctx) + \
sizeof(struct port_extctx) + \
((size_t)(n)) + ((size_t)(PORT_INT_REQUIRED_STACK)))
/**
* @brief IRQ prologue code.
* @details This macro must be inserted at the start of all IRQ handlers
* enabled to invoke system APIs.
*/
#if defined(__GNUC__) || defined(__DOXYGEN__)
#define PORT_IRQ_PROLOGUE() \
regarm_t _saved_lr = (regarm_t)__builtin_return_address(0)
#elif defined(__ICCARM__)
#define PORT_IRQ_PROLOGUE() \
regarm_t _saved_lr = (regarm_t)__get_LR()
#elif defined(__CC_ARM)
#define PORT_IRQ_PROLOGUE() \
regarm_t _saved_lr = (regarm_t)__return_address()
#endif
/**
* @brief IRQ epilogue code.
* @details This macro must be inserted at the end of all IRQ handlers
* enabled to invoke system APIs.
*/
#define PORT_IRQ_EPILOGUE() _port_irq_epilogue(_saved_lr)
/**
* @brief IRQ handler function declaration.
* @note @p id can be a function name or a vector number depending on the
* port implementation.
*/
#define PORT_IRQ_HANDLER(id) void id(void)
/**
* @brief Fast IRQ handler function declaration.
* @note @p id can be a function name or a vector number depending on the
* port implementation.
*/
#define PORT_FAST_IRQ_HANDLER(id) void id(void)
/**
* @brief Performs a context switch between two threads.
* @details This is the most critical code in any port, this function
* is responsible for the context switch between 2 threads.
* @note The implementation of this code affects <b>directly</b> the context
* switch performance so optimize here as much as you can.
*
* @param[in] ntp the thread to be switched in
* @param[in] otp the thread to be switched out
*/
#if (CH_DBG_ENABLE_STACK_CHECK == FALSE) || defined(__DOXYGEN__)
#define port_switch(ntp, otp) _port_switch(ntp, otp)
#else
#define port_switch(ntp, otp) { \
struct port_intctx *r13 = (struct port_intctx *)__get_PSP(); \
if ((stkalign_t *)(r13 - 1) < (otp)->p_stklimit) { \
chSysHalt("stack overflow"); \
} \
_port_switch(ntp, otp); \
}
#endif
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void _port_irq_epilogue(regarm_t lr);
void _port_switch(thread_t *ntp, thread_t *otp);
void _port_thread_start(void);
void _port_switch_from_isr(void);
void _port_exit_from_isr(void);
#ifdef __cplusplus
}
#endif
/*===========================================================================*/
/* Module inline functions. */
/*===========================================================================*/
/**
* @brief Port-related initialization code.
*/
static inline void port_init(void) {
NVIC_SetPriority(PendSV_IRQn, CORTEX_PRIORITY_PENDSV);
}
/**
* @brief Returns a word encoding the current interrupts status.
*
* @return The interrupts status.
*/
static inline syssts_t port_get_irq_status(void) {
return (syssts_t)__get_PRIMASK();
}
/**
* @brief Checks the interrupt status.
*
* @param[in] sts the interrupt status word
*
* @return The interrupt status.
* @retvel false the word specified a disabled interrupts status.
* @retvel true the word specified an enabled interrupts status.
*/
static inline bool port_irq_enabled(syssts_t sts) {
return (sts & (syssts_t)1) == (syssts_t)0;
}
/**
* @brief Determines the current execution context.
*
* @return The execution context.
* @retval false not running in ISR mode.
* @retval true running in ISR mode.
*/
static inline bool port_is_isr_context(void) {
return (bool)((__get_IPSR() & 0x1FFU) != 0U);
}
/**
* @brief Kernel-lock action.
* @details In this port this function disables interrupts globally.
*/
static inline void port_lock(void) {
__disable_irq();
}
/**
* @brief Kernel-unlock action.
* @details In this port this function enables interrupts globally.
*/
static inline void port_unlock(void) {
__enable_irq();
}
/**
* @brief Kernel-lock action from an interrupt handler.
* @details In this port this function disables interrupts globally.
* @note Same as @p port_lock() in this port.
*/
static inline void port_lock_from_isr(void) {
port_lock();
}
/**
* @brief Kernel-unlock action from an interrupt handler.
* @details In this port this function enables interrupts globally.
* @note Same as @p port_lock() in this port.
*/
static inline void port_unlock_from_isr(void) {
port_unlock();
}
/**
* @brief Disables all the interrupt sources.
*/
static inline void port_disable(void) {
__disable_irq();
}
/**
* @brief Disables the interrupt sources below kernel-level priority.
*/
static inline void port_suspend(void) {
__disable_irq();
}
/**
* @brief Enables all the interrupt sources.
*/
static inline void port_enable(void) {
__enable_irq();
}
/**
* @brief Enters an architecture-dependent IRQ-waiting mode.
* @details The function is meant to return when an interrupt becomes pending.
* The simplest implementation is an empty function or macro but this
* would not take advantage of architecture-specific power saving
* modes.
* @note Implemented as an inlined @p WFI instruction.
*/
static inline void port_wait_for_interrupt(void) {
#if CORTEX_ENABLE_WFI_IDLE == TRUE
__WFI();
#endif
}
#endif /* _FROM_ASM_ */
#endif /* _CHCORE_V6M_H_ */
/** @} */

View File

@ -1,168 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file chcore_v7m.c
* @brief ARMv7-M architecture port code.
*
* @addtogroup ARMCMx_V7M_CORE
* @{
*/
#include "ch.h"
/*===========================================================================*/
/* Module local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module interrupt handlers. */
/*===========================================================================*/
#if (CORTEX_SIMPLIFIED_PRIORITY == FALSE) || defined(__DOXYGEN__)
/**
* @brief SVC vector.
* @details The SVC vector is used for exception mode re-entering after a
* context switch.
* @note The PendSV vector is only used in advanced kernel mode.
*/
/*lint -save -e9075 [8.4] All symbols are invoked from asm context.*/
void SVC_Handler(void) {
/*lint -restore*/
struct port_extctx *ctxp;
#if CORTEX_USE_FPU
/* Enforcing unstacking of the FP part of the context.*/
FPU->FPCCR &= ~FPU_FPCCR_LSPACT_Msk;
#endif
/* The port_extctx structure is pointed by the PSP register.*/
ctxp = (struct port_extctx *)__get_PSP();
/* Discarding the current exception context and positioning the stack to
point to the real one.*/
ctxp++;
/* Restoring real position of the original stack frame.*/
__set_PSP((uint32_t)ctxp);
/* Restoring the normal interrupts status.*/
port_unlock_from_isr();
}
#endif /* CORTEX_SIMPLIFIED_PRIORITY == FALSE */
#if (CORTEX_SIMPLIFIED_PRIORITY == TRUE) || defined(__DOXYGEN__)
/**
* @brief PendSV vector.
* @details The PendSV vector is used for exception mode re-entering after a
* context switch.
* @note The PendSV vector is only used in compact kernel mode.
*/
/*lint -save -e9075 [8.4] All symbols are invoked from asm context.*/
void PendSV_Handler(void) {
/*lint -restore*/
struct port_extctx *ctxp;
#if CORTEX_USE_FPU
/* Enforcing unstacking of the FP part of the context.*/
FPU->FPCCR &= ~FPU_FPCCR_LSPACT_Msk;
#endif
/* The port_extctx structure is pointed by the PSP register.*/
ctxp = (struct port_extctx *)__get_PSP();
/* Discarding the current exception context and positioning the stack to
point to the real one.*/
ctxp++;
/* Writing back the modified PSP value.*/
__set_PSP((uint32_t)ctxp);
}
#endif /* CORTEX_SIMPLIFIED_PRIORITY == TRUE */
/*===========================================================================*/
/* Module exported functions. */
/*===========================================================================*/
/**
* @brief Exception exit redirection to _port_switch_from_isr().
*/
void _port_irq_epilogue(void) {
port_lock_from_isr();
if ((SCB->ICSR & SCB_ICSR_RETTOBASE_Msk) != 0U) {
struct port_extctx *ctxp;
#if CORTEX_USE_FPU == TRUE
/* Enforcing a lazy FPU state save by accessing the FPCSR register.*/
(void) __get_FPSCR();
#endif
/* The port_extctx structure is pointed by the PSP register.*/
ctxp = (struct port_extctx *)__get_PSP();
/* Adding an artificial exception return context, there is no need to
populate it fully.*/
ctxp--;
/* Setting up a fake XPSR register value.*/
ctxp->xpsr = (regarm_t)0x01000000;
#if CORTEX_USE_FPU == TRUE
ctxp->fpscr = (regarm_t)FPU->FPDSCR;
#endif
/* Writing back the modified PSP value.*/
__set_PSP((uint32_t)ctxp);
/* The exit sequence is different depending on if a preemption is
required or not.*/
if (chSchIsPreemptionRequired()) {
/* Preemption is required we need to enforce a context switch.*/
ctxp->pc = (regarm_t)_port_switch_from_isr;
}
else {
/* Preemption not required, we just need to exit the exception
atomically.*/
ctxp->pc = (regarm_t)_port_exit_from_isr;
}
/* Note, returning without unlocking is intentional, this is done in
order to keep the rest of the context switch atomic.*/
return;
}
port_unlock_from_isr();
}
/** @} */

View File

@ -1,577 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file chcore_v7m.h
* @brief ARMv7-M architecture port macros and structures.
*
* @addtogroup ARMCMx_V7M_CORE
* @{
*/
#ifndef _CHCORE_V7M_H_
#define _CHCORE_V7M_H_
/*===========================================================================*/
/* Module constants. */
/*===========================================================================*/
/**
* @brief This port supports a realtime counter.
*/
#define PORT_SUPPORTS_RT TRUE
/**
* @brief Disabled value for BASEPRI register.
*/
#define CORTEX_BASEPRI_DISABLED 0U
/*===========================================================================*/
/* Module pre-compile time settings. */
/*===========================================================================*/
/**
* @brief Stack size for the system idle thread.
* @details This size depends on the idle thread implementation, usually
* the idle thread should take no more space than those reserved
* by @p PORT_INT_REQUIRED_STACK.
* @note In this port it is set to 16 because the idle thread does have
* a stack frame when compiling without optimizations. You may
* reduce this value to zero when compiling with optimizations.
*/
#if !defined(PORT_IDLE_THREAD_STACK_SIZE) || defined(__DOXYGEN__)
#define PORT_IDLE_THREAD_STACK_SIZE 16
#endif
/**
* @brief Per-thread stack overhead for interrupts servicing.
* @details This constant is used in the calculation of the correct working
* area size.
* @note In this port this value is conservatively set to 64 because the
* function @p chSchDoReschedule() can have a stack frame, especially
* with compiler optimizations disabled. The value can be reduced
* when compiler optimizations are enabled.
*/
#if !defined(PORT_INT_REQUIRED_STACK) || defined(__DOXYGEN__)
#define PORT_INT_REQUIRED_STACK 64
#endif
/**
* @brief Enables the use of the WFI instruction in the idle thread loop.
*/
#if !defined(CORTEX_ENABLE_WFI_IDLE)
#define CORTEX_ENABLE_WFI_IDLE FALSE
#endif
/**
* @brief FPU support in context switch.
* @details Activating this option activates the FPU support in the kernel.
*/
#if !defined(CORTEX_USE_FPU)
#define CORTEX_USE_FPU CORTEX_HAS_FPU
#elif (CORTEX_USE_FPU == TRUE) && (CORTEX_HAS_FPU == FALSE)
/* This setting requires an FPU presence check in case it is externally
redefined.*/
#error "the selected core does not have an FPU"
#endif
/**
* @brief Simplified priority handling flag.
* @details Activating this option makes the Kernel work in compact mode.
* In compact mode interrupts are disabled globally instead of
* raising the priority mask to some intermediate level.
*/
#if !defined(CORTEX_SIMPLIFIED_PRIORITY)
#define CORTEX_SIMPLIFIED_PRIORITY FALSE
#endif
/**
* @brief SVCALL handler priority.
* @note The default SVCALL handler priority is defaulted to
* @p CORTEX_MAXIMUM_PRIORITY+1, this reserves the
* @p CORTEX_MAXIMUM_PRIORITY priority level as fast interrupts
* priority level.
*/
#if !defined(CORTEX_PRIORITY_SVCALL)
#define CORTEX_PRIORITY_SVCALL (CORTEX_MAXIMUM_PRIORITY + 1U)
#elif !PORT_IRQ_IS_VALID_PRIORITY(CORTEX_PRIORITY_SVCALL)
/* If it is externally redefined then better perform a validity check on it.*/
#error "invalid priority level specified for CORTEX_PRIORITY_SVCALL"
#endif
/**
* @brief NVIC VTOR initialization expression.
*/
#if !defined(CORTEX_VTOR_INIT) || defined(__DOXYGEN__)
#define CORTEX_VTOR_INIT 0x00000000U
#endif
/**
* @brief NVIC PRIGROUP initialization expression.
* @details The default assigns all available priority bits as preemption
* priority with no sub-priority.
*/
#if !defined(CORTEX_PRIGROUP_INIT) || defined(__DOXYGEN__)
#define CORTEX_PRIGROUP_INIT (7 - CORTEX_PRIORITY_BITS)
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/**
* @name Architecture and Compiler
* @{
*/
#if (CORTEX_MODEL == 3) || defined(__DOXYGEN__)
/**
* @brief Macro defining the specific ARM architecture.
*/
#define PORT_ARCHITECTURE_ARM_v7M
/**
* @brief Name of the implemented architecture.
*/
#define PORT_ARCHITECTURE_NAME "ARMv7-M"
/**
* @brief Name of the architecture variant.
*/
#define PORT_CORE_VARIANT_NAME "Cortex-M3"
#elif (CORTEX_MODEL == 4)
#define PORT_ARCHITECTURE_ARM_v7ME
#define PORT_ARCHITECTURE_NAME "ARMv7E-M"
#if CORTEX_USE_FPU
#define PORT_CORE_VARIANT_NAME "Cortex-M4F"
#else
#define PORT_CORE_VARIANT_NAME "Cortex-M4"
#endif
#elif (CORTEX_MODEL == 7)
#define PORT_ARCHITECTURE_ARM_v7ME
#define PORT_ARCHITECTURE_NAME "ARMv7E-M"
#if CORTEX_USE_FPU
#define PORT_CORE_VARIANT_NAME "Cortex-M7F"
#else
#define PORT_CORE_VARIANT_NAME "Cortex-M7"
#endif
#endif
/**
* @brief Port-specific information string.
*/
#if (CORTEX_SIMPLIFIED_PRIORITY == FALSE) || defined(__DOXYGEN__)
#define PORT_INFO "Advanced kernel mode"
#else
#define PORT_INFO "Compact kernel mode"
#endif
/** @} */
#if (CORTEX_SIMPLIFIED_PRIORITY == FALSE) || defined(__DOXYGEN__)
/**
* @brief Maximum usable priority for normal ISRs.
*/
#define CORTEX_MAX_KERNEL_PRIORITY (CORTEX_PRIORITY_SVCALL + 1U)
/**
* @brief BASEPRI level within kernel lock.
*/
#define CORTEX_BASEPRI_KERNEL \
CORTEX_PRIO_MASK(CORTEX_MAX_KERNEL_PRIORITY)
#else
#define CORTEX_MAX_KERNEL_PRIORITY 0U
#endif
/**
* @brief PendSV priority level.
* @note This priority is enforced to be equal to
* @p CORTEX_MAX_KERNEL_PRIORITY, this handler always have the
* highest priority that cannot preempt the kernel.
*/
#define CORTEX_PRIORITY_PENDSV CORTEX_MAX_KERNEL_PRIORITY
/*===========================================================================*/
/* Module data structures and types. */
/*===========================================================================*/
/* The following code is not processed when the file is included from an
asm module.*/
#if !defined(_FROM_ASM_)
/* The documentation of the following declarations is in chconf.h in order
to not have duplicated structure names into the documentation.*/
#if !defined(__DOXYGEN__)
struct port_extctx {
regarm_t r0;
regarm_t r1;
regarm_t r2;
regarm_t r3;
regarm_t r12;
regarm_t lr_thd;
regarm_t pc;
regarm_t xpsr;
#if CORTEX_USE_FPU
regarm_t s0;
regarm_t s1;
regarm_t s2;
regarm_t s3;
regarm_t s4;
regarm_t s5;
regarm_t s6;
regarm_t s7;
regarm_t s8;
regarm_t s9;
regarm_t s10;
regarm_t s11;
regarm_t s12;
regarm_t s13;
regarm_t s14;
regarm_t s15;
regarm_t fpscr;
regarm_t reserved;
#endif /* CORTEX_USE_FPU */
};
struct port_intctx {
#if CORTEX_USE_FPU
regarm_t s16;
regarm_t s17;
regarm_t s18;
regarm_t s19;
regarm_t s20;
regarm_t s21;
regarm_t s22;
regarm_t s23;
regarm_t s24;
regarm_t s25;
regarm_t s26;
regarm_t s27;
regarm_t s28;
regarm_t s29;
regarm_t s30;
regarm_t s31;
#endif /* CORTEX_USE_FPU */
regarm_t r4;
regarm_t r5;
regarm_t r6;
regarm_t r7;
regarm_t r8;
regarm_t r9;
regarm_t r10;
regarm_t r11;
regarm_t lr;
};
#endif /* !defined(__DOXYGEN__) */
/*===========================================================================*/
/* Module macros. */
/*===========================================================================*/
/**
* @brief Platform dependent part of the @p chThdCreateI() API.
* @details This code usually setup the context switching frame represented
* by an @p port_intctx structure.
*/
#define PORT_SETUP_CONTEXT(tp, workspace, wsize, pf, arg) { \
(tp)->p_ctx.r13 = (struct port_intctx *)((uint8_t *)(workspace) + \
(size_t)(wsize) - \
sizeof(struct port_intctx)); \
(tp)->p_ctx.r13->r4 = (regarm_t)(pf); \
(tp)->p_ctx.r13->r5 = (regarm_t)(arg); \
(tp)->p_ctx.r13->lr = (regarm_t)_port_thread_start; \
}
/**
* @brief Computes the thread working area global size.
* @note There is no need to perform alignments in this macro.
*/
#define PORT_WA_SIZE(n) (sizeof(struct port_intctx) + \
sizeof(struct port_extctx) + \
((size_t)(n)) + ((size_t)(PORT_INT_REQUIRED_STACK)))
/**
* @brief IRQ prologue code.
* @details This macro must be inserted at the start of all IRQ handlers
* enabled to invoke system APIs.
*/
#define PORT_IRQ_PROLOGUE()
/**
* @brief IRQ epilogue code.
* @details This macro must be inserted at the end of all IRQ handlers
* enabled to invoke system APIs.
*/
#define PORT_IRQ_EPILOGUE() _port_irq_epilogue()
/**
* @brief IRQ handler function declaration.
* @note @p id can be a function name or a vector number depending on the
* port implementation.
*/
#define PORT_IRQ_HANDLER(id) void id(void)
/**
* @brief Fast IRQ handler function declaration.
* @note @p id can be a function name or a vector number depending on the
* port implementation.
*/
#define PORT_FAST_IRQ_HANDLER(id) void id(void)
/**
* @brief Performs a context switch between two threads.
* @details This is the most critical code in any port, this function
* is responsible for the context switch between 2 threads.
* @note The implementation of this code affects <b>directly</b> the context
* switch performance so optimize here as much as you can.
*
* @param[in] ntp the thread to be switched in
* @param[in] otp the thread to be switched out
*/
#if (CH_DBG_ENABLE_STACK_CHECK == FALSE) || defined(__DOXYGEN__)
#define port_switch(ntp, otp) _port_switch(ntp, otp)
#else
#define port_switch(ntp, otp) { \
struct port_intctx *r13 = (struct port_intctx *)__get_PSP(); \
if ((stkalign_t *)(r13 - 1) < (otp)->p_stklimit) { \
chSysHalt("stack overflow"); \
} \
_port_switch(ntp, otp); \
}
#endif
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void _port_irq_epilogue(void);
void _port_switch(thread_t *ntp, thread_t *otp);
void _port_thread_start(void);
void _port_switch_from_isr(void);
void _port_exit_from_isr(void);
#ifdef __cplusplus
}
#endif
/*===========================================================================*/
/* Module inline functions. */
/*===========================================================================*/
/**
* @brief Port-related initialization code.
*/
static inline void port_init(void) {
/* Initialization of the vector table and priority related settings.*/
SCB->VTOR = CORTEX_VTOR_INIT;
/* Initializing priority grouping.*/
NVIC_SetPriorityGrouping(CORTEX_PRIGROUP_INIT);
/* DWT cycle counter enable, note, the M7 requires DWT unlocking.*/
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
#if CORTEX_MODEL == 7
DWT->LAR = 0xC5ACCE55U;
#endif
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
/* Initialization of the system vectors used by the port.*/
#if CORTEX_SIMPLIFIED_PRIORITY == FALSE
NVIC_SetPriority(SVCall_IRQn, CORTEX_PRIORITY_SVCALL);
#endif
NVIC_SetPriority(PendSV_IRQn, CORTEX_PRIORITY_PENDSV);
}
/**
* @brief Returns a word encoding the current interrupts status.
*
* @return The interrupts status.
*/
static inline syssts_t port_get_irq_status(void) {
syssts_t sts;
#if CORTEX_SIMPLIFIED_PRIORITY == FALSE
sts = (syssts_t)__get_BASEPRI();
#else /* CORTEX_SIMPLIFIED_PRIORITY */
sts = (syssts_t)__get_PRIMASK();
#endif /* CORTEX_SIMPLIFIED_PRIORITY */
return sts;
}
/**
* @brief Checks the interrupt status.
*
* @param[in] sts the interrupt status word
*
* @return The interrupt status.
* @retvel false the word specified a disabled interrupts status.
* @retvel true the word specified an enabled interrupts status.
*/
static inline bool port_irq_enabled(syssts_t sts) {
#if CORTEX_SIMPLIFIED_PRIORITY == FALSE
return sts == (syssts_t)CORTEX_BASEPRI_DISABLED;
#else /* CORTEX_SIMPLIFIED_PRIORITY */
return (sts & (syssts_t)1) == (syssts_t)0;
#endif /* CORTEX_SIMPLIFIED_PRIORITY */
}
/**
* @brief Determines the current execution context.
*
* @return The execution context.
* @retval false not running in ISR mode.
* @retval true running in ISR mode.
*/
static inline bool port_is_isr_context(void) {
return (bool)((__get_IPSR() & 0x1FFU) != 0U);
}
/**
* @brief Kernel-lock action.
* @details In this port this function raises the base priority to kernel
* level.
*/
static inline void port_lock(void) {
#if CORTEX_SIMPLIFIED_PRIORITY == FALSE
#if defined(__CM7_REV)
#if __CM7_REV <= 1
__disable_irq();
#endif
#endif
__set_BASEPRI(CORTEX_BASEPRI_KERNEL);
#if defined(__CM7_REV)
#if __CM7_REV <= 1
__enable_irq();
#endif
#endif
#else /* CORTEX_SIMPLIFIED_PRIORITY */
__disable_irq();
#endif /* CORTEX_SIMPLIFIED_PRIORITY */
}
/**
* @brief Kernel-unlock action.
* @details In this port this function lowers the base priority to user
* level.
*/
static inline void port_unlock(void) {
#if CORTEX_SIMPLIFIED_PRIORITY == FALSE
__set_BASEPRI(CORTEX_BASEPRI_DISABLED);
#else /* CORTEX_SIMPLIFIED_PRIORITY */
__enable_irq();
#endif /* CORTEX_SIMPLIFIED_PRIORITY */
}
/**
* @brief Kernel-lock action from an interrupt handler.
* @details In this port this function raises the base priority to kernel
* level.
* @note Same as @p port_lock() in this port.
*/
static inline void port_lock_from_isr(void) {
port_lock();
}
/**
* @brief Kernel-unlock action from an interrupt handler.
* @details In this port this function lowers the base priority to user
* level.
* @note Same as @p port_unlock() in this port.
*/
static inline void port_unlock_from_isr(void) {
port_unlock();
}
/**
* @brief Disables all the interrupt sources.
* @note In this port it disables all the interrupt sources by raising
* the priority mask to level 0.
*/
static inline void port_disable(void) {
__disable_irq();
}
/**
* @brief Disables the interrupt sources below kernel-level priority.
* @note Interrupt sources above kernel level remains enabled.
* @note In this port it raises/lowers the base priority to kernel level.
*/
static inline void port_suspend(void) {
#if (CORTEX_SIMPLIFIED_PRIORITY == FALSE) || defined(__DOXYGEN__)
__set_BASEPRI(CORTEX_BASEPRI_KERNEL);
__enable_irq();
#else
__disable_irq();
#endif
}
/**
* @brief Enables all the interrupt sources.
* @note In this port it lowers the base priority to user level.
*/
static inline void port_enable(void) {
#if (CORTEX_SIMPLIFIED_PRIORITY == FALSE) || defined(__DOXYGEN__)
__set_BASEPRI(CORTEX_BASEPRI_DISABLED);
#endif
__enable_irq();
}
/**
* @brief Enters an architecture-dependent IRQ-waiting mode.
* @details The function is meant to return when an interrupt becomes pending.
* The simplest implementation is an empty function or macro but this
* would not take advantage of architecture-specific power saving
* modes.
* @note Implemented as an inlined @p WFI instruction.
*/
static inline void port_wait_for_interrupt(void) {
#if CORTEX_ENABLE_WFI_IDLE == TRUE
__WFI();
#endif
}
/**
* @brief Returns the current value of the realtime counter.
*
* @return The realtime counter value.
*/
static inline rtcnt_t port_rt_get_counter_value(void) {
return DWT->CYCCNT;
}
#endif /* !defined(_FROM_ASM_) */
#endif /* _CHCORE_V7M_H_ */
/** @} */

View File

@ -1,554 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/*
Concepts and parts of this file have been contributed by Andre R.
*/
/**
* @file cmsis_os.c
* @brief CMSIS RTOS module code.
*
* @addtogroup CMSIS_OS
* @{
*/
#include "cmsis_os.h"
#include <string.h>
/*===========================================================================*/
/* Module local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported variables. */
/*===========================================================================*/
int32_t cmsis_os_started;
/*===========================================================================*/
/* Module local types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local variables. */
/*===========================================================================*/
static memory_pool_t sempool;
static semaphore_t semaphores[CMSIS_CFG_NUM_SEMAPHORES];
static memory_pool_t timpool;
static struct os_timer_cb timers[CMSIS_CFG_NUM_TIMERS];
/*===========================================================================*/
/* Module local functions. */
/*===========================================================================*/
/**
* @brief Virtual timers common callback.
*/
static void timer_cb(void const *arg) {
osTimerId timer_id = (osTimerId)arg;
timer_id->ptimer(timer_id->argument);
if (timer_id->type == osTimerPeriodic) {
chSysLockFromISR();
chVTDoSetI(&timer_id->vt, MS2ST(timer_id->millisec),
(vtfunc_t)timer_cb, timer_id);
chSysUnlockFromISR();
}
}
/*===========================================================================*/
/* Module exported functions. */
/*===========================================================================*/
/**
* @brief Kernel initialization.
*/
osStatus osKernelInitialize(void) {
cmsis_os_started = 0;
chSysInit();
chThdSetPriority(HIGHPRIO);
chPoolObjectInit(&sempool, sizeof(semaphore_t), chCoreAlloc);
chPoolLoadArray(&sempool, semaphores, CMSIS_CFG_NUM_SEMAPHORES);
chPoolObjectInit(&timpool, sizeof(virtual_timer_t), chCoreAlloc);
chPoolLoadArray(&timpool, timers, CMSIS_CFG_NUM_TIMERS);
return osOK;
}
/**
* @brief Kernel start.
*/
osStatus osKernelStart(void) {
cmsis_os_started = 1;
chThdSetPriority(NORMALPRIO);
return osOK;
}
/**
* @brief Creates a thread.
*/
osThreadId osThreadCreate(const osThreadDef_t *thread_def, void *argument) {
size_t size;
size = thread_def->stacksize == 0 ? CMSIS_CFG_DEFAULT_STACK :
thread_def->stacksize;
return (osThreadId)chThdCreateFromHeap(0,
THD_WORKING_AREA_SIZE(size),
NORMALPRIO+thread_def->tpriority,
(tfunc_t)thread_def->pthread,
argument);
}
/**
* @brief Thread termination.
* @note The thread is not really terminated but asked to terminate which
* is not compliant.
*/
osStatus osThreadTerminate(osThreadId thread_id) {
if (thread_id == osThreadGetId()) {
/* Note, no memory will be recovered unless a cleaner thread is
implemented using the registry.*/
chThdExit(0);
}
chThdTerminate(thread_id);
chThdWait((thread_t *)thread_id);
return osOK;
}
/**
* @brief Change thread priority.
* @note This can interfere with the priority inheritance mechanism.
*/
osStatus osThreadSetPriority(osThreadId thread_id, osPriority newprio) {
osPriority oldprio;
thread_t * tp = (thread_t *)thread_id;
chSysLock();
/* Changing priority.*/
#if CH_CFG_USE_MUTEXES
oldprio = (osPriority)tp->p_realprio;
if ((tp->p_prio == tp->p_realprio) || ((tprio_t)newprio > tp->p_prio))
tp->p_prio = (tprio_t)newprio;
tp->p_realprio = (tprio_t)newprio;
#else
oldprio = tp->p_prio;
tp->p_prio = (tprio_t)newprio;
#endif
/* The following states need priority queues reordering.*/
switch (tp->p_state) {
#if CH_CFG_USE_MUTEXES | \
CH_CFG_USE_CONDVARS | \
(CH_CFG_USE_SEMAPHORES && CH_CFG_USE_SEMAPHORES_PRIORITY) | \
(CH_CFG_USE_MESSAGES && CH_CFG_USE_MESSAGES_PRIORITY)
#if CH_CFG_USE_MUTEXES
case CH_STATE_WTMTX:
#endif
#if CH_CFG_USE_CONDVARS
case CH_STATE_WTCOND:
#endif
#if CH_CFG_USE_SEMAPHORES && CH_CFG_USE_SEMAPHORES_PRIORITY
case CH_STATE_WTSEM:
#endif
#if CH_CFG_USE_MESSAGES && CH_CFG_USE_MESSAGES_PRIORITY
case CH_STATE_SNDMSGQ:
#endif
/* Re-enqueues tp with its new priority on the queue.*/
queue_prio_insert(queue_dequeue(tp),
(threads_queue_t *)tp->p_u.wtobjp);
break;
#endif
case CH_STATE_READY:
#if CH_DBG_ENABLE_ASSERTS
/* Prevents an assertion in chSchReadyI().*/
tp->p_state = CH_STATE_CURRENT;
#endif
/* Re-enqueues tp with its new priority on the ready list.*/
chSchReadyI(queue_dequeue(tp));
break;
}
/* Rescheduling.*/
chSchRescheduleS();
chSysUnlock();
return oldprio;
}
/**
* @brief Create a timer.
*/
osTimerId osTimerCreate(const osTimerDef_t *timer_def,
os_timer_type type,
void *argument) {
osTimerId timer = chPoolAlloc(&timpool);
chVTObjectInit(&timer->vt);
timer->ptimer = timer_def->ptimer;
timer->type = type;
timer->argument = argument;
return timer;
}
/**
* @brief Start a timer.
*/
osStatus osTimerStart(osTimerId timer_id, uint32_t millisec) {
if ((millisec == 0) || (millisec == osWaitForever))
return osErrorValue;
timer_id->millisec = millisec;
chVTSet(&timer_id->vt, MS2ST(millisec), (vtfunc_t)timer_cb, timer_id);
return osOK;
}
/**
* @brief Stop a timer.
*/
osStatus osTimerStop(osTimerId timer_id) {
chVTReset(&timer_id->vt);
return osOK;
}
/**
* @brief Delete a timer.
*/
osStatus osTimerDelete(osTimerId timer_id) {
chVTReset(&timer_id->vt);
chPoolFree(&timpool, (void *)timer_id);
return osOK;
}
/**
* @brief Send signals.
*/
int32_t osSignalSet(osThreadId thread_id, int32_t signals) {
int32_t oldsignals;
syssts_t sts = chSysGetStatusAndLockX();
oldsignals = (int32_t)thread_id->p_epending;
chEvtSignalI((thread_t *)thread_id, (eventmask_t)signals);
chSysRestoreStatusX(sts);
return oldsignals;
}
/**
* @brief Clear signals.
*/
int32_t osSignalClear(osThreadId thread_id, int32_t signals) {
eventmask_t m;
chSysLock();
m = thread_id->p_epending & (eventmask_t)signals;
thread_id->p_epending &= ~(eventmask_t)signals;
chSysUnlock();
return (int32_t)m;
}
/**
* @brief Wait for signals.
*/
osEvent osSignalWait(int32_t signals, uint32_t millisec) {
osEvent event;
systime_t timeout = ((millisec == 0) || (millisec == osWaitForever)) ?
TIME_INFINITE : MS2ST(millisec);
if (signals == 0)
event.value.signals = (uint32_t)chEvtWaitAnyTimeout(ALL_EVENTS, timeout);
else
event.value.signals = (uint32_t)chEvtWaitAllTimeout((eventmask_t)signals,
timeout);
/* Type of event.*/
if (event.value.signals == 0)
event.status = osEventTimeout;
else
event.status = osEventSignal;
return event;
}
/**
* @brief Create a semaphore.
* @note @p semaphore_def is not used.
* @note Can involve memory allocation.
*/
osSemaphoreId osSemaphoreCreate(const osSemaphoreDef_t *semaphore_def,
int32_t count) {
(void)semaphore_def;
semaphore_t *sem = chPoolAlloc(&sempool);
chSemObjectInit(sem, (cnt_t)count);
return sem;
}
/**
* @brief Wait on a semaphore.
*/
int32_t osSemaphoreWait(osSemaphoreId semaphore_id, uint32_t millisec) {
systime_t timeout = ((millisec == 0) || (millisec == osWaitForever)) ?
TIME_INFINITE : MS2ST(millisec);
msg_t msg = chSemWaitTimeout((semaphore_t *)semaphore_id, timeout);
switch (msg) {
case MSG_OK:
return osOK;
case MSG_TIMEOUT:
return osErrorTimeoutResource;
}
return osErrorResource;
}
/**
* @brief Release a semaphore.
*/
osStatus osSemaphoreRelease(osSemaphoreId semaphore_id) {
syssts_t sts = chSysGetStatusAndLockX();
chSemSignalI((semaphore_t *)semaphore_id);
chSysRestoreStatusX(sts);
return osOK;
}
/**
* @brief Deletes a semaphore.
* @note After deletion there could be references in the system to a
* non-existent semaphore.
*/
osStatus osSemaphoreDelete(osSemaphoreId semaphore_id) {
chSemReset((semaphore_t *)semaphore_id, 0);
chPoolFree(&sempool, (void *)semaphore_id);
return osOK;
}
/**
* @brief Create a mutex.
* @note @p mutex_def is not used.
* @note Can involve memory allocation.
*/
osMutexId osMutexCreate(const osMutexDef_t *mutex_def) {
(void)mutex_def;
binary_semaphore_t *mtx = chPoolAlloc(&sempool);
chBSemObjectInit(mtx, false);
return mtx;
}
/**
* @brief Wait on a mutex.
*/
osStatus osMutexWait(osMutexId mutex_id, uint32_t millisec) {
systime_t timeout = ((millisec == 0) || (millisec == osWaitForever)) ?
TIME_INFINITE : MS2ST(millisec);
msg_t msg = chBSemWaitTimeout((binary_semaphore_t *)mutex_id, timeout);
switch (msg) {
case MSG_OK:
return osOK;
case MSG_TIMEOUT:
return osErrorTimeoutResource;
}
return osErrorResource;
}
/**
* @brief Release a mutex.
*/
osStatus osMutexRelease(osMutexId mutex_id) {
syssts_t sts = chSysGetStatusAndLockX();
chBSemSignalI((binary_semaphore_t *)mutex_id);
chSysRestoreStatusX(sts);
return osOK;
}
/**
* @brief Deletes a mutex.
* @note After deletion there could be references in the system to a
* non-existent semaphore.
*/
osStatus osMutexDelete(osMutexId mutex_id) {
chSemReset((semaphore_t *)mutex_id, 0);
chPoolFree(&sempool, (void *)mutex_id);
return osOK;
}
/**
* @brief Create a memory pool.
* @note The pool is not really created because it is allocated statically,
* this function just re-initializes it.
*/
osPoolId osPoolCreate(const osPoolDef_t *pool_def) {
chPoolObjectInit(pool_def->pool, (size_t)pool_def->item_sz, NULL);
chPoolLoadArray(pool_def->pool, pool_def->items, (size_t)pool_def->pool_sz);
return (osPoolId)pool_def->pool;
}
/**
* @brief Allocate an object.
*/
void *osPoolAlloc(osPoolId pool_id) {
void *object;
syssts_t sts = chSysGetStatusAndLockX();
object = chPoolAllocI((memory_pool_t *)pool_id);
chSysRestoreStatusX(sts);
return object;
}
/**
* @brief Allocate an object clearing it.
*/
void *osPoolCAlloc(osPoolId pool_id) {
void *object;
object = chPoolAllocI((memory_pool_t *)pool_id);
memset(object, 0, pool_id->mp_object_size);
return object;
}
/**
* @brief Free an object.
*/
osStatus osPoolFree(osPoolId pool_id, void *block) {
syssts_t sts = chSysGetStatusAndLockX();
chPoolFreeI((memory_pool_t *)pool_id, block);
chSysRestoreStatusX(sts);
return osOK;
}
/**
* @brief Create a message queue.
* @note The queue is not really created because it is allocated statically,
* this function just re-initializes it.
*/
osMessageQId osMessageCreate(const osMessageQDef_t *queue_def,
osThreadId thread_id) {
/* Ignoring this parameter for now.*/
(void)thread_id;
if (queue_def->item_sz > sizeof (msg_t))
return NULL;
chMBObjectInit(queue_def->mailbox,
queue_def->items,
(size_t)queue_def->queue_sz);
return (osMessageQId) queue_def->mailbox;
}
/**
* @brief Put a message in the queue.
*/
osStatus osMessagePut(osMessageQId queue_id,
uint32_t info,
uint32_t millisec) {
msg_t msg;
systime_t timeout = ((millisec == 0) || (millisec == osWaitForever)) ?
TIME_INFINITE : MS2ST(millisec);
if (port_is_isr_context()) {
/* Waiting makes no sense in ISRs so any value except "immediate"
makes no sense.*/
if (millisec != 0)
return osErrorValue;
chSysLockFromISR();
msg = chMBPostI((mailbox_t *)queue_id, (msg_t)info);
chSysUnlockFromISR();
}
else
msg = chMBPost((mailbox_t *)queue_id, (msg_t)info, timeout);
return msg == MSG_OK ? osOK : osEventTimeout;
}
/**
* @brief Get a message from the queue.
*/
osEvent osMessageGet(osMessageQId queue_id,
uint32_t millisec) {
msg_t msg;
osEvent event;
systime_t timeout = ((millisec == 0) || (millisec == osWaitForever)) ?
TIME_INFINITE : MS2ST(millisec);
event.def.message_id = queue_id;
if (port_is_isr_context()) {
/* Waiting makes no sense in ISRs so any value except "immediate"
makes no sense.*/
if (millisec != 0) {
event.status = osErrorValue;
return event;
}
chSysLockFromISR();
msg = chMBFetchI((mailbox_t *)queue_id, (msg_t*)&event.value.v);
chSysUnlockFromISR();
}
else {
msg = chMBFetch((mailbox_t *)queue_id, (msg_t*)&event.value.v, timeout);
}
/* Returned event type.*/
event.status = msg == MSG_OK ? osEventMessage : osEventTimeout;
return event;
}
/** @} */

View File

@ -1,520 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/*
Concepts and parts of this file have been contributed by Andre R.
*/
/**
* @file cmsis_os.h
* @brief CMSIS RTOS module macros and structures.
*
* @addtogroup CMSIS_OS
* @{
*/
#ifndef _CMSIS_OS_H_
#define _CMSIS_OS_H_
#include "ch.h"
/*===========================================================================*/
/* Module constants. */
/*===========================================================================*/
/**
* @brief API version.
*/
#define osCMSIS 0x10002
/**
* @brief Kernel version.
*/
#define osKernelSystemId "KERNEL V1.00"
/**
* @brief ChibiOS/RT version encoded for CMSIS.
*/
#define osCMSIS_KERNEL ((CH_KERNEL_MAJOR << 16) | \
(CH_KERNEL_MINOR << 8) | \
(CH_KERNEL_PATCH))
/**
* @name CMSIS Capabilities
* @{
*/
#define osFeature_MainThread 1
#define osFeature_Pool 1
#define osFeature_MailQ 0
#define osFeature_MessageQ 1
#define osFeature_Signals 24
#define osFeature_Semaphore ((1U << 31) - 1U)
#define osFeature_Wait 0
#define osFeature_SysTick 1
/**< @} */
/**
* @brief Wait forever specification for timeouts.
*/
#define osWaitForever TIME_INFINITE
/**
* @brief System tick frequency.
*/
#define osKernelSysTickFrequency CH_CFG_FREQUENCY
/*===========================================================================*/
/* Module pre-compile time settings. */
/*===========================================================================*/
/**
* @brief Number of pre-allocated static semaphores/mutexes.
*/
#if !defined(CMSIS_CFG_DEFAULT_STACK)
#define CMSIS_CFG_DEFAULT_STACK 256
#endif
/**
* @brief Number of pre-allocated static semaphores/mutexes.
*/
#if !defined(CMSIS_CFG_NUM_SEMAPHORES)
#define CMSIS_CFG_NUM_SEMAPHORES 4
#endif
/**
* @brief Number of pre-allocated static timers.
*/
#if !defined(CMSIS_CFG_NUM_TIMERS)
#define CMSIS_CFG_NUM_TIMERS 4
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !CH_CFG_USE_MEMPOOLS
#error "CMSIS RTOS requires CH_CFG_USE_MEMPOOLS"
#endif
#if !CH_CFG_USE_EVENTS
#error "CMSIS RTOS requires CH_CFG_USE_EVENTS"
#endif
#if !CH_CFG_USE_EVENTS_TIMEOUT
#error "CMSIS RTOS requires CH_CFG_USE_EVENTS_TIMEOUT"
#endif
#if !CH_CFG_USE_SEMAPHORES
#error "CMSIS RTOS requires CH_CFG_USE_SEMAPHORES"
#endif
#if !CH_CFG_USE_DYNAMIC
#error "CMSIS RTOS requires CH_CFG_USE_DYNAMIC"
#endif
/*===========================================================================*/
/* Module data structures and types. */
/*===========================================================================*/
/**
* @brief Type of priority levels.
*/
typedef enum {
osPriorityIdle = -3,
osPriorityLow = -2,
osPriorityBelowNormal = -1,
osPriorityNormal = 0,
osPriorityAboveNormal = +1,
osPriorityHigh = +2,
osPriorityRealtime = +3,
osPriorityError = 0x84
} osPriority;
/**
* @brief Type of error codes.
*/
typedef enum {
osOK = 0,
osEventSignal = 0x08,
osEventMessage = 0x10,
osEventMail = 0x20,
osEventTimeout = 0x40,
osErrorParameter = 0x80,
osErrorResource = 0x81,
osErrorTimeoutResource = 0xC1,
osErrorISR = 0x82,
osErrorISRRecursive = 0x83,
osErrorPriority = 0x84,
osErrorNoMemory = 0x85,
osErrorValue = 0x86,
osErrorOS = 0xFF,
os_status_reserved = 0x7FFFFFFF
} osStatus;
/**
* @brief Type of a timer mode.
*/
typedef enum {
osTimerOnce = 0,
osTimerPeriodic = 1
} os_timer_type;
/**
* @brief Type of thread functions.
*/
typedef void (*os_pthread) (void const *argument);
/**
* @brief Type of timer callback.
*/
typedef void (*os_ptimer) (void const *argument);
/**
* @brief Type of pointer to thread control block.
*/
typedef thread_t *osThreadId;
/**
* @brief Type of pointer to timer control block.
*/
typedef struct os_timer_cb {
virtual_timer_t vt;
os_timer_type type;
os_ptimer ptimer;
void *argument;
uint32_t millisec;
} *osTimerId;
/**
* @brief Type of pointer to mutex control block.
*/
typedef binary_semaphore_t *osMutexId;
/**
* @brief Type of pointer to semaphore control block.
*/
typedef semaphore_t *osSemaphoreId;
/**
* @brief Type of pointer to memory pool control block.
*/
typedef memory_pool_t *osPoolId;
/**
* @brief Type of pointer to message queue control block.
*/
typedef struct mailbox *osMessageQId;
/**
* @brief Type of an event.
*/
typedef struct {
osStatus status;
union {
uint32_t v;
void *p;
int32_t signals;
} value;
union {
/* osMailQId mail_id;*/
osMessageQId message_id;
} def;
} osEvent;
/**
* @brief Type of a thread definition block.
*/
typedef struct os_thread_def {
os_pthread pthread;
osPriority tpriority;
uint32_t stacksize;
} osThreadDef_t;
/**
* @brief Type of a timer definition block.
*/
typedef struct os_timer_def {
os_ptimer ptimer;
} osTimerDef_t;
/**
* @brief Type of a mutex definition block.
*/
typedef struct os_mutex_def {
uint32_t dummy;
} osMutexDef_t;
/**
* @brief Type of a semaphore definition block.
*/
typedef struct os_semaphore_def {
uint32_t dummy;
} osSemaphoreDef_t;
/**
* @brief Type of a memory pool definition block.
*/
typedef struct os_pool_def {
uint32_t pool_sz;
uint32_t item_sz;
memory_pool_t *pool;
void *items;
} osPoolDef_t;
/**
* @brief Type of a message queue definition block.
*/
typedef struct os_messageQ_def {
uint32_t queue_sz;
uint32_t item_sz;
mailbox_t *mailbox;
void *items;
} osMessageQDef_t;
/*===========================================================================*/
/* Module macros. */
/*===========================================================================*/
/**
* @brief Convert a microseconds value to a RTOS kernel system timer value.
*/
#define osKernelSysTickMicroSec(microsec) (((uint64_t)microsec * \
(osKernelSysTickFrequency)) / \
1000000)
/**
* @brief Create a Thread definition.
*/
#if defined(osObjectsExternal)
#define osThreadDef(name, priority, instances, stacksz) \
extern const osThreadDef_t os_thread_def_##name
#else
#define osThreadDef(name, priority, stacksz) \
const osThreadDef_t os_thread_def_##name = { \
(name), \
(priority), \
(stacksz) \
}
#endif
/**
* @brief Access a Thread definition.
*/
#define osThread(name) &os_thread_def_##name
/**
* @brief Define a Timer object.
*/
#if defined(osObjectsExternal)
#define osTimerDef(name, function) \
extern const osTimerDef_t os_timer_def_##name
#else
#define osTimerDef(name, function) \
const osTimerDef_t os_timer_def_##name = { \
(function) \
}
#endif
/**
* @brief Access a Timer definition.
*/
#define osTimer(name) &os_timer_def_##name
/**
* @brief Define a Mutex.
*/
#if defined(osObjectsExternal)
#define osMutexDef(name) extern const osMutexDef_t os_mutex_def_##name
#else
#define osMutexDef(name) const osMutexDef_t os_mutex_def_##name = {0}
#endif
/**
* @brief Access a Mutex definition.
*/
#define osMutex(name) &os_mutex_def_##name
/**
* @brief Define a Semaphore.
*/
#if defined(osObjectsExternal)
#define osSemaphoreDef(name) \
extern const osSemaphoreDef_t os_semaphore_def_##name
#else // define the object
#define osSemaphoreDef(name) \
const osSemaphoreDef_t os_semaphore_def_##name = {0}
#endif
/**
* @brief Access a Semaphore definition.
*/
#define osSemaphore(name) &os_semaphore_def_##name
/**
* @brief Define a Memory Pool.
*/
#if defined(osObjectsExternal)
#define osPoolDef(name, no, type) \
extern const osPoolDef_t os_pool_def_##name
#else
#define osPoolDef(name, no, type) \
static const type os_pool_buf_##name[no]; \
static memory_pool_t os_pool_obj_##name; \
const osPoolDef_t os_pool_def_##name = { \
(no), \
sizeof (type), \
(void *)&os_pool_obj_##name, \
(void *)&os_pool_buf_##name[0] \
}
#endif
/**
* @brief Access a Memory Pool definition.
*/
#define osPool(name) &os_pool_def_##name
/**
* @brief Define a Message Queue.
*/
#if defined(osObjectsExternal)
#define osMessageQDef(name, queue_sz, type) \
extern const osMessageQDef_t os_messageQ_def_##name
#else
#define osMessageQDef(name, queue_sz, type) \
static const msg_t os_messageQ_buf_##name[queue_sz]; \
static mailbox_t os_messageQ_obj_##name; \
const osMessageQDef_t os_messageQ_def_##name = { \
(queue_sz), \
sizeof (type) \
(void *)&os_messageQ_obj_##name, \
(void *)&os_messageQ_buf_##name[0] \
}
#endif
/**
* @brief Access a Message Queue definition.
*/
#define osMessageQ(name) &os_messageQ_def_##name
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
extern int32_t cmsis_os_started;
#ifdef __cplusplus
extern "C" {
#endif
osStatus osKernelInitialize(void);
osStatus osKernelStart(void);
osThreadId osThreadCreate(const osThreadDef_t *thread_def, void *argument);
osStatus osThreadTerminate(osThreadId thread_id);
osStatus osThreadSetPriority(osThreadId thread_id, osPriority newprio);
/*osEvent osWait(uint32_t millisec);*/
osTimerId osTimerCreate(const osTimerDef_t *timer_def,
os_timer_type type,
void *argument);
osStatus osTimerStart(osTimerId timer_id, uint32_t millisec);
osStatus osTimerStop(osTimerId timer_id);
osStatus osTimerDelete(osTimerId timer_id);
int32_t osSignalSet(osThreadId thread_id, int32_t signals);
int32_t osSignalClear(osThreadId thread_id, int32_t signals);
osEvent osSignalWait(int32_t signals, uint32_t millisec);
osSemaphoreId osSemaphoreCreate(const osSemaphoreDef_t *semaphore_def,
int32_t count);
int32_t osSemaphoreWait(osSemaphoreId semaphore_id, uint32_t millisec);
osStatus osSemaphoreRelease(osSemaphoreId semaphore_id);
osStatus osSemaphoreDelete(osSemaphoreId semaphore_id);
osMutexId osMutexCreate(const osMutexDef_t *mutex_def);
osStatus osMutexWait(osMutexId mutex_id, uint32_t millisec);
osStatus osMutexRelease(osMutexId mutex_id);
osStatus osMutexDelete(osMutexId mutex_id);
osPoolId osPoolCreate(const osPoolDef_t *pool_def);
void *osPoolAlloc(osPoolId pool_id);
void *osPoolCAlloc(osPoolId pool_id);
osStatus osPoolFree(osPoolId pool_id, void *block);
osMessageQId osMessageCreate(const osMessageQDef_t *queue_def,
osThreadId thread_id);
osStatus osMessagePut(osMessageQId queue_id,
uint32_t info,
uint32_t millisec);
osEvent osMessageGet(osMessageQId queue_id,
uint32_t millisec);
#ifdef __cplusplus
}
#endif
/*===========================================================================*/
/* Module inline functions. */
/*===========================================================================*/
/**
* @brief To be or not to be.
*/
static inline int32_t osKernelRunning(void) {
return cmsis_os_started;
}
/**
* @brief System ticks since start.
*/
static inline uint32_t osKernelSysTick(void) {
return (uint32_t)chVTGetSystemTimeX();
}
/**
* @brief Returns the current thread.
*/
static inline osThreadId osThreadGetId(void) {
return (osThreadId)chThdGetSelfX();
}
/**
* @brief Thread time slice yield.
*/
static inline osStatus osThreadYield(void) {
chThdYield();
return osOK;
}
/**
* @brief Returns priority of a thread.
*/
static inline osPriority osThreadGetPriority(osThreadId thread_id) {
return thread_id->p_prio;
}
/**
* @brief Thread delay in milliseconds.
*/
static inline osStatus osDelay(uint32_t millisec) {
chThdSleepMilliseconds(millisec);
return osOK;
}
#endif /* _CMSIS_OS_H_ */
/** @} */

View File

@ -1,4 +0,0 @@
# List of the ChibiOS/RT CMSIS RTOS wrapper.
CMSISRTOSSRC = ${CHIBIOS}/os/rt/ports/ARMCMx/cmsis_os/cmsis_os.c
CMSISRTOSINC = ${CHIBIOS}/os/rt/ports/ARMCMx/cmsis_os

View File

@ -1,142 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file compilers/GCC/chcoreasm_v6m.s
* @brief ARMv6-M architecture port low level code.
*
* @addtogroup ARMCMx_GCC_CORE
* @{
*/
#if !defined(FALSE) || defined(__DOXYGEN__)
#define FALSE 0
#endif
#if !defined(TRUE) || defined(__DOXYGEN__)
#define TRUE 1
#endif
#define _FROM_ASM_
#include "chconf.h"
#include "chcore.h"
#if !defined(__DOXYGEN__)
.set CONTEXT_OFFSET, 12
.set SCB_ICSR, 0xE000ED04
.set ICSR_PENDSVSET, 0x10000000
.set ICSR_NMIPENDSET, 0x80000000
.cpu cortex-m0
.fpu softvfp
.thumb
.text
/*--------------------------------------------------------------------------*
* Performs a context switch between two threads.
*--------------------------------------------------------------------------*/
.thumb_func
.globl _port_switch
_port_switch:
push {r4, r5, r6, r7, lr}
mov r4, r8
mov r5, r9
mov r6, r10
mov r7, r11
push {r4, r5, r6, r7}
mov r3, sp
str r3, [r1, #CONTEXT_OFFSET]
ldr r3, [r0, #CONTEXT_OFFSET]
mov sp, r3
pop {r4, r5, r6, r7}
mov r8, r4
mov r9, r5
mov r10, r6
mov r11, r7
pop {r4, r5, r6, r7, pc}
/*--------------------------------------------------------------------------*
* Start a thread by invoking its work function.
*
* Threads execution starts here, the code leaves the system critical zone
* and then jumps into the thread function passed in register R4. The
* register R5 contains the thread parameter. The function chThdExit() is
* called on thread function return.
*--------------------------------------------------------------------------*/
.thumb_func
.globl _port_thread_start
_port_thread_start:
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_unlock
#endif
#if CH_DBG_STATISTICS
bl _stats_stop_measure_crit_thd
#endif
cpsie i
mov r0, r5
blx r4
movs r0, #0 /* MSG_OK */
bl chThdExit
/*--------------------------------------------------------------------------*
* Post-IRQ switch code.
*
* Exception handlers return here for context switching.
*--------------------------------------------------------------------------*/
.thumb_func
.globl _port_switch_from_isr
_port_switch_from_isr:
#if CH_DBG_STATISTICS
bl _stats_start_measure_crit_thd
#endif
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_lock
#endif
bl chSchDoReschedule
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_unlock
#endif
#if CH_DBG_STATISTICS
bl _stats_stop_measure_crit_thd
#endif
.globl _port_exit_from_isr
_port_exit_from_isr:
ldr r2, .L2
ldr r3, .L3
str r3, [r2, #0]
#if CORTEX_ALTERNATE_SWITCH
cpsie i
#endif
.L1: b .L1
.align 2
.L2: .word SCB_ICSR
#if CORTEX_ALTERNATE_SWITCH
.L3: .word ICSR_PENDSVSET
#else
.L3: .word ICSR_NMIPENDSET
#endif
#endif /* !defined(__DOXYGEN__) */
/** @} */

View File

@ -1,148 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file compilers/GCC/chcoreasm_v7m.s
* @brief ARMv7-M architecture port low level code.
*
* @addtogroup ARMCMx_GCC_CORE
* @{
*/
#if !defined(FALSE) || defined(__DOXYGEN__)
#define FALSE 0
#endif
#if !defined(TRUE) || defined(__DOXYGEN__)
#define TRUE 1
#endif
#define _FROM_ASM_
#include "chconf.h"
#include "chcore.h"
#if !defined(__DOXYGEN__)
.set CONTEXT_OFFSET, 12
.set SCB_ICSR, 0xE000ED04
.set ICSR_PENDSVSET, 0x10000000
.syntax unified
.cpu cortex-m4
#if CORTEX_USE_FPU
.fpu fpv4-sp-d16
#else
.fpu softvfp
#endif
.thumb
.text
/*--------------------------------------------------------------------------*
* Performs a context switch between two threads.
*--------------------------------------------------------------------------*/
.thumb_func
.globl _port_switch
_port_switch:
push {r4, r5, r6, r7, r8, r9, r10, r11, lr}
#if CORTEX_USE_FPU
vpush {s16-s31}
#endif
str sp, [r1, #CONTEXT_OFFSET]
#if (CORTEX_SIMPLIFIED_PRIORITY == FALSE) && \
((CORTEX_MODEL == 3) || (CORTEX_MODEL == 4))
/* Workaround for ARM errata 752419, only applied if
condition exists for it to be triggered.*/
ldr r3, [r0, #CONTEXT_OFFSET]
mov sp, r3
#else
ldr sp, [r0, #CONTEXT_OFFSET]
#endif
#if CORTEX_USE_FPU
vpop {s16-s31}
#endif
pop {r4, r5, r6, r7, r8, r9, r10, r11, pc}
/*--------------------------------------------------------------------------*
* Start a thread by invoking its work function.
*
* Threads execution starts here, the code leaves the system critical zone
* and then jumps into the thread function passed in register R4. The
* register R5 contains the thread parameter. The function chThdExit() is
* called on thread function return.
*--------------------------------------------------------------------------*/
.thumb_func
.globl _port_thread_start
_port_thread_start:
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_unlock
#endif
#if CH_DBG_STATISTICS
bl _stats_stop_measure_crit_thd
#endif
#if CORTEX_SIMPLIFIED_PRIORITY
cpsie i
#else
movs r3, #0 /* CORTEX_BASEPRI_DISABLED */
msr BASEPRI, r3
#endif
mov r0, r5
blx r4
movs r0, #0 /* MSG_OK */
bl chThdExit
/*--------------------------------------------------------------------------*
* Post-IRQ switch code.
*
* Exception handlers return here for context switching.
*--------------------------------------------------------------------------*/
.thumb_func
.globl _port_switch_from_isr
_port_switch_from_isr:
#if CH_DBG_STATISTICS
bl _stats_start_measure_crit_thd
#endif
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_lock
#endif
bl chSchDoReschedule
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_unlock
#endif
#if CH_DBG_STATISTICS
bl _stats_stop_measure_crit_thd
#endif
.globl _port_exit_from_isr
_port_exit_from_isr:
#if CORTEX_SIMPLIFIED_PRIORITY
movw r3, #:lower16:SCB_ICSR
movt r3, #:upper16:SCB_ICSR
mov r2, ICSR_PENDSVSET
str r2, [r3, #0]
cpsie i
#else /* !CORTEX_SIMPLIFIED_PRIORITY */
svc #0
#endif /* !CORTEX_SIMPLIFIED_PRIORITY */
.L1: b .L1
#endif /* !defined(__DOXYGEN__) */
/** @} */

View File

@ -1,98 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file ARMCMx/compilers/GCC/chtypes.h
* @brief ARM Cortex-Mx port system types.
*
* @addtogroup ARMCMx_GCC_CORE
* @{
*/
#ifndef _CHTYPES_H_
#define _CHTYPES_H_
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
/**
* @name Common constants
*/
/**
* @brief Generic 'false' boolean constant.
*/
#if !defined(FALSE) || defined(__DOXYGEN__)
#define FALSE 0
#endif
/**
* @brief Generic 'true' boolean constant.
*/
#if !defined(TRUE) || defined(__DOXYGEN__)
#define TRUE 1
#endif
/** @} */
/**
* @name Kernel types
* @{
*/
typedef uint32_t rtcnt_t; /**< Realtime counter. */
typedef uint64_t rttime_t; /**< Realtime accumulator. */
typedef uint32_t syssts_t; /**< System status word. */
typedef uint8_t tmode_t; /**< Thread flags. */
typedef uint8_t tstate_t; /**< Thread state. */
typedef uint8_t trefs_t; /**< Thread references counter. */
typedef uint8_t tslices_t; /**< Thread time slices counter.*/
typedef uint32_t tprio_t; /**< Thread priority. */
typedef int32_t msg_t; /**< Inter-thread message. */
typedef int32_t eventid_t; /**< Numeric event identifier. */
typedef uint32_t eventmask_t; /**< Mask of event identifiers. */
typedef uint32_t eventflags_t; /**< Mask of event flags. */
typedef int32_t cnt_t; /**< Generic signed counter. */
typedef uint32_t ucnt_t; /**< Generic unsigned counter. */
/** @} */
/**
* @brief ROM constant modifier.
* @note It is set to use the "const" keyword in this port.
*/
#define ROMCONST const
/**
* @brief Makes functions not inlineable.
* @note If the compiler does not support such attribute then the
* realtime counter precision could be degraded.
*/
#define NOINLINE __attribute__((noinline))
/**
* @brief Optimized thread function declaration macro.
*/
#define PORT_THD_FUNCTION(tname, arg) void tname(void *arg)
/**
* @brief Packed variable specifier.
*/
#define PACKED_VAR __attribute__((packed))
#endif /* _CHTYPES_H_ */
/** @} */

View File

@ -1,8 +0,0 @@
# List of the ChibiOS/RT Cortex-M0 STM32F0xx port files.
PORTSRC = $(CHIBIOS)/os/rt/ports/ARMCMx/chcore.c \
$(CHIBIOS)/os/rt/ports/ARMCMx/chcore_v6m.c
PORTASM = $(CHIBIOS)/os/rt/ports/ARMCMx/compilers/GCC/chcoreasm_v6m.s
PORTINC = $(CHIBIOS)/os/rt/ports/ARMCMx \
$(CHIBIOS)/os/rt/ports/ARMCMx/compilers/GCC

View File

@ -1,8 +0,0 @@
# List of the ChibiOS/RT ARMv7M generic port files.
PORTSRC = $(CHIBIOS)/os/rt/ports/ARMCMx/chcore.c \
$(CHIBIOS)/os/rt/ports/ARMCMx/chcore_v7m.c
PORTASM = $(CHIBIOS)/os/rt/ports/ARMCMx/compilers/GCC/chcoreasm_v7m.s
PORTINC = $(CHIBIOS)/os/rt/ports/ARMCMx \
$(CHIBIOS)/os/rt/ports/ARMCMx/compilers/GCC

View File

@ -1,142 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file compilers/IAR/chcoreasm_v6m.s
* @brief ARMv6-M architecture port low level code.
*
* @addtogroup ARMCMx_IAR_CORE
* @{
*/
#if !defined(FALSE) || defined(__DOXYGEN__)
#define FALSE 0
#endif
#if !defined(TRUE) || defined(__DOXYGEN__)
#define TRUE 1
#endif
#define _FROM_ASM_
#include "chconf.h"
#include "chcore.h"
#if !defined(__DOXYGEN__)
MODULE ?chcoreasm_v6m
AAPCS INTERWORK, VFP_COMPATIBLE
PRESERVE8
CONTEXT_OFFSET SET 12
SCB_ICSR SET 0xE000ED04
SECTION .text:CODE:NOROOT(2)
EXTERN chThdExit
EXTERN chSchDoReschedule
#if CH_DBG_STATISTICS
EXTERN _stats_start_measure_crit_thd
EXTERN _stats_stop_measure_crit_thd
#endif
#if CH_DBG_SYSTEM_STATE_CHECK
EXTERN _dbg_check_unlock
EXTERN _dbg_check_lock
#endif
THUMB
/*
* Performs a context switch between two threads.
*/
PUBLIC _port_switch
_port_switch:
push {r4, r5, r6, r7, lr}
mov r4, r8
mov r5, r9
mov r6, r10
mov r7, r11
push {r4, r5, r6, r7}
mov r3, sp
str r3, [r1, #CONTEXT_OFFSET]
ldr r3, [r0, #CONTEXT_OFFSET]
mov sp, r3
pop {r4, r5, r6, r7}
mov r8, r4
mov r9, r5
mov r10, r6
mov r11, r7
pop {r4, r5, r6, r7, pc}
/*
* Start a thread by invoking its work function.
* If the work function returns @p chThdExit() is automatically invoked.
*/
PUBLIC _port_thread_start
_port_thread_start:
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_unlock
#endif
#if CH_DBG_STATISTICS
bl _stats_stop_measure_crit_thd
#endif
cpsie i
mov r0, r5
blx r4
bl chThdExit
/*
* Post-IRQ switch code.
* Exception handlers return here for context switching.
*/
PUBLIC _port_switch_from_isr
PUBLIC _port_exit_from_isr
_port_switch_from_isr:
#if CH_DBG_STATISTICS
bl _stats_start_measure_crit_thd
#endif
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_lock
#endif
bl chSchDoReschedule
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_unlock
#endif
#if CH_DBG_STATISTICS
bl _stats_stop_measure_crit_thd
#endif
_port_exit_from_isr:
ldr r2, =SCB_ICSR
movs r3, #128
#if CORTEX_ALTERNATE_SWITCH
lsls r3, r3, #21
str r3, [r2, #0]
cpsie i
#else
lsls r3, r3, #24
str r3, [r2, #0]
#endif
waithere:
b waithere
END
#endif /* !defined(__DOXYGEN__) */
/** @} */

View File

@ -1,150 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file compilers/IAR/chcoreasm_v7m.s
* @brief ARMv7-M architecture port low level code.
*
* @addtogroup ARMCMx_IAR_CORE
* @{
*/
#if !defined(FALSE) || defined(__DOXYGEN__)
#define FALSE 0
#endif
#if !defined(TRUE) || defined(__DOXYGEN__)
#define TRUE 1
#endif
#define _FROM_ASM_
#include "chconf.h"
#include "chcore.h"
#if !defined(__DOXYGEN__)
MODULE ?chcoreasm_v7m
AAPCS INTERWORK, VFP_COMPATIBLE
PRESERVE8
CONTEXT_OFFSET SET 12
SCB_ICSR SET 0xE000ED04
ICSR_PENDSVSET SET 0x10000000
SECTION .text:CODE:NOROOT(2)
EXTERN chThdExit
EXTERN chSchDoReschedule
#if CH_DBG_STATISTICS
EXTERN _stats_start_measure_crit_thd
EXTERN _stats_stop_measure_crit_thd
#endif
#if CH_DBG_SYSTEM_STATE_CHECK
EXTERN _dbg_check_unlock
EXTERN _dbg_check_lock
#endif
THUMB
/*
* Performs a context switch between two threads.
*/
PUBLIC _port_switch
_port_switch:
push {r4, r5, r6, r7, r8, r9, r10, r11, lr}
#if CORTEX_USE_FPU
vpush {s16-s31}
#endif
str sp, [r1, #CONTEXT_OFFSET]
#if (CORTEX_SIMPLIFIED_PRIORITY == FALSE) && \
((CORTEX_MODEL == 3) || (CORTEX_MODEL == 4))
/* Workaround for ARM errata 752419, only applied if
condition exists for it to be triggered.*/
ldr r3, [r0, #CONTEXT_OFFSET]
mov sp, r3
#else
ldr sp, [r0, #CONTEXT_OFFSET]
#endif
#if CORTEX_USE_FPU
vpop {s16-s31}
#endif
pop {r4, r5, r6, r7, r8, r9, r10, r11, pc}
/*
* Start a thread by invoking its work function.
* If the work function returns @p chThdExit() is automatically invoked.
*/
PUBLIC _port_thread_start
_port_thread_start:
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_unlock
#endif
#if CH_DBG_STATISTICS
bl _stats_stop_measure_crit_thd
#endif
#if CORTEX_SIMPLIFIED_PRIORITY
cpsie i
#else
movs r3, #0 /* CORTEX_BASEPRI_DISABLED */
msr BASEPRI, r3
#endif
mov r0, r5
blx r4
bl chThdExit
/*
* Post-IRQ switch code.
* Exception handlers return here for context switching.
*/
PUBLIC _port_switch_from_isr
PUBLIC _port_exit_from_isr
_port_switch_from_isr:
#if CH_DBG_STATISTICS
bl _stats_start_measure_crit_thd
#endif
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_lock
#endif
bl chSchDoReschedule
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_unlock
#endif
#if CH_DBG_STATISTICS
bl _stats_stop_measure_crit_thd
#endif
_port_exit_from_isr:
#if CORTEX_SIMPLIFIED_PRIORITY
mov r3, #LWRD SCB_ICSR
movt r3, #HWRD SCB_ICSR
mov r2, #ICSR_PENDSVSET
str r2, [r3]
cpsie i
#else
svc #0
#endif
.L3: b .L3
END
#endif /* !defined(__DOXYGEN__) */
/** @} */

View File

@ -1,98 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file ARMCMx/compilers/IAR/chtypes.h
* @brief ARM Cortex-Mx port system types.
*
* @addtogroup ARMCMx_IAR_CORE
* @{
*/
#ifndef _CHTYPES_H_
#define _CHTYPES_H_
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
/**
* @name Common constants
*/
/**
* @brief Generic 'false' boolean constant.
*/
#if !defined(FALSE) || defined(__DOXYGEN__)
#define FALSE 0
#endif
/**
* @brief Generic 'true' boolean constant.
*/
#if !defined(TRUE) || defined(__DOXYGEN__)
#define TRUE (!FALSE)
#endif
/** @} */
/**
* @name Kernel types
* @{
*/
typedef uint32_t rtcnt_t; /**< Realtime counter. */
typedef uint64_t rttime_t; /**< Realtime accumulator. */
typedef uint32_t syssts_t; /**< System status word. */
typedef uint8_t tmode_t; /**< Thread flags. */
typedef uint8_t tstate_t; /**< Thread state. */
typedef uint8_t trefs_t; /**< Thread references counter. */
typedef uint8_t tslices_t; /**< Thread time slices counter.*/
typedef uint32_t tprio_t; /**< Thread priority. */
typedef int32_t msg_t; /**< Inter-thread message. */
typedef int32_t eventid_t; /**< Numeric event identifier. */
typedef uint32_t eventmask_t; /**< Mask of event identifiers. */
typedef uint32_t eventflags_t; /**< Mask of event flags. */
typedef int32_t cnt_t; /**< Generic signed counter. */
typedef uint32_t ucnt_t; /**< Generic unsigned counter. */
/** @} */
/**
* @brief ROM constant modifier.
* @note It is set to use the "const" keyword in this port.
*/
#define ROMCONST const
/**
* @brief Makes functions not inlineable.
* @note If the compiler does not support such attribute then the
* realtime counter precision could be degraded.
*/
#define NOINLINE
/**
* @brief Optimized thread function declaration macro.
*/
#define PORT_THD_FUNCTION(tname, arg) void tname(void *arg)
/**
* @brief Packed variable specifier.
*/
#define PACKED_VAR __packed
#endif /* _CHTYPES_H_ */
/** @} */

View File

@ -1,139 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file compilers/RVCT/chcoreasm_v6m.s
* @brief ARMv6-M architecture port low level code.
*
* @addtogroup ARMCMx_RVCT_CORE
* @{
*/
#if !defined(FALSE) || defined(__DOXYGEN__)
#define FALSE 0
#endif
#if !defined(TRUE) || defined(__DOXYGEN__)
#define TRUE 1
#endif
#define _FROM_ASM_
#include "chconf.h"
#include "chcore.h"
#if !defined(__DOXYGEN__)
CONTEXT_OFFSET EQU 12
SCB_ICSR EQU 0xE000ED04
PRESERVE8
THUMB
AREA |.text|, CODE, READONLY
IMPORT chThdExit
IMPORT chSchDoReschedule
#if CH_DBG_STATISTICS
IMPORT _stats_start_measure_crit_thd
IMPORT _stats_stop_measure_crit_thd
#endif
#if CH_DBG_SYSTEM_STATE_CHECK
IMPORT _dbg_check_unlock
IMPORT _dbg_check_lock
#endif
/*
* Performs a context switch between two threads.
*/
EXPORT _port_switch
_port_switch PROC
push {r4, r5, r6, r7, lr}
mov r4, r8
mov r5, r9
mov r6, r10
mov r7, r11
push {r4, r5, r6, r7}
mov r3, sp
str r3, [r1, #CONTEXT_OFFSET]
ldr r3, [r0, #CONTEXT_OFFSET]
mov sp, r3
pop {r4, r5, r6, r7}
mov r8, r4
mov r9, r5
mov r10, r6
mov r11, r7
pop {r4, r5, r6, r7, pc}
ENDP
/*
* Start a thread by invoking its work function.
* If the work function returns @p chThdExit() is automatically invoked.
*/
EXPORT _port_thread_start
_port_thread_start PROC
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_unlock
#endif
#if CH_DBG_STATISTICS
bl _stats_stop_measure_crit_thd
#endif
cpsie i
mov r0, r5
blx r4
bl chThdExit
ENDP
/*
* Post-IRQ switch code.
* Exception handlers return here for context switching.
*/
EXPORT _port_switch_from_isr
EXPORT _port_exit_from_isr
_port_switch_from_isr PROC
#if CH_DBG_STATISTICS
bl _stats_start_measure_crit_thd
#endif
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_lock
#endif
bl chSchDoReschedule
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_unlock
#endif
#if CH_DBG_STATISTICS
bl _stats_stop_measure_crit_thd
#endif
_port_exit_from_isr
ldr r2, =SCB_ICSR
movs r3, #128
#if CORTEX_ALTERNATE_SWITCH
lsls r3, r3, #21
str r3, [r2, #0]
cpsie i
#else
lsls r3, r3, #24
str r3, [r2, #0]
#endif
waithere b waithere
ENDP
END
#endif /* !defined(__DOXYGEN__) */
/** @} */

View File

@ -1,148 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file compilers/RVCT/chcoreasm_v7m.s
* @brief ARMv7-M architecture port low level code.
*
* @addtogroup ARMCMx_RVCT_CORE
* @{
*/
#if !defined(FALSE) || defined(__DOXYGEN__)
#define FALSE 0
#endif
#if !defined(TRUE) || defined(__DOXYGEN__)
#define TRUE 1
#endif
#define _FROM_ASM_
#include "chconf.h"
#include "chcore.h"
#if !defined(__DOXYGEN__)
CONTEXT_OFFSET EQU 12
SCB_ICSR EQU 0xE000ED04
ICSR_PENDSVSET EQU 0x10000000
PRESERVE8
THUMB
AREA |.text|, CODE, READONLY
IMPORT chThdExit
IMPORT chSchDoReschedule
#if CH_DBG_STATISTICS
IMPORT _stats_start_measure_crit_thd
IMPORT _stats_stop_measure_crit_thd
#endif
#if CH_DBG_SYSTEM_STATE_CHECK
IMPORT _dbg_check_unlock
IMPORT _dbg_check_lock
#endif
/*
* Performs a context switch between two threads.
*/
EXPORT _port_switch
_port_switch PROC
push {r4, r5, r6, r7, r8, r9, r10, r11, lr}
#if CORTEX_USE_FPU
vpush {s16-s31}
#endif
str sp, [r1, #CONTEXT_OFFSET]
#if (CORTEX_SIMPLIFIED_PRIORITY == FALSE) && \
((CORTEX_MODEL == 3) || (CORTEX_MODEL == 4))
/* Workaround for ARM errata 752419, only applied if
condition exists for it to be triggered.*/
ldr r3, [r0, #CONTEXT_OFFSET]
mov sp, r3
#else
ldr sp, [r0, #CONTEXT_OFFSET]
#endif
#if CORTEX_USE_FPU
vpop {s16-s31}
#endif
pop {r4, r5, r6, r7, r8, r9, r10, r11, pc}
ENDP
/*
* Start a thread by invoking its work function.
* If the work function returns @p chThdExit() is automatically invoked.
*/
EXPORT _port_thread_start
_port_thread_start PROC
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_unlock
#endif
#if CH_DBG_STATISTICS
bl _stats_stop_measure_crit_thd
#endif
#if CORTEX_SIMPLIFIED_PRIORITY
cpsie i
#else
movs r3, #0 /* CORTEX_BASEPRI_DISABLED */
msr BASEPRI, r3
#endif
mov r0, r5
blx r4
bl chThdExit
ENDP
/*
* Post-IRQ switch code.
* Exception handlers return here for context switching.
*/
EXPORT _port_switch_from_isr
EXPORT _port_exit_from_isr
_port_switch_from_isr PROC
#if CH_DBG_STATISTICS
bl _stats_start_measure_crit_thd
#endif
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_lock
#endif
bl chSchDoReschedule
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_unlock
#endif
#if CH_DBG_STATISTICS
bl _stats_stop_measure_crit_thd
#endif
_port_exit_from_isr
#if CORTEX_SIMPLIFIED_PRIORITY
mov r3, #SCB_ICSR :AND: 0xFFFF
movt r3, #SCB_ICSR :SHR: 16
mov r2, #ICSR_PENDSVSET
str r2, [r3, #0]
cpsie i
#else
svc #0
#endif
waithere b waithere
ENDP
END
#endif /* !defined(__DOXYGEN__) */
/** @} */

View File

@ -1,98 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file ARMCMx/compilers/RVCT/chtypes.h
* @brief ARM Cortex-Mx port system types.
*
* @addtogroup ARMCMx_RVCT_CORE
* @{
*/
#ifndef _CHTYPES_H_
#define _CHTYPES_H_
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
/**
* @name Common constants
*/
/**
* @brief Generic 'false' boolean constant.
*/
#if !defined(FALSE) || defined(__DOXYGEN__)
#define FALSE 0
#endif
/**
* @brief Generic 'true' boolean constant.
*/
#if !defined(TRUE) || defined(__DOXYGEN__)
#define TRUE (!FALSE)
#endif
/** @} */
/**
* @name Kernel types
* @{
*/
typedef uint32_t rtcnt_t; /**< Realtime counter. */
typedef uint64_t rttime_t; /**< Realtime accumulator. */
typedef uint32_t syssts_t; /**< System status word. */
typedef uint8_t tmode_t; /**< Thread flags. */
typedef uint8_t tstate_t; /**< Thread state. */
typedef uint8_t trefs_t; /**< Thread references counter. */
typedef uint8_t tslices_t; /**< Thread time slices counter.*/
typedef uint32_t tprio_t; /**< Thread priority. */
typedef int32_t msg_t; /**< Inter-thread message. */
typedef int32_t eventid_t; /**< Numeric event identifier. */
typedef uint32_t eventmask_t; /**< Mask of event identifiers. */
typedef uint32_t eventflags_t; /**< Mask of event flags. */
typedef int32_t cnt_t; /**< Generic signed counter. */
typedef uint32_t ucnt_t; /**< Generic unsigned counter. */
/** @} */
/**
* @brief ROM constant modifier.
* @note It is set to use the "const" keyword in this port.
*/
#define ROMCONST const
/**
* @brief Makes functions not inlineable.
* @note If the compiler does not support such attribute then the
* realtime counter precision could be degraded.
*/
#define NOINLINE
/**
* @brief Optimized thread function declaration macro.
*/
#define PORT_THD_FUNCTION(tname, arg) void tname(void *arg)
/**
* @brief Packed variable specifier.
*/
#define PACKED_VAR __packed
#endif /* _CHTYPES_H_ */
/** @} */

View File

@ -1,132 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file AVR/chcore.c
* @brief AVR architecture port code.
*
* @addtogroup AVR_CORE
* @{
*/
#include "ch.h"
/**
* @brief Performs a context switch between two threads.
* @details This is the most critical code in any port, this function
* is responsible for the context switch between 2 threads.
* @note The implementation of this code affects <b>directly</b> the context
* switch performance so optimize here as much as you can.
* @note The function is declared as a weak symbol, it is possible to
* redefine it in your application code.
*
* @param[in] ntp the thread to be switched in
* @param[in] otp the thread to be switched out
*/
#if !defined(__DOXYGEN__)
__attribute__((naked, weak))
#endif
void port_switch(thread_t *ntp, thread_t *otp) {
asm volatile ("push r2");
asm volatile ("push r3");
asm volatile ("push r4");
asm volatile ("push r5");
asm volatile ("push r6");
asm volatile ("push r7");
asm volatile ("push r8");
asm volatile ("push r9");
asm volatile ("push r10");
asm volatile ("push r11");
asm volatile ("push r12");
asm volatile ("push r13");
asm volatile ("push r14");
asm volatile ("push r15");
asm volatile ("push r16");
asm volatile ("push r17");
asm volatile ("push r28");
asm volatile ("push r29");
asm volatile ("movw r30, r22");
asm volatile ("in r0, 0x3d");
asm volatile ("std Z+5, r0");
asm volatile ("in r0, 0x3e");
asm volatile ("std Z+6, r0");
asm volatile ("movw r30, r24");
asm volatile ("ldd r0, Z+5");
asm volatile ("out 0x3d, r0");
asm volatile ("ldd r0, Z+6");
asm volatile ("out 0x3e, r0");
asm volatile ("pop r29");
asm volatile ("pop r28");
asm volatile ("pop r17");
asm volatile ("pop r16");
asm volatile ("pop r15");
asm volatile ("pop r14");
asm volatile ("pop r13");
asm volatile ("pop r12");
asm volatile ("pop r11");
asm volatile ("pop r10");
asm volatile ("pop r9");
asm volatile ("pop r8");
asm volatile ("pop r7");
asm volatile ("pop r6");
asm volatile ("pop r5");
asm volatile ("pop r4");
asm volatile ("pop r3");
asm volatile ("pop r2");
asm volatile ("ret");
}
/**
* @brief Halts the system.
* @details This function is invoked by the operating system when an
* unrecoverable error is detected (for example because a programming
* error in the application code that triggers an assertion while in
* debug mode).
* @note The function is declared as a weak symbol, it is possible to
* redefine it in your application code.
*/
#if !defined(__DOXYGEN__)
__attribute__((weak))
#endif
void port_halt(void) {
port_disable();
while (TRUE) {
}
}
/**
* @brief Start a thread by invoking its work function.
* @details If the work function returns @p chThdExit() is automatically
* invoked.
*/
void _port_thread_start(void) {
chSysUnlock();
asm volatile ("movw r24, r4");
asm volatile ("movw r30, r2");
asm volatile ("icall");
asm volatile ("call chThdExit");
}
/** @} */

View File

@ -1,390 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file AVR/chcore.h
* @brief AVR architecture port macros and structures.
*
* @addtogroup AVR_CORE
* @{
*/
#ifndef _CHCORE_H_
#define _CHCORE_H_
#include <avr/io.h>
#include <avr/interrupt.h>
#if CH_DBG_ENABLE_STACK_CHECK
#error "option CH_DBG_ENABLE_STACK_CHECK not supported by this port"
#endif
/**
* @brief If enabled allows the idle thread to enter a low power mode.
*/
#ifndef ENABLE_WFI_IDLE
#define ENABLE_WFI_IDLE 0
#endif
/**
* @brief Macro defining the AVR architecture.
*/
#define PORT_ARCHITECTURE_AVR
/**
* @brief Name of the implemented architecture.
*/
#define PORT_ARCHITECTURE_NAME "AVR"
/**
* @brief Name of the architecture variant (optional).
*/
#define PORT_CORE_VARIANT_NAME "MegaAVR"
/**
* @brief Name of the compiler supported by this port.
*/
#define PORT_COMPILER_NAME "GCC " __VERSION__
/**
* @brief Port-specific information string.
*/
#define PORT_INFO "None"
/**
* @brief This port supports a realtime counter.
*/
#define PORT_SUPPORTS_RT FALSE
/**
* @brief 8 bits stack and memory alignment enforcement.
*/
typedef uint8_t stkalign_t;
/**
* @brief Interrupt saved context.
* @details This structure represents the stack frame saved during a
* preemption-capable interrupt handler.
* @note The field @p _next is not part of the context, it represents the
* offset of the structure relative to the stack pointer.
*/
struct port_extctx {
uint8_t _next;
uint8_t r31;
uint8_t r30;
uint8_t r27;
uint8_t r26;
uint8_t r25;
uint8_t r24;
uint8_t r23;
uint8_t r22;
uint8_t r21;
uint8_t r20;
uint8_t r19;
uint8_t r18;
uint8_t sr;
uint8_t r1;
uint8_t r0;
#ifdef __AVR_3_BYTE_PC__
uint8_t pcx;
#endif
uint16_t pc;
};
/**
* @brief System saved context.
* @details This structure represents the inner stack frame during a context
* switching.
* @note The field @p _next is not part of the context, it represents the
* offset of the structure relative to the stack pointer.
*/
struct port_intctx {
uint8_t _next;
uint8_t r29;
uint8_t r28;
uint8_t r17;
uint8_t r16;
uint8_t r15;
uint8_t r14;
uint8_t r13;
uint8_t r12;
uint8_t r11;
uint8_t r10;
uint8_t r9;
uint8_t r8;
uint8_t r7;
uint8_t r6;
uint8_t r5;
uint8_t r4;
uint8_t r3;
uint8_t r2;
#ifdef __AVR_3_BYTE_PC__
uint8_t pcx;
#endif
uint8_t pcl;
uint8_t pch;
};
/**
* @brief Platform dependent part of the @p thread_t structure.
* @details In the AVR port this structure just holds a pointer to the
* @p port_intctx structure representing the stack pointer at the time
* of the context switch.
*/
struct context {
struct port_intctx *sp;
};
/**
* @brief Platform dependent part of the @p chThdCreateI() API.
* @details This code usually setup the context switching frame represented
* by an @p port_intctx structure.
*/
#ifdef __AVR_3_BYTE_PC__
#define PORT_SETUP_CONTEXT(tp, workspace, wsize, pf, arg) { \
tp->p_ctx.sp = (struct port_intctx*)((uint8_t *)workspace + wsize - \
sizeof(struct port_intctx)); \
tp->p_ctx.sp->r2 = (int)pf; \
tp->p_ctx.sp->r3 = (int)pf >> 8; \
tp->p_ctx.sp->r4 = (int)arg; \
tp->p_ctx.sp->r5 = (int)arg >> 8; \
tp->p_ctx.sp->pcx = (int)0; \
tp->p_ctx.sp->pcl = (int)_port_thread_start >> 8; \
tp->p_ctx.sp->pch = (int)_port_thread_start; \
}
#else /* __AVR_3_BYTE_PC__ */
#define PORT_SETUP_CONTEXT(tp, workspace, wsize, pf, arg) { \
tp->p_ctx.sp = (struct port_intctx*)((uint8_t *)workspace + wsize - \
sizeof(struct port_intctx)); \
tp->p_ctx.sp->r2 = (int)pf; \
tp->p_ctx.sp->r3 = (int)pf >> 8; \
tp->p_ctx.sp->r4 = (int)arg; \
tp->p_ctx.sp->r5 = (int)arg >> 8; \
tp->p_ctx.sp->pcl = (int)_port_thread_start >> 8; \
tp->p_ctx.sp->pch = (int)_port_thread_start; \
}
#endif /* __AVR_3_BYTE_PC__ */
/**
* @brief Stack size for the system idle thread.
* @details This size depends on the idle thread implementation, usually
* the idle thread should take no more space than those reserved
* by @p PORT_INT_REQUIRED_STACK.
* @note In this port it is set to 8.
*/
#if !defined(PORT_IDLE_THREAD_STACK_SIZE) || defined(__DOXYGEN__)
#define PORT_IDLE_THREAD_STACK_SIZE 8
#endif
/**
* @brief Per-thread stack overhead for interrupts servicing.
* @details This constant is used in the calculation of the correct working
* area size.
* This value can be zero on those architecture where there is a
* separate interrupt stack and the stack space between @p port_intctx
* and @p port_extctx is known to be zero.
* @note In this port the default is 32 bytes per thread.
*/
#if !defined(PORT_INT_REQUIRED_STACK) || defined(__DOXYGEN__)
#define PORT_INT_REQUIRED_STACK 32
#endif
/**
* @brief Enforces a correct alignment for a stack area size value.
*/
#define STACK_ALIGN(n) ((((n) - 1) | (sizeof(stkalign_t) - 1)) + 1)
/**
* @brief Computes the thread working area global size.
*/
#define PORT_WA_SIZE(n) STACK_ALIGN(sizeof(thread_t) + \
(sizeof(struct port_intctx) - 1) + \
(sizeof(struct port_extctx) - 1) + \
(n) + (PORT_INT_REQUIRED_STACK))
/**
* @brief Static working area allocation.
* @details This macro is used to allocate a static thread working area
* aligned as both position and size.
*/
#define WORKING_AREA(s, n) stkalign_t s[PORT_WA_SIZE(n) / sizeof(stkalign_t)]
/**
* @brief IRQ prologue code.
* @details This macro must be inserted at the start of all IRQ handlers
* enabled to invoke system APIs.
* @note This code tricks the compiler to save all the specified registers
* by "touching" them.
*/
#define PORT_IRQ_PROLOGUE() { \
asm ("" : : : "r18", "r19", "r20", "r21", "r22", "r23", "r24", \
"r25", "r26", "r27", "r30", "r31"); \
}
/**
* @brief IRQ epilogue code.
* @details This macro must be inserted at the end of all IRQ handlers
* enabled to invoke system APIs.
*/
#define PORT_IRQ_EPILOGUE() { \
_dbg_check_lock(); \
if (chSchIsPreemptionRequired()) \
chSchDoReschedule(); \
_dbg_check_unlock(); \
}
/**
* @brief IRQ handler function declaration.
* @note @p id can be a function name or a vector number depending on the
* port implementation.
*/
#define PORT_IRQ_HANDLER(id) ISR(id)
/**
* @brief Port-related initialization code.
* @note This function is empty in this port.
*/
#define port_init()
/**
* @brief Returns a word encoding the current interrupts status.
*
* @return The interrupts status.
*/
static inline syssts_t port_get_irq_status(void) {
return SREG;
}
/**
* @brief Checks the interrupt status.
*
* @param[in] sts the interrupt status word
*
* @return The interrupt status.
* @retvel false the word specified a disabled interrupts status.
* @retvel true the word specified an enabled interrupts status.
*/
static inline bool port_irq_enabled(syssts_t sts) {
return (bool)((sts & 0x80) != 0);
}
/**
* @brief Determines the current execution context.
*
* @return The execution context.
* @retval false not running in ISR mode.
* @retval true running in ISR mode.
*/
static inline bool port_is_isr_context(void) {
//TODO: is there any way to determine this?
return false;
}
/**
* @brief Kernel-lock action.
* @details Usually this function just disables interrupts but may perform more
* actions.
* @note Implemented as global interrupt disable.
*/
#define port_lock() asm volatile ("cli" : : : "memory")
/**
* @brief Kernel-unlock action.
* @details Usually this function just enables interrupts but may perform more
* actions.
* @note Implemented as global interrupt enable.
*/
#define port_unlock() asm volatile ("sei" : : : "memory")
/**
* @brief Kernel-lock action from an interrupt handler.
* @details This function is invoked before invoking I-class APIs from
* interrupt handlers. The implementation is architecture dependent,
* in its simplest form it is void.
* @note This function is empty in this port.
*/
#define port_lock_from_isr()
/**
* @brief Kernel-unlock action from an interrupt handler.
* @details This function is invoked after invoking I-class APIs from interrupt
* handlers. The implementation is architecture dependent, in its
* simplest form it is void.
* @note This function is empty in this port.
*/
#define port_unlock_from_isr()
/**
* @brief Disables all the interrupt sources.
* @note Of course non-maskable interrupt sources are not included.
* @note Implemented as global interrupt disable.
*/
#define port_disable() asm volatile ("cli" : : : "memory")
/**
* @brief Disables the interrupt sources below kernel-level priority.
* @note Interrupt sources above kernel level remains enabled.
* @note Same as @p port_disable() in this port, there is no difference
* between the two states.
*/
#define port_suspend() asm volatile ("cli" : : : "memory")
/**
* @brief Enables all the interrupt sources.
* @note Implemented as global interrupt enable.
*/
#define port_enable() asm volatile ("sei" : : : "memory")
/**
* @brief Enters an architecture-dependent IRQ-waiting mode.
* @details The function is meant to return when an interrupt becomes pending.
* The simplest implementation is an empty function or macro but this
* would not take advantage of architecture-specific power saving
* modes.
* @note This port function is implemented as inlined code for performance
* reasons.
*/
#if ENABLE_WFI_IDLE != 0
#define port_wait_for_interrupt() { \
asm volatile ("sleep" : : : "memory"); \
}
#else
#define port_wait_for_interrupt()
#endif
#ifdef __cplusplus
extern "C" {
#endif
void port_switch(thread_t *ntp, thread_t *otp);
void port_halt(void);
void _port_thread_start(void);
#ifdef __cplusplus
}
#endif
#if CH_CFG_ST_TIMEDELTA > 0
#include "chcore_timer.h"
#endif
#endif /* _CHCORE_H_ */
/** @} */

View File

@ -1,124 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file AVR/chcore_timer.h
* @brief System timer header file.
*
* @addtogroup AVR_TIMER
* @{
*/
#ifndef _CHCORE_TIMER_H_
#define _CHCORE_TIMER_H_
/* This is the only header in the HAL designed to be include-able alone.*/
#include "st.h"
/*===========================================================================*/
/* Module constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Module pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Module data structures and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
/*===========================================================================*/
/* Module inline functions. */
/*===========================================================================*/
/**
* @brief Starts the alarm.
* @note Makes sure that no spurious alarms are triggered after
* this call.
*
* @param[in] time the time to be set for the first alarm
*
* @notapi
*/
static inline void port_timer_start_alarm(systime_t time) {
stStartAlarm(time);
}
/**
* @brief Stops the alarm interrupt.
*
* @notapi
*/
static inline void port_timer_stop_alarm(void) {
stStopAlarm();
}
/**
* @brief Sets the alarm time.
*
* @param[in] time the time to be set for the next alarm
*
* @notapi
*/
static inline void port_timer_set_alarm(systime_t time) {
stSetAlarm(time);
}
/**
* @brief Returns the system time.
*
* @return The system time.
*
* @notapi
*/
static inline systime_t port_timer_get_time(void) {
return stGetCounter();
}
/**
* @brief Returns the current alarm time.
*
* @return The currently set alarm time.
*
* @notapi
*/
static inline systime_t port_timer_get_alarm(void) {
return stGetAlarm();
}
#endif /* _CHCORE_TIMER_H_ */
/** @} */

View File

@ -1,91 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file AVR/compilers/GCC/chtypes.h
* @brief AVR architecture port system types.
*
* @addtogroup AVR_CORE
* @{
*/
#ifndef _CHTYPES_H_
#define _CHTYPES_H_
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
/**
* @name Common constants
*/
/**
* @brief Generic 'false' boolean constant.
*/
#if !defined(FALSE) || defined(__DOXYGEN__)
#define FALSE 0
#endif
/**
* @brief Generic 'true' boolean constant.
*/
#if !defined(TRUE) || defined(__DOXYGEN__)
#define TRUE (!FALSE)
#endif
/** @} */
typedef bool bool_t; /**< Fast boolean type. */
typedef uint8_t syssts_t; /**< System status word. */
typedef uint8_t tmode_t; /**< Thread flags. */
typedef uint8_t tstate_t; /**< Thread state. */
typedef uint8_t trefs_t; /**< Thread references counter. */
typedef uint8_t tslices_t; /**< Thread time slices counter. */
typedef uint8_t tprio_t; /**< Thread priority. */
typedef int16_t msg_t; /**< Inter-thread message. */
typedef uint8_t eventid_t; /**< Event Id. */
typedef uint8_t eventmask_t; /**< Event mask. */
typedef uint8_t eventflags_t; /**< Event flags. */
typedef int8_t cnt_t; /**< Resources counter. */
/**
* @brief ROM constant modifier.
* @note It is set to use the "const" keyword in this port.
*/
#define ROMCONST const
/**
* @brief Makes functions not inlineable.
* @note If the compiler does not support such attribute then the
* realtime counter precision could be degraded.
*/
#define NOINLINE __attribute__((noinline))
/**
* @brief Optimized thread function declaration macro.
*/
#define PORT_THD_FUNCTION(tname, arg) void tname(void *arg)
/**
* @brief Packed variable specifier.
*/
#define PACKED_VAR __attribute__((packed))
#endif /* _CHTYPES_H_ */
/** @} */

View File

@ -1,7 +0,0 @@
# List of the ChibiOS/RT AVR port files.
PORTSRC = ${CHIBIOS}/os/rt/ports/AVR/chcore.c
PORTASM =
PORTINC = ${CHIBIOS}/os/rt/ports/AVR \
${CHIBIOS}/os/rt/ports/AVR/compilers/GCC

View File

@ -1,120 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file SIMIA32/chcore.c
* @brief Simulator on IA32 port code.
*
* @addtogroup SIMIA32_GCC_CORE
* @{
*/
#include <windows.h>
#include "ch.h"
/*===========================================================================*/
/* Module local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported variables. */
/*===========================================================================*/
bool port_isr_context_flag;
syssts_t port_irq_sts;
/*===========================================================================*/
/* Module local types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported functions. */
/*===========================================================================*/
/**
* Performs a context switch between two threads.
* @param otp the thread to be switched out
* @param ntp the thread to be switched in
*/
__attribute__((used))
static void __dummy(thread_t *ntp, thread_t *otp) {
(void)ntp; (void)otp;
asm volatile (
#if defined(WIN32)
".globl @port_switch@8 \n\t"
"@port_switch@8:"
#elif defined(__APPLE__)
".globl _port_switch \n\t"
"_port_switch:"
#else
".globl port_switch \n\t"
"port_switch:"
#endif
"push %ebp \n\t"
"push %esi \n\t"
"push %edi \n\t"
"push %ebx \n\t"
"movl %esp, 12(%edx) \n\t"
"movl 12(%ecx), %esp \n\t"
"pop %ebx \n\t"
"pop %edi \n\t"
"pop %esi \n\t"
"pop %ebp \n\t"
"ret");
}
/**
* @brief Start a thread by invoking its work function.
* @details If the work function returns @p chThdExit() is automatically
* invoked.
*/
__attribute__((cdecl, noreturn))
void _port_thread_start(msg_t (*pf)(void *), void *p) {
chSysUnlock();
pf(p);
chThdExit(0);
while(1);
}
/**
* @brief Returns the current value of the realtime counter.
*
* @return The realtime counter value.
*/
rtcnt_t port_rt_get_counter_value(void) {
LARGE_INTEGER n;
QueryPerformanceCounter(&n);
return (rtcnt_t)(n.QuadPart / 1000LL);
}
/** @} */

View File

@ -1,382 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file SIMIA32/chcore.h
* @brief Simulator on IA32 port macros and structures.
*
* @addtogroup SIMIA32_GCC_CORE
* @{
*/
#ifndef _CHCORE_H_
#define _CHCORE_H_
/*===========================================================================*/
/* Module constants. */
/*===========================================================================*/
/**
* Macro defining the a simulated architecture into x86.
*/
#define PORT_ARCHITECTURE_SIMIA32
/**
* Name of the implemented architecture.
*/
#define PORT_ARCHITECTURE_NAME "Simulator"
/**
* @brief Name of the architecture variant (optional).
*/
#define PORT_CORE_VARIANT_NAME "x86 (integer only)"
/**
* @brief Name of the compiler supported by this port.
*/
#define PORT_COMPILER_NAME "GCC " __VERSION__
/**
* @brief Port-specific information string.
*/
#define PORT_INFO "No preemption"
/**
* @brief This port supports a realtime counter.
*/
#define PORT_SUPPORTS_RT TRUE
/*===========================================================================*/
/* Module pre-compile time settings. */
/*===========================================================================*/
/**
* @brief Stack size for the system idle thread.
* @details This size depends on the idle thread implementation, usually
* the idle thread should take no more space than those reserved
* by @p PORT_INT_REQUIRED_STACK.
*/
#ifndef PORT_IDLE_THREAD_STACK_SIZE
#define PORT_IDLE_THREAD_STACK_SIZE 256
#endif
/**
* @brief Per-thread stack overhead for interrupts servicing.
* @details This constant is used in the calculation of the correct working
* area size.
*/
#ifndef PORT_INT_REQUIRED_STACK
#define PORT_INT_REQUIRED_STACK 16384
#endif
/**
* @brief Enables an alternative timer implementation.
* @details Usually the port uses a timer interface defined in the file
* @p chcore_timer.h, if this option is enabled then the file
* @p chcore_timer_alt.h is included instead.
*/
#if !defined(PORT_USE_ALT_TIMER)
#define PORT_USE_ALT_TIMER FALSE
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if CH_DBG_ENABLE_STACK_CHECK
#error "option CH_DBG_ENABLE_STACK_CHECK not supported by this port"
#endif
/*===========================================================================*/
/* Module data structures and types. */
/*===========================================================================*/
/**
* @brief 16 bytes stack and memory alignment enforcement.
*/
typedef struct {
uint8_t a[16];
} stkalign_t __attribute__((aligned(16)));
/**
* @brief Type of a generic x86 register.
*/
typedef void *regx86;
/**
* @brief Interrupt saved context.
* @details This structure represents the stack frame saved during a
* preemption-capable interrupt handler.
*/
struct port_extctx {
};
/**
* @brief System saved context.
* @details This structure represents the inner stack frame during a context
* switch.
*/
struct port_intctx {
regx86 ebx;
regx86 edi;
regx86 esi;
regx86 ebp;
regx86 eip;
};
/**
* @brief Platform dependent part of the @p thread_t structure.
* @details In this port the structure just holds a pointer to the
* @p port_intctx structure representing the stack pointer
* at context switch time.
*/
struct context {
struct port_intctx *esp;
};
/*===========================================================================*/
/* Module macros. */
/*===========================================================================*/
#define APUSH(p, a) do { \
(p) -= sizeof(void *); \
*(void **)(p) = (void*)(a); \
} while (false)
/* Darwin requires the stack to be aligned to a 16-byte boundary at
* the time of a call instruction (in case the called function needs
* to save MMX registers). This aligns to 'mod' module 16, so that we'll end
* up with the right alignment after pushing the args. */
#define AALIGN(p, mask, mod) \
p = (void *)((((uint32_t)(p) - (uint32_t)(mod)) & ~(uint32_t)(mask)) + (uint32_t)(mod)) \
/**
* @brief Platform dependent part of the @p chThdCreateI() API.
* @details This code usually setup the context switching frame represented
* by an @p port_intctx structure.
*/
#define PORT_SETUP_CONTEXT(tp, workspace, wsize, pf, arg) { \
/*lint -save -e611 -e9033 -e9074 -e9087 [10.8, 11.1, 11.3] Valid casts.*/ \
uint8_t *esp = (uint8_t *)workspace + wsize; \
APUSH(esp, 0); \
uint8_t *savebp = esp; \
AALIGN(esp, 15, 8); \
APUSH(esp, arg); \
APUSH(esp, pf); \
APUSH(esp, 0); \
esp -= sizeof(struct port_intctx); \
((struct port_intctx *)esp)->eip = (void *)_port_thread_start; \
((struct port_intctx *)esp)->ebx = NULL; \
((struct port_intctx *)esp)->edi = NULL; \
((struct port_intctx *)esp)->esi = NULL; \
((struct port_intctx *)esp)->ebp = (void *)savebp; \
(tp)->p_ctx.esp = (struct port_intctx *)esp; \
/*lint -restore*/ \
}
/**
* @brief Computes the thread working area global size.
* @note There is no need to perform alignments in this macro.
*/
#define PORT_WA_SIZE(n) ((sizeof(void *) * 4U) + \
sizeof(struct port_intctx) + \
((size_t)(n)) + \
((size_t)(PORT_INT_REQUIRED_STACK)))
/**
* @brief IRQ prologue code.
* @details This macro must be inserted at the start of all IRQ handlers
* enabled to invoke system APIs.
*/
#define PORT_IRQ_PROLOGUE() { \
port_isr_context_flag = true; \
}
/**
* @brief IRQ epilogue code.
* @details This macro must be inserted at the end of all IRQ handlers
* enabled to invoke system APIs.
*/
#define PORT_IRQ_EPILOGUE() { \
port_isr_context_flag = false; \
}
/**
* @brief IRQ handler function declaration.
* @note @p id can be a function name or a vector number depending on the
* port implementation.
*/
#define PORT_IRQ_HANDLER(id) void id(void)
/**
* @brief Fast IRQ handler function declaration.
* @note @p id can be a function name or a vector number depending on the
* port implementation.
*/
#define PORT_FAST_IRQ_HANDLER(id) void id(void)
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
extern bool port_isr_context_flag;
extern syssts_t port_irq_sts;
#ifdef __cplusplus
extern "C" {
#endif
/*lint -save -e950 [Dir-2.1] Non-ANSI keywords are fine in the port layer.*/
__attribute__((fastcall)) void port_switch(thread_t *ntp, thread_t *otp);
__attribute__((cdecl, noreturn)) void _port_thread_start(msg_t (*pf)(void *p),
void *p);
/*lint -restore*/
rtcnt_t port_rt_get_counter_value(void);
void _sim_check_for_interrupts(void);
#ifdef __cplusplus
}
#endif
/*===========================================================================*/
/* Module inline functions. */
/*===========================================================================*/
/**
* @brief Port-related initialization code.
*/
static inline void port_init(void) {
port_irq_sts = (syssts_t)0;
port_isr_context_flag = false;
}
/**
* @brief Returns a word encoding the current interrupts status.
*
* @return The interrupts status.
*/
static inline syssts_t port_get_irq_status(void) {
return port_irq_sts;
}
/**
* @brief Checks the interrupt status.
*
* @param[in] sts the interrupt status word
*
* @return The interrupt status.
* @retvel false the word specified a disabled interrupts status.
* @retvel true the word specified an enabled interrupts status.
*/
static inline bool port_irq_enabled(syssts_t sts) {
return sts == (syssts_t)0;
}
/**
* @brief Determines the current execution context.
*
* @return The execution context.
* @retval false not running in ISR mode.
* @retval true running in ISR mode.
*/
static inline bool port_is_isr_context(void) {
return port_isr_context_flag;
}
/**
* @brief Kernel-lock action.
* @details In this port this function disables interrupts globally.
*/
static inline void port_lock(void) {
port_irq_sts = (syssts_t)1;
}
/**
* @brief Kernel-unlock action.
* @details In this port this function enables interrupts globally.
*/
static inline void port_unlock(void) {
port_irq_sts = (syssts_t)0;
}
/**
* @brief Kernel-lock action from an interrupt handler.
* @details In this port this function disables interrupts globally.
* @note Same as @p port_lock() in this port.
*/
static inline void port_lock_from_isr(void) {
port_irq_sts = (syssts_t)1;
}
/**
* @brief Kernel-unlock action from an interrupt handler.
* @details In this port this function enables interrupts globally.
* @note Same as @p port_lock() in this port.
*/
static inline void port_unlock_from_isr(void) {
port_irq_sts = (syssts_t)0;
}
/**
* @brief Disables all the interrupt sources.
*/
static inline void port_disable(void) {
port_irq_sts = (syssts_t)1;
}
/**
* @brief Disables the interrupt sources below kernel-level priority.
*/
static inline void port_suspend(void) {
port_irq_sts = (syssts_t)1;
}
/**
* @brief Enables all the interrupt sources.
*/
static inline void port_enable(void) {
port_irq_sts = (syssts_t)0;
}
/**
* @brief Enters an architecture-dependent IRQ-waiting mode.
* @details The function is meant to return when an interrupt becomes pending.
* The simplest implementation is an empty function or macro but this
* would not take advantage of architecture-specific power saving
* modes.
* @note Implemented as an inlined @p WFI instruction.
*/
static inline void port_wait_for_interrupt(void) {
_sim_check_for_interrupts();
}
#endif /* _CHCORE_H_ */
/** @} */

View File

@ -1,110 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file SIMIA32/compilers/GCC/chtypes.h
* @brief Simulator on IA32 port system types.
*
* @addtogroup SIMIA32_GCC_CORE
* @{
*/
#ifndef _CHTYPES_H_
#define _CHTYPES_H_
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
/**
* @name Common constants
*/
/**
* @brief Generic 'false' boolean constant.
*/
#if !defined(FALSE) || defined(__DOXYGEN__)
#define FALSE 0
#endif
/**
* @brief Generic 'true' boolean constant.
*/
#if !defined(TRUE) || defined(__DOXYGEN__)
#define TRUE 1
#endif
/** @} */
/**
* @name Derived generic types
* @{
*/
typedef volatile int8_t vint8_t; /**< Volatile signed 8 bits. */
typedef volatile uint8_t vuint8_t; /**< Volatile unsigned 8 bits. */
typedef volatile int16_t vint16_t; /**< Volatile signed 16 bits. */
typedef volatile uint16_t vuint16_t; /**< Volatile unsigned 16 bits. */
typedef volatile int32_t vint32_t; /**< Volatile signed 32 bits. */
typedef volatile uint32_t vuint32_t; /**< Volatile unsigned 32 bits. */
/** @} */
/**
* @name Kernel types
* @{
*/
typedef uint32_t rtcnt_t; /**< Realtime counter. */
typedef uint64_t rttime_t; /**< Realtime accumulator. */
typedef uint32_t syssts_t; /**< System status word. */
typedef uint8_t tmode_t; /**< Thread flags. */
typedef uint8_t tstate_t; /**< Thread state. */
typedef uint8_t trefs_t; /**< Thread references counter. */
typedef uint8_t tslices_t; /**< Thread time slices counter.*/
typedef uint32_t tprio_t; /**< Thread priority. */
typedef int32_t msg_t; /**< Inter-thread message. */
typedef int32_t eventid_t; /**< Numeric event identifier. */
typedef uint32_t eventmask_t; /**< Mask of event identifiers. */
typedef uint32_t eventflags_t; /**< Mask of event flags. */
typedef int32_t cnt_t; /**< Generic signed counter. */
typedef uint32_t ucnt_t; /**< Generic unsigned counter. */
/** @} */
/**
* @brief ROM constant modifier.
* @note It is set to use the "const" keyword in this port.
*/
#define ROMCONST const
/**
* @brief Makes functions not inlineable.
* @note If the compiler does not support such attribute then the
* realtime counter precision could be degraded.
*/
#define NOINLINE __attribute__((noinline))
/**
* @brief Optimized thread function declaration macro.
*/
#define PORT_THD_FUNCTION(tname, arg) void tname(void *arg)
/**
* @brief Packed variable specifier.
*/
#define PACKED_VAR __attribute__((packed))
#endif /* _CHTYPES_H_ */
/** @} */

View File

@ -1,7 +0,0 @@
# List of the ChibiOS/RT SIMIA32 port files.
PORTSRC = ${CHIBIOS}/os/rt/ports/SIMIA32/chcore.c
PORTASM =
PORTINC = ${CHIBIOS}/os/rt/ports/SIMIA32/compilers/GCC \
${CHIBIOS}/os/rt/ports/SIMIA32

View File

@ -1,54 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file e200/chcore.c
* @brief Power e200 port code.
*
* @addtogroup PPC_CORE
* @{
*/
#include "ch.h"
/*===========================================================================*/
/* Module local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported functions. */
/*===========================================================================*/
/** @} */

View File

@ -1,599 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file PPC/chcore.h
* @brief Power e200 port macros and structures.
*
* @addtogroup PPC_CORE
* @{
*/
#ifndef _CHCORE_H_
#define _CHCORE_H_
#include "intc.h"
/*===========================================================================*/
/* Module constants. */
/*===========================================================================*/
/**
* @name Architecture and Compiler
* @{
*/
/**
* @brief Macro defining an PPC architecture.
*/
#define PORT_ARCHITECTURE_PPC
/**
* @brief Macro defining the specific PPC architecture.
*/
#define PORT_ARCHITECTURE_PPC_E200
/**
* @brief Name of the implemented architecture.
*/
#define PORT_ARCHITECTURE_NAME "Power Architecture"
/**
* @brief Compiler name and version.
*/
#if defined(__GNUC__) || defined(__DOXYGEN__)
#define PORT_COMPILER_NAME "GCC " __VERSION__
#elif defined(__MWERKS__)
#define PORT_COMPILER_NAME "CW"
#else
#error "unsupported compiler"
#endif
/**
* @brief This port supports a realtime counter.
*/
#define PORT_SUPPORTS_RT FALSE
/** @} */
/**
* @name E200 core variants
* @{
*/
#define PPC_VARIANT_e200z0 200
#define PPC_VARIANT_e200z2 202
#define PPC_VARIANT_e200z3 203
#define PPC_VARIANT_e200z4 204
/** @} */
/* Inclusion of the PPC implementation specific parameters.*/
#include "ppcparams.h"
#include "vectors.h"
/*===========================================================================*/
/* Module pre-compile time settings. */
/*===========================================================================*/
/**
* @brief Stack size for the system idle thread.
* @details This size depends on the idle thread implementation, usually
* the idle thread should take no more space than those reserved
* by @p PORT_INT_REQUIRED_STACK.
* @note In this port it is set to 32 because the idle thread does have
* a stack frame when compiling without optimizations. You may
* reduce this value to zero when compiling with optimizations.
*/
#if !defined(PORT_IDLE_THREAD_STACK_SIZE) || defined(__DOXYGEN__)
#define PORT_IDLE_THREAD_STACK_SIZE 32
#endif
/**
* @brief Per-thread stack overhead for interrupts servicing.
* @details This constant is used in the calculation of the correct working
* area size.
* @note In this port this value is conservatively is set to 256 because
* there is no separate interrupts stack (yet).
*/
#if !defined(PORT_INT_REQUIRED_STACK) || defined(__DOXYGEN__)
#define PORT_INT_REQUIRED_STACK 256
#endif
/**
* @brief Enables an alternative timer implementation.
* @details Usually the port uses a timer interface defined in the file
* @p chcore_timer.h, if this option is enabled then the file
* @p chcore_timer_alt.h is included instead.
*/
#if !defined(PORT_USE_ALT_TIMER) || defined(__DOXYGEN__)
#define PORT_USE_ALT_TIMER FALSE
#endif
/**
* @brief Use VLE instruction set.
* @note This parameter is usually set in the Makefile.
*/
#if !defined(PPC_USE_VLE) || defined(__DOXYGEN__)
#define PPC_USE_VLE TRUE
#endif
/**
* @brief Enables the use of the @p WFI instruction.
*/
#if !defined(PPC_ENABLE_WFI_IDLE) || defined(__DOXYGEN__)
#define PPC_ENABLE_WFI_IDLE FALSE
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if PPC_USE_VLE && !PPC_SUPPORTS_VLE
#error "the selected MCU does not support VLE instructions set"
#endif
#if !PPC_USE_VLE && !PPC_SUPPORTS_BOOKE
#error "the selected MCU does not support BookE instructions set"
#endif
/**
* @brief Name of the architecture variant.
*/
#if (PPC_VARIANT == PPC_VARIANT_e200z0) || defined(__DOXYGEN__)
#define PORT_CORE_VARIANT_NAME "e200z0"
#elif PPC_VARIANT == PPC_VARIANT_e200z2
#define PORT_CORE_VARIANT_NAME "e200z2"
#elif PPC_VARIANT == PPC_VARIANT_e200z3
#define PORT_CORE_VARIANT_NAME "e200z3"
#elif PPC_VARIANT == PPC_VARIANT_e200z4
#define PORT_CORE_VARIANT_NAME "e200z4"
#else
#error "unknown or unsupported PowerPC variant specified"
#endif
/**
* @brief Port-specific information string.
*/
#if PPC_USE_VLE
#define PORT_INFO "VLE mode"
#else
#define PORT_INFO "Book-E mode"
#endif
/*===========================================================================*/
/* Module data structures and types. */
/*===========================================================================*/
/* The following code is not processed when the file is included from an
asm module.*/
#if !defined(_FROM_ASM_)
/**
* @brief Type of stack and memory alignment enforcement.
* @note In this architecture the stack alignment is enforced to 64 bits.
*/
typedef uint64_t stkalign_t;
/**
* @brief Generic PPC register.
*/
typedef void *regppc_t;
/**
* @brief Mandatory part of a stack frame.
*/
struct port_eabi_frame {
uint32_t slink; /**< Stack back link. */
uint32_t shole; /**< Stack hole for LR storage. */
};
/**
* @brief Interrupt saved context.
* @details This structure represents the stack frame saved during a
* preemption-capable interrupt handler.
* @note R2 and R13 are not saved because those are assumed to be immutable
* during the system life cycle.
*/
struct port_extctx {
struct port_eabi_frame frame;
/* Start of the e_stmvsrrw frame (offset 8).*/
regppc_t pc;
regppc_t msr;
/* Start of the e_stmvsprw frame (offset 16).*/
regppc_t cr;
regppc_t lr;
regppc_t ctr;
regppc_t xer;
/* Start of the e_stmvgprw frame (offset 32).*/
regppc_t r0;
regppc_t r3;
regppc_t r4;
regppc_t r5;
regppc_t r6;
regppc_t r7;
regppc_t r8;
regppc_t r9;
regppc_t r10;
regppc_t r11;
regppc_t r12;
regppc_t padding;
};
/**
* @brief System saved context.
* @details This structure represents the inner stack frame during a context
* switching.
* @note R2 and R13 are not saved because those are assumed to be immutable
* during the system life cycle.
* @note LR is stored in the caller context so it is not present in this
* structure.
*/
struct port_intctx {
regppc_t cr; /* Part of it is not volatile... */
regppc_t r14;
regppc_t r15;
regppc_t r16;
regppc_t r17;
regppc_t r18;
regppc_t r19;
regppc_t r20;
regppc_t r21;
regppc_t r22;
regppc_t r23;
regppc_t r24;
regppc_t r25;
regppc_t r26;
regppc_t r27;
regppc_t r28;
regppc_t r29;
regppc_t r30;
regppc_t r31;
regppc_t padding;
};
/**
* @brief Platform dependent part of the @p thread_t structure.
* @details This structure usually contains just the saved stack pointer
* defined as a pointer to a @p port_intctx structure.
*/
struct context {
struct port_intctx *sp;
};
#endif /* !defined(_FROM_ASM_) */
/*===========================================================================*/
/* Module macros. */
/*===========================================================================*/
/**
* @brief Platform dependent part of the @p chThdCreateI() API.
* @details This code usually setup the context switching frame represented
* by an @p port_intctx structure.
*/
#define PORT_SETUP_CONTEXT(tp, workspace, wsize, pf, arg) { \
uint8_t *sp = (uint8_t *)(workspace) + \
(wsize) - \
sizeof(struct port_eabi_frame); \
((struct port_eabi_frame *)sp)->slink = 0; \
((struct port_eabi_frame *)sp)->shole = (uint32_t)_port_thread_start; \
(tp)->p_ctx.sp = (struct port_intctx *)(sp - sizeof(struct port_intctx)); \
(tp)->p_ctx.sp->r31 = (regppc_t)(arg); \
(tp)->p_ctx.sp->r30 = (regppc_t)(pf); \
}
/**
* @brief Computes the thread working area global size.
* @note There is no need to perform alignments in this macro.
*/
#define PORT_WA_SIZE(n) (sizeof(struct port_intctx) + \
sizeof(struct port_extctx) + \
((size_t)(n)) + ((size_t)(PORT_INT_REQUIRED_STACK)))
/**
* @brief IRQ prologue code.
* @details This macro must be inserted at the start of all IRQ handlers
* enabled to invoke system APIs.
*/
#define PORT_IRQ_PROLOGUE()
/**
* @brief IRQ epilogue code.
* @details This macro must be inserted at the end of all IRQ handlers
* enabled to invoke system APIs.
*/
#define PORT_IRQ_EPILOGUE()
/**
* @brief IRQ handler function declaration.
* @note @p id can be a function name or a vector number depending on the
* port implementation.
*/
#define PORT_IRQ_HANDLER(id) void id(void)
/**
* @brief Fast IRQ handler function declaration.
* @note @p id can be a function name or a vector number depending on the
* port implementation.
*/
#define PORT_FAST_IRQ_HANDLER(id) void id(void)
/**
* @brief Priority level verification macro.
*/
#define PORT_IRQ_IS_VALID_PRIORITY(n) \
(((n) >= 0U) && ((n) < INTC_PRIORITY_LEVELS))
/**
* @brief Priority level verification macro.
*/
#define PORT_IRQ_IS_VALID_KERNEL_PRIORITY(n) \
(((n) >= 0U) && ((n) < INTC_PRIORITY_LEVELS))
/**
* @brief Performs a context switch between two threads.
* @details This is the most critical code in any port, this function
* is responsible for the context switch between 2 threads.
* @note The implementation of this code affects <b>directly</b> the context
* switch performance so optimize here as much as you can.
*
* @param[in] ntp the thread to be switched in
* @param[in] otp the thread to be switched out
*/
#if !CH_DBG_ENABLE_STACK_CHECK || defined(__DOXYGEN__)
#define port_switch(ntp, otp) _port_switch(ntp, otp)
#else
#define port_switch(ntp, otp) { \
register struct port_intctx *sp asm ("%r1"); \
if ((stkalign_t *)(sp - 1) < otp->p_stklimit) \
chSysHalt("stack overflow"); \
_port_switch(ntp, otp); \
}
#endif
/**
* @brief Writes to a special register.
*
* @param[in] spr special register number
* @param[in] val value to be written, must be an automatic variable
*/
#define port_write_spr(spr, val) \
asm volatile ("mtspr %[p0], %[p1]" : : [p0] "n" (spr), [p1] "r" (val))
/**
* @brief Writes to a special register.
*
* @param[in] spr special register number
* @param[in] val returned value, must be an automatic variable
*/
#define port_read_spr(spr, val) \
asm volatile ("mfspr %[p0], %[p1]" : [p0] "=r" (val) : [p1] "n" (spr))
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
/* The following code is not processed when the file is included from an
asm module.*/
#if !defined(_FROM_ASM_)
#ifdef __cplusplus
extern "C" {
#endif
void _port_switch(thread_t *ntp, thread_t *otp);
void _port_thread_start(void);
#ifdef __cplusplus
}
#endif
#endif /* !defined(_FROM_ASM_) */
/*===========================================================================*/
/* Module inline functions. */
/*===========================================================================*/
/* The following code is not processed when the file is included from an
asm module.*/
#if !defined(_FROM_ASM_)
/**
* @brief Kernel port layer initialization.
* @details IVOR4 and IVOR10 initialization.
*/
static inline void port_init(void) {
uint32_t n;
unsigned i;
/* Initializing the SPRG0 register to zero, it is required for interrupts
handling.*/
n = 0;
port_write_spr(272, n);
#if PPC_SUPPORTS_IVORS
{
/* The CPU supports IVOR registers, the kernel requires IVOR4 and IVOR10
and the initialization is performed here.*/
extern void _IVOR4(void);
port_write_spr(404, _IVOR4);
#if PPC_SUPPORTS_DECREMENTER
extern void _IVOR10(void);
port_write_spr(410, _IVOR10);
#endif
}
#endif
/* INTC initialization, software vector mode, 4 bytes vectors, starting
at priority 0.*/
INTC_BCR = 0;
for (i = 0; i < PPC_CORE_NUMBER; i++) {
INTC_CPR(i) = 0;
INTC_IACKR(i) = (uint32_t)_vectors;
}
}
/**
* @brief Returns a word encoding the current interrupts status.
*
* @return The interrupts status.
*/
static inline syssts_t port_get_irq_status(void) {
uint32_t sts;
asm volatile ("mfmsr %[p0]" : [p0] "=r" (sts) :);
return sts;
}
/**
* @brief Checks the interrupt status.
*
* @param[in] sts the interrupt status word
*
* @return The interrupt status.
* @retvel false the word specified a disabled interrupts status.
* @retvel true the word specified an enabled interrupts status.
*/
static inline bool port_irq_enabled(syssts_t sts) {
return (bool)((sts & (1 << 15)) != 0);
}
/**
* @brief Determines the current execution context.
*
* @return The execution context.
* @retval false not running in ISR mode.
* @retval true running in ISR mode.
*/
static inline bool port_is_isr_context(void) {
uint32_t sprg0;
/* The SPRG0 register is increased before entering interrupt handlers and
decreased at the end.*/
port_read_spr(272, sprg0);
return (bool)(sprg0 > 0);
}
/**
* @brief Kernel-lock action.
* @note Implemented as global interrupt disable.
*/
static inline void port_lock(void) {
asm volatile ("wrteei 0" : : : "memory");
}
/**
* @brief Kernel-unlock action.
* @note Implemented as global interrupt enable.
*/
static inline void port_unlock(void) {
asm volatile("wrteei 1" : : : "memory");
}
/**
* @brief Kernel-lock action from an interrupt handler.
* @note Implementation not needed.
*/
static inline void port_lock_from_isr(void) {
}
/**
* @brief Kernel-unlock action from an interrupt handler.
* @note Implementation not needed.
*/
static inline void port_unlock_from_isr(void) {
}
/**
* @brief Disables all the interrupt sources.
* @note Implemented as global interrupt disable.
*/
static inline void port_disable(void) {
asm volatile ("wrteei 0" : : : "memory");
}
/**
* @brief Disables the interrupt sources below kernel-level priority.
* @note Same as @p port_disable() in this port, there is no difference
* between the two states.
*/
static inline void port_suspend(void) {
asm volatile ("wrteei 0" : : : "memory");
}
/**
* @brief Enables all the interrupt sources.
* @note Implemented as global interrupt enable.
*/
static inline void port_enable(void) {
asm volatile ("wrteei 1" : : : "memory");
}
/**
* @brief Enters an architecture-dependent IRQ-waiting mode.
* @details The function is meant to return when an interrupt becomes pending.
* The simplest implementation is an empty function or macro but this
* would not take advantage of architecture-specific power saving
* modes.
* @note Implemented as an inlined @p wait instruction.
*/
static inline void port_wait_for_interrupt(void) {
#if PPC_ENABLE_WFI_IDLE
asm volatile ("wait" : : : "memory");
#endif
}
/**
* @brief Returns the current value of the realtime counter.
*
* @return The realtime counter value.
*/
static inline rtcnt_t port_rt_get_counter_value(void) {
return 0;
}
#endif /* !defined(_FROM_ASM_) */
/*===========================================================================*/
/* Module late inclusions. */
/*===========================================================================*/
#if !defined(_FROM_ASM_)
#if CH_CFG_ST_TIMEDELTA > 0
#if !PORT_USE_ALT_TIMER
#include "chcore_timer.h"
#else /* PORT_USE_ALT_TIMER */
#include "chcore_timer_alt.h"
#endif /* PORT_USE_ALT_TIMER */
#endif /* CH_CFG_ST_TIMEDELTA > 0 */
#endif /* !defined(_FROM_ASM_) */
#endif /* _CHCORE_H_ */
/** @} */

View File

@ -1,105 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file e200/compilers/GCC/chcoreasm.s
* @brief Power Architecture port low level code.
*
* @addtogroup PPC_GCC_CORE
* @{
*/
/*===========================================================================*/
/* Module constants. */
/*===========================================================================*/
#if !defined(FALSE) || defined(__DOXYGEN__)
#define FALSE 0
#endif
#if !defined(TRUE) || defined(__DOXYGEN__)
#define TRUE 1
#endif
/*===========================================================================*/
/* Code section. */
/*===========================================================================*/
/*
* Imports the PPC configuration headers.
*/
#define _FROM_ASM_
#include "chconf.h"
#include "chcore.h"
#if !defined(__DOXYGEN__)
.extern chThdExit
#if PPC_USE_VLE == TRUE
.section .text_vle, 16
.align 2
.globl _port_switch
.type _port_switch, @function
_port_switch:
e_subi r1, r1, 80
se_mflr r0
e_stw r0, 84(r1)
mfcr r0
se_stw r0, 0(r1)
e_stmw r14, 4(r1)
se_stw r1, 12(r4)
se_lwz r1, 12(r3)
e_lmw r14, 4(r1)
se_lwz r0, 0(r1)
mtcr r0
e_lwz r0, 84(r1)
se_mtlr r0
e_addi r1, r1, 80
se_blr
.align 2
.globl _port_thread_start
.type _port_thread_start, @function
_port_thread_start:
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_unlock
#endif
#if CH_DBG_STATISTICS
bl _stats_stop_measure_crit_thd
#endif
wrteei 1
mr r3, r31
mtctr r30
se_bctrl
se_li r0, 0
e_bl chThdExit
#else /* PPC_USE_VLE == FALSE */
#error "non-VLE mode not yet implemented"
#endif /* PPC_USE_VLE == FALSE */
#endif /* !defined(__DOXYGEN__) */
/** @} */

View File

@ -1,93 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file e200/compilers/CW/chtypes.h
* @brief Power e200 port system types.
*
* @addtogroup PPC_CW_CORE
* @{
*/
#ifndef _CHTYPES_H_
#define _CHTYPES_H_
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
/**
* @name Common constants
*/
/**
* @brief Generic 'false' boolean constant.
*/
#if !defined(FALSE) || defined(__DOXYGEN__)
#define FALSE 0
#endif
/**
* @brief Generic 'true' boolean constant.
*/
#if !defined(TRUE) || defined(__DOXYGEN__)
#define TRUE 1
#endif
/** @} */
/**
* @name Kernel types
* @{
*/
typedef uint32_t rtcnt_t; /**< Realtime counter. */
typedef uint64_t rttime_t; /**< Realtime accumulator. */
typedef uint32_t syssts_t; /**< System status word. */
typedef uint8_t tmode_t; /**< Thread flags. */
typedef uint8_t tstate_t; /**< Thread state. */
typedef uint8_t trefs_t; /**< Thread references counter. */
typedef uint8_t tslices_t; /**< Thread time slices counter.*/
typedef uint32_t tprio_t; /**< Thread priority. */
typedef int32_t msg_t; /**< Inter-thread message. */
typedef int32_t eventid_t; /**< Numeric event identifier. */
typedef uint32_t eventmask_t; /**< Mask of event identifiers. */
typedef uint32_t eventflags_t; /**< Mask of event flags. */
typedef int32_t cnt_t; /**< Generic signed counter. */
typedef uint32_t ucnt_t; /**< Generic unsigned counter. */
/** @} */
/**
* @brief ROM constant modifier.
* @note It is set to use the "const" keyword in this port.
*/
#define ROMCONST const
/**
* @brief Makes functions not inlineable.
* @note If the compiler does not support such attribute then the
* realtime counter precision could be degraded.
*/
#define NOINLINE __attribute__((noinline))
/**
* @brief Optimized thread function declaration macro.
*/
#define PORT_THD_FUNCTION(tname, arg) void tname(void *arg)
#endif /* _CHTYPES_H_ */
/** @} */

View File

@ -1,204 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file ivor.s
* @brief Kernel ISRs.
*
* @addtogroup PPC_CORE
* @{
*/
/*===========================================================================*/
/* Module constants. */
/*===========================================================================*/
#if !defined(FALSE) || defined(__DOXYGEN__)
#define FALSE 0
#endif
#if !defined(TRUE) || defined(__DOXYGEN__)
#define TRUE 1
#endif
/*===========================================================================*/
/* Code section. */
/*===========================================================================*/
/*
* Imports the PPC configuration headers.
*/
#define _FROM_ASM_
#include "chconf.h"
#include "chcore.h"
#if !defined(__DOXYGEN__)
.extern _stats_start_measure_crit_thd
.extern _stats_stop_measure_crit_thd
.extern _dbg_check_lock
.extern _dbg_check_unlock
.extern chSchIsPreemptionRequired
.extern chSchDoReschedule
.extern chSysTimerHandlerI
.section .handlers, text_vle
#if PPC_USE_VLE == TRUE
#if PPC_SUPPORTS_DECREMENTER
/*
* _IVOR10 handler (Book-E decrementer).
*/
.align 16
.globl _IVOR10
.type _IVOR10, @function
_IVOR10:
/* Saving the external context (port_extctx structure).*/
e_stwu r1, -80(r1)
e_stmvsrrw 8(r1) /* Saves PC, MSR. */
e_stmvsprw 16(r1) /* Saves CR, LR, CTR, XER. */
e_stmvgprw 32(r1) /* Saves GPR0, GPR3...GPR12. */
/* Increasing the SPGR0 register.*/
mfspr r0, 272
se_addi r0, 1
mtspr 272, r0
/* Reset DIE bit in TSR register.*/
e_lis r3, 0x0800 /* DIS bit mask. */
mtspr 336, r3 /* TSR register. */
/* Restoring pre-IRQ MSR register value.*/
mfSRR1 r0
#if !PPC_USE_IRQ_PREEMPTION
/* No preemption, keeping EE disabled.*/
se_bclri r0, 16 /* EE = bit 16. */
#endif
mtMSR r0
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_enter_isr
bl _dbg_check_lock_from_isr
#endif
/* System tick handler invocation.*/
e_bl chSysTimerHandlerI
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_unlock_from_isr
bl _dbg_check_leave_isr
#endif
#if PPC_USE_IRQ_PREEMPTION
/* Prevents preemption again.*/
wrteei 0
#endif
/* Jumps to the common IVOR epilogue code.*/
se_b _ivor_exit
#endif /* PPC_SUPPORTS_DECREMENTER */
/*
* _IVOR4 handler (Book-E external interrupt).
*/
.align 16
.globl _IVOR4
.type _IVOR4, @function
_IVOR4:
/* Saving the external context (port_extctx structure).*/
e_stwu r1, -80(r1)
e_stmvsrrw 8(r1) /* Saves PC, MSR. */
e_stmvsprw 16(r1) /* Saves CR, LR, CTR, XER. */
e_stmvgprw 32(r1) /* Saves GPR0, GPR3...GPR12. */
/* Increasing the SPGR0 register.*/
mfspr r0, 272
se_addi r0, 1
mtspr 272, r0
/* Software vector address from the INTC register.*/
e_lis r3, INTC_IACKR_ADDR@h
e_or2i r3, INTC_IACKR_ADDR@l /* IACKR register address. */
se_lwz r3, 0(r3) /* IACKR register value. */
se_lwz r3, 0(r3)
mtCTR r3 /* Software handler address. */
/* Restoring pre-IRQ MSR register value.*/
mfSRR1 r0
#if !PPC_USE_IRQ_PREEMPTION
/* No preemption, keeping EE disabled.*/
se_bclri r0, 16 /* EE = bit 16. */
#endif
mtMSR r0
/* Exectes the software handler.*/
se_bctrl
#if PPC_USE_IRQ_PREEMPTION
/* Prevents preemption again.*/
wrteei 0
#endif
/* Informs the INTC that the interrupt has been served.*/
mbar 0
e_lis r3, INTC_EOIR_ADDR@h
e_or2i r3, INTC_EOIR_ADDR@l
se_stw r3, 0(r3) /* Writing any value should do. */
/* Common IVOR epilogue code, context restore.*/
.globl _ivor_exit
_ivor_exit:
/* Decreasing the SPGR0 register.*/
mfspr r0, 272
se_subi r0, 1
mtspr 272, r0
#if CH_DBG_STATISTICS
e_bl _stats_start_measure_crit_thd
#endif
#if CH_DBG_SYSTEM_STATE_CHECK
e_bl _dbg_check_lock
#endif
e_bl chSchIsPreemptionRequired
e_cmpli cr0, r3, 0
se_beq .noresch
e_bl chSchDoReschedule
.noresch:
#if CH_DBG_SYSTEM_STATE_CHECK
e_bl _dbg_check_unlock
#endif
#if CH_DBG_STATISTICS
e_bl _stats_stop_measure_crit_thd
#endif
/* Restoring the external context.*/
e_lmvgprw 32(r1) /* Restores GPR0, GPR3...GPR12. */
e_lmvsprw 16(r1) /* Restores CR, LR, CTR, XER. */
e_lmvsrrw 8(r1) /* Restores PC, MSR. */
e_addi r1, r1, 80 /* Back to the previous frame. */
se_rfi
#else /* PPC_USE_VLE == FALSE */
#error "non-VLE mode not yet implemented"
#endif /* PPC_USE_VLE == FALSE */
#endif /* !defined(__DOXYGEN__) */
/** @} */

View File

@ -1,97 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file e200/compilers/GCC/chcoreasm.s
* @brief Power Architecture port low level code.
*
* @addtogroup PPC_GCC_CORE
* @{
*/
/*===========================================================================*/
/* Module constants. */
/*===========================================================================*/
#if !defined(FALSE) || defined(__DOXYGEN__)
#define FALSE 0
#endif
#if !defined(TRUE) || defined(__DOXYGEN__)
#define TRUE 1
#endif
/*===========================================================================*/
/* Code section. */
/*===========================================================================*/
#define _FROM_ASM_
#include "chconf.h"
#include "chcore.h"
#if !defined(__DOXYGEN__)
#if PPC_USE_VLE == TRUE
.section .text_vle, "ax"
#else
.section .text, "ax"
#endif
.align 2
.globl _port_switch
.type _port_switch, @function
_port_switch:
subi %sp, %sp, 80
mflr %r0
stw %r0, 84(%sp)
mfcr %r0
stw %r0, 0(%sp)
stmw %r14, 4(%sp)
stw %sp, 12(%r4)
lwz %sp, 12(%r3)
lmw %r14, 4(%sp)
lwz %r0, 0(%sp)
mtcr %r0
lwz %r0, 84(%sp)
mtlr %r0
addi %sp, %sp, 80
blr
.align 2
.globl _port_thread_start
.type _port_thread_start, @function
_port_thread_start:
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_unlock
#endif
#if CH_DBG_STATISTICS
bl _stats_stop_measure_crit_thd
#endif
wrteei 1
mr %r3, %r31
mtctr %r30
bctrl
li %r0, 0
bl chThdExit
#endif /* !defined(__DOXYGEN__) */
/** @} */

View File

@ -1,93 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file e200/compilers/GCC/chtypes.h
* @brief Power e200 port system types.
*
* @addtogroup PPC_GCC_CORE
* @{
*/
#ifndef _CHTYPES_H_
#define _CHTYPES_H_
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
/**
* @name Common constants
*/
/**
* @brief Generic 'false' boolean constant.
*/
#if !defined(FALSE) || defined(__DOXYGEN__)
#define FALSE 0
#endif
/**
* @brief Generic 'true' boolean constant.
*/
#if !defined(TRUE) || defined(__DOXYGEN__)
#define TRUE 1
#endif
/** @} */
/**
* @name Kernel types
* @{
*/
typedef uint32_t rtcnt_t; /**< Realtime counter. */
typedef uint64_t rttime_t; /**< Realtime accumulator. */
typedef uint32_t syssts_t; /**< System status word. */
typedef uint8_t tmode_t; /**< Thread flags. */
typedef uint8_t tstate_t; /**< Thread state. */
typedef uint8_t trefs_t; /**< Thread references counter. */
typedef uint8_t tslices_t; /**< Thread time slices counter.*/
typedef uint32_t tprio_t; /**< Thread priority. */
typedef int32_t msg_t; /**< Inter-thread message. */
typedef int32_t eventid_t; /**< Numeric event identifier. */
typedef uint32_t eventmask_t; /**< Mask of event identifiers. */
typedef uint32_t eventflags_t; /**< Mask of event flags. */
typedef int32_t cnt_t; /**< Generic signed counter. */
typedef uint32_t ucnt_t; /**< Generic unsigned counter. */
/** @} */
/**
* @brief ROM constant modifier.
* @note It is set to use the "const" keyword in this port.
*/
#define ROMCONST const
/**
* @brief Makes functions not inlineable.
* @note If the compiler does not support such attribute then the
* realtime counter precision could be degraded.
*/
#define NOINLINE __attribute__((noinline))
/**
* @brief Optimized thread function declaration macro.
*/
#define PORT_THD_FUNCTION(tname, arg) void tname(void *arg)
#endif /* _CHTYPES_H_ */
/** @} */

View File

@ -1,258 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file ivor.s
* @brief Kernel ISRs.
*
* @addtogroup PPC_CORE
* @{
*/
#if !defined(FALSE) || defined(__DOXYGEN__)
#define FALSE 0
#endif
#if !defined(TRUE) || defined(__DOXYGEN__)
#define TRUE 1
#endif
/*
* Imports the PPC configuration headers.
*/
#define _FROM_ASM_
#include "chconf.h"
#include "chcore.h"
#if !defined(__DOXYGEN__)
.section .handlers, "ax"
#if PPC_SUPPORTS_DECREMENTER
/*
* _IVOR10 handler (Book-E decrementer).
*/
.align 4
.globl _IVOR10
.type _IVOR10, @function
_IVOR10:
/* Saving the external context (port_extctx structure).*/
stwu %sp, -80(%sp)
#if PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI
e_stmvsrrw 8(%sp) /* Saves PC, MSR. */
e_stmvsprw 16(%sp) /* Saves CR, LR, CTR, XER. */
e_stmvgprw 32(%sp) /* Saves GPR0, GPR3...GPR12. */
#else /* !(PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI) */
stw %r0, 32(%sp) /* Saves GPR0. */
mfSRR0 %r0
stw %r0, 8(%sp) /* Saves PC. */
mfSRR1 %r0
stw %r0, 12(%sp) /* Saves MSR. */
mfCR %r0
stw %r0, 16(%sp) /* Saves CR. */
mfLR %r0
stw %r0, 20(%sp) /* Saves LR. */
mfCTR %r0
stw %r0, 24(%sp) /* Saves CTR. */
mfXER %r0
stw %r0, 28(%sp) /* Saves XER. */
stw %r3, 36(%sp) /* Saves GPR3...GPR12. */
stw %r4, 40(%sp)
stw %r5, 44(%sp)
stw %r6, 48(%sp)
stw %r7, 52(%sp)
stw %r8, 56(%sp)
stw %r9, 60(%sp)
stw %r10, 64(%sp)
stw %r11, 68(%sp)
stw %r12, 72(%sp)
#endif /* !(PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI) */
/* Increasing the SPGR0 register.*/
mfspr %r0, 272
eaddi %r0, %r0, 1
mtspr 272, %r0
/* Reset DIE bit in TSR register.*/
lis %r3, 0x0800 /* DIS bit mask. */
mtspr 336, %r3 /* TSR register. */
/* Restoring pre-IRQ MSR register value.*/
mfSRR1 %r0
#if !PPC_USE_IRQ_PREEMPTION
/* No preemption, keeping EE disabled.*/
se_bclri %r0, 16 /* EE = bit 16. */
#endif
mtMSR %r0
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_enter_isr
bl _dbg_check_lock_from_isr
#endif
/* System tick handler invocation.*/
bl chSysTimerHandlerI
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_unlock_from_isr
bl _dbg_check_leave_isr
#endif
#if PPC_USE_IRQ_PREEMPTION
/* Prevents preemption again.*/
wrteei 0
#endif
/* Jumps to the common IVOR epilogue code.*/
b _ivor_exit
#endif /* PPC_SUPPORTS_DECREMENTER */
/*
* _IVOR4 handler (Book-E external interrupt).
*/
.align 4
.globl _IVOR4
.type _IVOR4, @function
_IVOR4:
/* Saving the external context (port_extctx structure).*/
stwu %sp, -80(%sp)
#if PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI
e_stmvsrrw 8(%sp) /* Saves PC, MSR. */
e_stmvsprw 16(%sp) /* Saves CR, LR, CTR, XER. */
e_stmvgprw 32(%sp) /* Saves GPR0, GPR3...GPR12. */
#else /* !(PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI) */
stw %r0, 32(%sp) /* Saves GPR0. */
mfSRR0 %r0
stw %r0, 8(%sp) /* Saves PC. */
mfSRR1 %r0
stw %r0, 12(%sp) /* Saves MSR. */
mfCR %r0
stw %r0, 16(%sp) /* Saves CR. */
mfLR %r0
stw %r0, 20(%sp) /* Saves LR. */
mfCTR %r0
stw %r0, 24(%sp) /* Saves CTR. */
mfXER %r0
stw %r0, 28(%sp) /* Saves XER. */
stw %r3, 36(%sp) /* Saves GPR3...GPR12. */
stw %r4, 40(%sp)
stw %r5, 44(%sp)
stw %r6, 48(%sp)
stw %r7, 52(%sp)
stw %r8, 56(%sp)
stw %r9, 60(%sp)
stw %r10, 64(%sp)
stw %r11, 68(%sp)
stw %r12, 72(%sp)
#endif /* !(PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI) */
/* Increasing the SPGR0 register.*/
mfspr %r0, 272
eaddi %r0, %r0, 1
mtspr 272, %r0
/* Software vector address from the INTC register.*/
lis %r3, INTC_IACKR_ADDR@h
ori %r3, %r3, INTC_IACKR_ADDR@l /* IACKR register address. */
lwz %r3, 0(%r3) /* IACKR register value. */
lwz %r3, 0(%r3)
mtCTR %r3 /* Software handler address. */
/* Restoring pre-IRQ MSR register value.*/
mfSRR1 %r0
#if !PPC_USE_IRQ_PREEMPTION
/* No preemption, keeping EE disabled.*/
se_bclri %r0, 16 /* EE = bit 16. */
#endif
mtMSR %r0
/* Exectes the software handler.*/
bctrl
#if PPC_USE_IRQ_PREEMPTION
/* Prevents preemption again.*/
wrteei 0
#endif
/* Informs the INTC that the interrupt has been served.*/
mbar 0
lis %r3, INTC_EOIR_ADDR@h
ori %r3, %r3, INTC_EOIR_ADDR@l
stw %r3, 0(%r3) /* Writing any value should do. */
/* Common IVOR epilogue code, context restore.*/
.globl _ivor_exit
_ivor_exit:
/* Decreasing the SPGR0 register.*/
mfspr %r0, 272
eaddi %r0, %r0, -1
mtspr 272, %r0
#if CH_DBG_STATISTICS
bl _stats_start_measure_crit_thd
#endif
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_lock
#endif
bl chSchIsPreemptionRequired
cmpli cr0, %r3, 0
beq cr0, .noresch
bl chSchDoReschedule
.noresch:
#if CH_DBG_SYSTEM_STATE_CHECK
bl _dbg_check_unlock
#endif
#if CH_DBG_STATISTICS
bl _stats_stop_measure_crit_thd
#endif
/* Restoring the external context.*/
#if PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI
e_lmvgprw 32(%sp) /* Restores GPR0, GPR3...GPR12. */
e_lmvsprw 16(%sp) /* Restores CR, LR, CTR, XER. */
e_lmvsrrw 8(%sp) /* Restores PC, MSR. */
#else /*!(PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI) */
lwz %r3, 36(%sp) /* Restores GPR3...GPR12. */
lwz %r4, 40(%sp)
lwz %r5, 44(%sp)
lwz %r6, 48(%sp)
lwz %r7, 52(%sp)
lwz %r8, 56(%sp)
lwz %r9, 60(%sp)
lwz %r10, 64(%sp)
lwz %r11, 68(%sp)
lwz %r12, 72(%sp)
lwz %r0, 8(%sp)
mtSRR0 %r0 /* Restores PC. */
lwz %r0, 12(%sp)
mtSRR1 %r0 /* Restores MSR. */
lwz %r0, 16(%sp)
mtCR %r0 /* Restores CR. */
lwz %r0, 20(%sp)
mtLR %r0 /* Restores LR. */
lwz %r0, 24(%sp)
mtCTR %r0 /* Restores CTR. */
lwz %r0, 28(%sp)
mtXER %r0 /* Restores XER. */
lwz %r0, 32(%sp) /* Restores GPR0. */
#endif /* !(PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI) */
addi %sp, %sp, 80 /* Back to the previous frame. */
rfi
#endif /* !defined(__DOXYGEN__) */
/** @} */

View File

@ -1,8 +0,0 @@
# List of the ChibiOS/RT e200 generic port files.
PORTSRC = $(CHIBIOS)/os/rt/ports/e200/chcore.c
PORTASM = $(CHIBIOS)/os/rt/ports/e200/compilers/GCC/ivor.s \
$(CHIBIOS)/os/rt/ports/e200/compilers/GCC/chcoreasm.s
PORTINC = $(CHIBIOS)/os/rt/ports/e200 \
$(CHIBIOS)/os/rt/ports/e200/compilers/GCC

View File

@ -14,9 +14,6 @@ endif
ifneq ($(findstring CH_DBG_STATISTICS TRUE,$(CHCONF)),) ifneq ($(findstring CH_DBG_STATISTICS TRUE,$(CHCONF)),)
KERNSRC += $(CHIBIOS)/os/rt/src/chstats.c KERNSRC += $(CHIBIOS)/os/rt/src/chstats.c
endif endif
ifneq ($(findstring CH_CFG_USE_DYNAMIC TRUE,$(CHCONF)),)
KERNSRC += $(CHIBIOS)/os/rt/src/chdynamic.c
endif
ifneq ($(findstring CH_CFG_USE_REGISTRY TRUE,$(CHCONF)),) ifneq ($(findstring CH_CFG_USE_REGISTRY TRUE,$(CHCONF)),)
KERNSRC += $(CHIBIOS)/os/rt/src/chregistry.c KERNSRC += $(CHIBIOS)/os/rt/src/chregistry.c
endif endif
@ -35,42 +32,46 @@ endif
ifneq ($(findstring CH_CFG_USE_MESSAGES TRUE,$(CHCONF)),) ifneq ($(findstring CH_CFG_USE_MESSAGES TRUE,$(CHCONF)),)
KERNSRC += $(CHIBIOS)/os/rt/src/chmsg.c KERNSRC += $(CHIBIOS)/os/rt/src/chmsg.c
endif endif
ifneq ($(findstring CH_CFG_USE_MAILBOXES TRUE,$(CHCONF)),)
KERNSRC += $(CHIBIOS)/os/rt/src/chmboxes.c
endif
ifneq ($(findstring CH_CFG_USE_QUEUES TRUE,$(CHCONF)),) ifneq ($(findstring CH_CFG_USE_QUEUES TRUE,$(CHCONF)),)
KERNSRC += $(CHIBIOS)/os/rt/src/chqueues.c KERNSRC += $(CHIBIOS)/os/rt/src/chqueues.c
endif endif
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)),) ifneq ($(findstring CH_CFG_USE_MEMCORE TRUE,$(CHCONF)),)
KERNSRC += $(CHIBIOS)/os/rt/src/chmemcore.c KERNSRC += $(CHIBIOS)/os/common/oslib/src/chmemcore.c
endif endif
ifneq ($(findstring CH_CFG_USE_HEAP TRUE,$(CHCONF)),) ifneq ($(findstring CH_CFG_USE_HEAP TRUE,$(CHCONF)),)
KERNSRC += $(CHIBIOS)/os/rt/src/chheap.c KERNSRC += $(CHIBIOS)/os/common/oslib/src/chheap.c
endif endif
ifneq ($(findstring CH_CFG_USE_MEMPOOLS TRUE,$(CHCONF)),) ifneq ($(findstring CH_CFG_USE_MEMPOOLS TRUE,$(CHCONF)),)
KERNSRC += $(CHIBIOS)/os/rt/src/chmempools.c KERNSRC += $(CHIBIOS)/os/common/oslib/src/chmempools.c
endif
ifneq ($(findstring CH_CFG_USE_DYNAMIC TRUE,$(CHCONF)),)
KERNSRC += $(CHIBIOS)/os/common/oslib/src/chdynamic.c
endif endif
else else
KERNSRC = $(CHIBIOS)/os/rt/src/chsys.c \ KERNSRC := $(CHIBIOS)/os/rt/src/chsys.c \
$(CHIBIOS)/os/rt/src/chdebug.c \ $(CHIBIOS)/os/rt/src/chdebug.c \
$(CHIBIOS)/os/rt/src/chvt.c \ $(CHIBIOS)/os/rt/src/chvt.c \
$(CHIBIOS)/os/rt/src/chschd.c \ $(CHIBIOS)/os/rt/src/chschd.c \
$(CHIBIOS)/os/rt/src/chthreads.c \ $(CHIBIOS)/os/rt/src/chthreads.c \
$(CHIBIOS)/os/rt/src/chtm.c \ $(CHIBIOS)/os/rt/src/chtm.c \
$(CHIBIOS)/os/rt/src/chstats.c \ $(CHIBIOS)/os/rt/src/chstats.c \
$(CHIBIOS)/os/rt/src/chdynamic.c \
$(CHIBIOS)/os/rt/src/chregistry.c \ $(CHIBIOS)/os/rt/src/chregistry.c \
$(CHIBIOS)/os/rt/src/chsem.c \ $(CHIBIOS)/os/rt/src/chsem.c \
$(CHIBIOS)/os/rt/src/chmtx.c \ $(CHIBIOS)/os/rt/src/chmtx.c \
$(CHIBIOS)/os/rt/src/chcond.c \ $(CHIBIOS)/os/rt/src/chcond.c \
$(CHIBIOS)/os/rt/src/chevents.c \ $(CHIBIOS)/os/rt/src/chevents.c \
$(CHIBIOS)/os/rt/src/chmsg.c \ $(CHIBIOS)/os/rt/src/chmsg.c \
$(CHIBIOS)/os/rt/src/chmboxes.c \
$(CHIBIOS)/os/rt/src/chqueues.c \ $(CHIBIOS)/os/rt/src/chqueues.c \
$(CHIBIOS)/os/rt/src/chmemcore.c \ $(CHIBIOS)/os/common/oslib/src/chmboxes.c \
$(CHIBIOS)/os/rt/src/chheap.c \ $(CHIBIOS)/os/common/oslib/src/chmemcore.c \
$(CHIBIOS)/os/rt/src/chmempools.c $(CHIBIOS)/os/common/oslib/src/chheap.c \
$(CHIBIOS)/os/common/oslib/src/chmempools.c \
$(CHIBIOS)/os/common/oslib/src/chdynamic.c
endif endif
# Required include directories # Required include directories
KERNINC = $(CHIBIOS)/os/rt/include KERNINC := $(CHIBIOS)/os/rt/include \
$(CHIBIOS)/os/common/oslib/include

View File

@ -76,7 +76,7 @@ void chCondObjectInit(condition_variable_t *cp) {
chDbgCheck(cp != NULL); chDbgCheck(cp != NULL);
queue_init(&cp->c_queue); queue_init(&cp->queue);
} }
/** /**
@ -91,8 +91,8 @@ void chCondSignal(condition_variable_t *cp) {
chDbgCheck(cp != NULL); chDbgCheck(cp != NULL);
chSysLock(); chSysLock();
if (queue_notempty(&cp->c_queue)) { if (queue_notempty(&cp->queue)) {
chSchWakeupS(queue_fifo_remove(&cp->c_queue), MSG_OK); chSchWakeupS(queue_fifo_remove(&cp->queue), MSG_OK);
} }
chSysUnlock(); chSysUnlock();
} }
@ -113,9 +113,9 @@ void chCondSignalI(condition_variable_t *cp) {
chDbgCheckClassI(); chDbgCheckClassI();
chDbgCheck(cp != NULL); chDbgCheck(cp != NULL);
if (queue_notempty(&cp->c_queue)) { if (queue_notempty(&cp->queue)) {
thread_t *tp = queue_fifo_remove(&cp->c_queue); thread_t *tp = queue_fifo_remove(&cp->queue);
tp->p_u.rdymsg = MSG_OK; tp->u.rdymsg = MSG_OK;
(void) chSchReadyI(tp); (void) chSchReadyI(tp);
} }
} }
@ -154,8 +154,8 @@ void chCondBroadcastI(condition_variable_t *cp) {
/* Empties the condition variable queue and inserts all the threads into the /* Empties the condition variable queue and inserts all the threads into the
ready list in FIFO order. The wakeup message is set to @p MSG_RESET in ready list in FIFO order. The wakeup message is set to @p MSG_RESET in
order to make a chCondBroadcast() detectable from a chCondSignal().*/ order to make a chCondBroadcast() detectable from a chCondSignal().*/
while (queue_notempty(&cp->c_queue)) { while (queue_notempty(&cp->queue)) {
chSchReadyI(queue_fifo_remove(&cp->c_queue))->p_u.rdymsg = MSG_RESET; chSchReadyI(queue_fifo_remove(&cp->queue))->u.rdymsg = MSG_RESET;
} }
} }
@ -209,7 +209,7 @@ msg_t chCondWaitS(condition_variable_t *cp) {
chDbgCheckClassS(); chDbgCheckClassS();
chDbgCheck(cp != NULL); chDbgCheck(cp != NULL);
chDbgAssert(ctp->p_mtxlist != NULL, "not owning a mutex"); chDbgAssert(ctp->mtxlist != NULL, "not owning a mutex");
/* Getting "current" mutex and releasing it.*/ /* Getting "current" mutex and releasing it.*/
mp = chMtxGetNextMutexS(); mp = chMtxGetNextMutexS();
@ -217,10 +217,10 @@ msg_t chCondWaitS(condition_variable_t *cp) {
/* Start waiting on the condition variable, on exit the mutex is taken /* Start waiting on the condition variable, on exit the mutex is taken
again.*/ again.*/
ctp->p_u.wtobjp = cp; ctp->u.wtobjp = cp;
queue_prio_insert(ctp, &cp->c_queue); queue_prio_insert(ctp, &cp->queue);
chSchGoSleepS(CH_STATE_WTCOND); chSchGoSleepS(CH_STATE_WTCOND);
msg = ctp->p_u.rdymsg; msg = ctp->u.rdymsg;
chMtxLockS(mp); chMtxLockS(mp);
return msg; return msg;
@ -299,7 +299,7 @@ msg_t chCondWaitTimeoutS(condition_variable_t *cp, systime_t time) {
chDbgCheckClassS(); chDbgCheckClassS();
chDbgCheck((cp != NULL) && (time != TIME_IMMEDIATE)); chDbgCheck((cp != NULL) && (time != TIME_IMMEDIATE));
chDbgAssert(currp->p_mtxlist != NULL, "not owning a mutex"); chDbgAssert(currp->mtxlist != NULL, "not owning a mutex");
/* Getting "current" mutex and releasing it.*/ /* Getting "current" mutex and releasing it.*/
mp = chMtxGetNextMutexS(); mp = chMtxGetNextMutexS();
@ -307,8 +307,8 @@ msg_t chCondWaitTimeoutS(condition_variable_t *cp, systime_t time) {
/* Start waiting on the condition variable, on exit the mutex is taken /* Start waiting on the condition variable, on exit the mutex is taken
again.*/ again.*/
currp->p_u.wtobjp = cp; currp->u.wtobjp = cp;
queue_prio_insert(currp, &cp->c_queue); queue_prio_insert(currp, &cp->queue);
msg = chSchGoSleepTimeoutS(CH_STATE_WTCOND, time); msg = chSchGoSleepTimeoutS(CH_STATE_WTCOND, time);
if (msg != MSG_TIMEOUT) { if (msg != MSG_TIMEOUT) {
chMtxLockS(mp); chMtxLockS(mp);

View File

@ -101,6 +101,31 @@
/* Module local functions. */ /* Module local functions. */
/*===========================================================================*/ /*===========================================================================*/
#if (CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_NONE) || defined(__DOXYGEN__)
/**
* @brief Writes a time stamp and increases the trace buffer pointer.
*
* @notapi
*/
NOINLINE static void trace_next(void) {
ch.dbg.trace_buffer.ptr->time = chVTGetSystemTimeX();
#if PORT_SUPPORTS_RT == TRUE
ch.dbg.trace_buffer.ptr->rtstamp = chSysGetRealtimeCounterX();
#else
ch.dbg.trace_buffer.ptr->rtstamp = (rtcnt_t)0;
#endif
/* Trace hook, useful in order to interface debug tools.*/
CH_CFG_TRACE_HOOK(ch.dbg.trace_buffer.ptr);
if (++ch.dbg.trace_buffer.ptr >=
&ch.dbg.trace_buffer.buffer[CH_DBG_TRACE_BUFFER_SIZE]) {
ch.dbg.trace_buffer.ptr = &ch.dbg.trace_buffer.buffer[0];
}
}
#endif
/*===========================================================================*/ /*===========================================================================*/
/* Module exported functions. */ /* Module exported functions. */
/*===========================================================================*/ /*===========================================================================*/
@ -256,17 +281,24 @@ void chDbgCheckClassS(void) {
#endif /* CH_DBG_SYSTEM_STATE_CHECK == TRUE */ #endif /* CH_DBG_SYSTEM_STATE_CHECK == TRUE */
#if (CH_DBG_ENABLE_TRACE == TRUE) || defined(__DOXYGEN__) #if (CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_NONE) || defined(__DOXYGEN__)
/** /**
* @brief Trace circular buffer subsystem initialization. * @brief Trace circular buffer subsystem initialization.
* @note Internal use only. * @note Internal use only.
*/ */
void _dbg_trace_init(void) { void _dbg_trace_init(void) {
unsigned i;
ch.dbg.trace_buffer.tb_size = CH_DBG_TRACE_BUFFER_SIZE; ch.dbg.trace_buffer.suspended = 0U;
ch.dbg.trace_buffer.tb_ptr = &ch.dbg.trace_buffer.tb_buffer[0]; ch.dbg.trace_buffer.size = CH_DBG_TRACE_BUFFER_SIZE;
ch.dbg.trace_buffer.ptr = &ch.dbg.trace_buffer.buffer[0];
for (i = 0U; i < CH_DBG_TRACE_BUFFER_SIZE; i++) {
ch.dbg.trace_buffer.buffer[i].type = CH_TRACE_TYPE_UNUSED;
}
} }
#if ((CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_SWITCH) != 0) || \
defined(__DOXYGEN__)
/** /**
* @brief Inserts in the circular debug trace buffer a context switch record. * @brief Inserts in the circular debug trace buffer a context switch record.
* *
@ -274,17 +306,173 @@ void _dbg_trace_init(void) {
* *
* @notapi * @notapi
*/ */
void _dbg_trace(thread_t *otp) { void _dbg_trace_switch(thread_t *otp) {
ch.dbg.trace_buffer.tb_ptr->se_time = chVTGetSystemTimeX(); if ((ch.dbg.trace_buffer.suspended & CH_TRACE_SUSPEND_SWITCH) == 0U) {
ch.dbg.trace_buffer.tb_ptr->se_tp = currp; ch.dbg.trace_buffer.ptr->type = CH_TRACE_TYPE_SWITCH;
ch.dbg.trace_buffer.tb_ptr->se_wtobjp = otp->p_u.wtobjp; ch.dbg.trace_buffer.ptr->state = (uint8_t)otp->state;
ch.dbg.trace_buffer.tb_ptr->se_state = (uint8_t)otp->p_state; ch.dbg.trace_buffer.ptr->u.sw.ntp = currp;
if (++ch.dbg.trace_buffer.tb_ptr >= ch.dbg.trace_buffer.ptr->u.sw.wtobjp = otp->u.wtobjp;
&ch.dbg.trace_buffer.tb_buffer[CH_DBG_TRACE_BUFFER_SIZE]) { trace_next();
ch.dbg.trace_buffer.tb_ptr = &ch.dbg.trace_buffer.tb_buffer[0];
} }
} }
#endif /* CH_DBG_ENABLE_TRACE */ #endif /* (CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_SWITCH) != 0 */
#if ((CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_ISR) != 0) || \
defined(__DOXYGEN__)
/**
* @brief Inserts in the circular debug trace buffer an ISR-enter record.
*
* @param[in] isr name of the isr
*
* @notapi
*/
void _dbg_trace_isr_enter(const char *isr) {
if ((ch.dbg.trace_buffer.suspended & CH_TRACE_SUSPEND_ISR_ENTER) == 0U) {
port_lock_from_isr();
ch.dbg.trace_buffer.ptr->type = CH_TRACE_TYPE_ISR_ENTER;
ch.dbg.trace_buffer.ptr->state = 0U;
ch.dbg.trace_buffer.ptr->u.isr.name = isr;
trace_next();
port_unlock_from_isr();
}
}
/**
* @brief Inserts in the circular debug trace buffer an ISR-leave record.
*
* @param[in] isr name of the isr
*
* @notapi
*/
void _dbg_trace_isr_leave(const char *isr) {
if ((ch.dbg.trace_buffer.suspended & CH_TRACE_SUSPEND_ISR_LEAVE) == 0U) {
port_lock_from_isr();
ch.dbg.trace_buffer.ptr->type = CH_TRACE_TYPE_ISR_LEAVE;
ch.dbg.trace_buffer.ptr->state = 0U;
ch.dbg.trace_buffer.ptr->u.isr.name = isr;
trace_next();
port_unlock_from_isr();
}
}
#endif /* (CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_ISR) != 0 */
#if ((CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_HALT) != 0) || \
defined(__DOXYGEN__)
/**
* @brief Inserts in the circular debug trace buffer an halt record.
*
* @param[in] reason the halt error string
*
* @notapi
*/
void _dbg_trace_halt(const char *reason) {
if ((ch.dbg.trace_buffer.suspended & CH_TRACE_SUSPEND_HALT) == 0U) {
ch.dbg.trace_buffer.ptr->type = CH_TRACE_TYPE_HALT;
ch.dbg.trace_buffer.ptr->state = 0;
ch.dbg.trace_buffer.ptr->u.halt.reason = reason;
trace_next();
}
}
#endif /* (CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_HALT) != 0 */
#if ((CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_USER) != 0) || \
defined(__DOXYGEN__)
/**
* @brief Adds an user trace record to the trace buffer.
*
* @param[in] up1 user parameter 1
* @param[in] up2 user parameter 2
*
* @iclass
*/
void chDbgWriteTraceI(void *up1, void *up2) {
chDbgCheckClassI();
if ((ch.dbg.trace_buffer.suspended & CH_TRACE_SUSPEND_SWITCH) == 0U) {
ch.dbg.trace_buffer.ptr->type = CH_TRACE_TYPE_USER;
ch.dbg.trace_buffer.ptr->state = 0;
ch.dbg.trace_buffer.ptr->u.user.up1 = up1;
ch.dbg.trace_buffer.ptr->u.user.up2 = up2;
trace_next();
}
}
/**
* @brief Adds an user trace record to the trace buffer.
*
* @param[in] up1 user parameter 1
* @param[in] up2 user parameter 2
*
* @api
*/
void chDbgWriteTrace(void *up1, void *up2) {
chSysLock();
chDbgWriteTraceI(up1, up2);
chSysUnlock();
}
#endif /* (CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_USER) != 0 */
/**
* @brief Suspends one or more trace events.
*
* @paramin mask mask of the trace events to be suspended
*
* @iclass
*/
void chDbgSuspendTraceI(uint16_t mask) {
chDbgCheckClassI();
ch.dbg.trace_buffer.suspended |= mask;
}
/**
* @brief Suspends one or more trace events.
*
* @paramin mask mask of the trace events to be suspended
*
* @api
*/
void chDbgSuspendTrace(uint16_t mask) {
chSysLock();
chDbgSuspendTraceI(mask);
chSysUnlock();
}
/**
* @brief Resumes one or more trace events.
*
* @paramin mask mask of the trace events to be resumed
*
* @iclass
*/
void chDbgResumeTraceI(uint16_t mask) {
chDbgCheckClassI();
ch.dbg.trace_buffer.suspended &= ~mask;
}
/**
* @brief Resumes one or more trace events.
*
* @paramin mask mask of the trace events to be resumed
*
* @api
*/
void chDbgResumeTrace(uint16_t mask) {
chSysLock();
chDbgResumeTraceI(mask);
chSysUnlock();
}
#endif /* CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_NONE */
/** @} */ /** @} */

View File

@ -1,238 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file chdynamic.c
* @brief Dynamic threads code.
*
* @addtogroup dynamic_threads
* @details Dynamic threads related APIs and services.
* @{
*/
#include "ch.h"
#if (CH_CFG_USE_DYNAMIC == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Module local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported functions. */
/*===========================================================================*/
/**
* @brief Adds a reference to a thread object.
* @pre The configuration option @p CH_CFG_USE_DYNAMIC must be enabled in
* order to use this function.
*
* @param[in] tp pointer to the thread
* @return The same thread pointer passed as parameter
* representing the new reference.
*
* @api
*/
thread_t *chThdAddRef(thread_t *tp) {
chSysLock();
chDbgAssert(tp->p_refs < (trefs_t)255, "too many references");
tp->p_refs++;
chSysUnlock();
return tp;
}
/**
* @brief Releases a reference to a thread object.
* @details If the references counter reaches zero <b>and</b> the thread
* is in the @p CH_STATE_FINAL state then the thread's memory is
* returned to the proper allocator.
* @pre The configuration option @p CH_CFG_USE_DYNAMIC must be enabled in
* order to use this function.
* @note Static threads are not affected.
*
* @param[in] tp pointer to the thread
*
* @api
*/
void chThdRelease(thread_t *tp) {
trefs_t refs;
chSysLock();
chDbgAssert(tp->p_refs > (trefs_t)0, "not referenced");
tp->p_refs--;
refs = tp->p_refs;
chSysUnlock();
/* If the references counter reaches zero and the thread is in its
terminated state then the memory can be returned to the proper
allocator. Of course static threads are not affected.*/
if ((refs == (trefs_t)0) && (tp->p_state == CH_STATE_FINAL)) {
switch (tp->p_flags & CH_FLAG_MODE_MASK) {
#if CH_CFG_USE_HEAP == TRUE
case CH_FLAG_MODE_HEAP:
#if CH_CFG_USE_REGISTRY == TRUE
REG_REMOVE(tp);
#endif
chHeapFree(tp);
break;
#endif
#if CH_CFG_USE_MEMPOOLS == TRUE
case CH_FLAG_MODE_MPOOL:
#if CH_CFG_USE_REGISTRY == TRUE
REG_REMOVE(tp);
#endif
chPoolFree(tp->p_mpool, tp);
break;
#endif
default:
/* Nothing to do for static threads, those are removed from the
registry on exit.*/
break;
}
}
}
#if (CH_CFG_USE_HEAP == TRUE) || defined(__DOXYGEN__)
/**
* @brief Creates a new thread allocating the memory from the heap.
* @pre The configuration options @p CH_CFG_USE_DYNAMIC and
* @p CH_CFG_USE_HEAP must be enabled in order to use this function.
* @note A thread can terminate by calling @p chThdExit() or by simply
* returning from its main function.
* @note The memory allocated for the thread is not released when the thread
* terminates but when a @p chThdWait() is performed.
*
* @param[in] heapp heap from which allocate the memory or @p NULL for the
* default heap
* @param[in] size size of the working area to be allocated
* @param[in] prio the priority level for the new thread
* @param[in] pf the thread function
* @param[in] arg an argument passed to the thread function. It can be
* @p NULL.
* @return The pointer to the @p thread_t structure allocated for
* the thread into the working space area.
* @retval NULL if the memory cannot be allocated.
*
* @api
*/
thread_t *chThdCreateFromHeap(memory_heap_t *heapp, size_t size,
tprio_t prio, tfunc_t pf, void *arg) {
void *wsp;
thread_t *tp;
wsp = chHeapAlloc(heapp, size);
if (wsp == NULL) {
return NULL;
}
#if CH_DBG_FILL_THREADS == TRUE
_thread_memfill((uint8_t *)wsp,
(uint8_t *)wsp + sizeof(thread_t),
CH_DBG_THREAD_FILL_VALUE);
_thread_memfill((uint8_t *)wsp + sizeof(thread_t),
(uint8_t *)wsp + size,
CH_DBG_STACK_FILL_VALUE);
#endif
chSysLock();
tp = chThdCreateI(wsp, size, prio, pf, arg);
tp->p_flags = CH_FLAG_MODE_HEAP;
chSchWakeupS(tp, MSG_OK);
chSysUnlock();
return tp;
}
#endif /* CH_CFG_USE_HEAP == TRUE */
#if (CH_CFG_USE_MEMPOOLS == TRUE) || defined(__DOXYGEN__)
/**
* @brief Creates a new thread allocating the memory from the specified
* memory pool.
* @pre The configuration options @p CH_CFG_USE_DYNAMIC and
* @p CH_CFG_USE_MEMPOOLS must be enabled in order to use this
* function.
* @note A thread can terminate by calling @p chThdExit() or by simply
* returning from its main function.
* @note The memory allocated for the thread is not released when the thread
* terminates but when a @p chThdWait() is performed.
*
* @param[in] mp pointer to the memory pool object
* @param[in] prio the priority level for the new thread
* @param[in] pf the thread function
* @param[in] arg an argument passed to the thread function. It can be
* @p NULL.
* @return The pointer to the @p thread_t structure allocated for
* the thread into the working space area.
* @retval NULL if the memory pool is empty.
*
* @api
*/
thread_t *chThdCreateFromMemoryPool(memory_pool_t *mp, tprio_t prio,
tfunc_t pf, void *arg) {
void *wsp;
thread_t *tp;
chDbgCheck(mp != NULL);
wsp = chPoolAlloc(mp);
if (wsp == NULL) {
return NULL;
}
#if CH_DBG_FILL_THREADS == TRUE
_thread_memfill((uint8_t *)wsp,
(uint8_t *)wsp + sizeof(thread_t),
CH_DBG_THREAD_FILL_VALUE);
_thread_memfill((uint8_t *)wsp + sizeof(thread_t),
(uint8_t *)wsp + mp->mp_object_size,
CH_DBG_STACK_FILL_VALUE);
#endif
chSysLock();
tp = chThdCreateI(wsp, mp->mp_object_size, prio, pf, arg);
tp->p_flags = CH_FLAG_MODE_MPOOL;
tp->p_mpool = mp;
chSchWakeupS(tp, MSG_OK);
chSysUnlock();
return tp;
}
#endif /* CH_CFG_USE_MEMPOOLS == TRUE */
#endif /* CH_CFG_USE_DYNAMIC == TRUE */
/** @} */

View File

@ -108,12 +108,12 @@ void chEvtRegisterMaskWithFlags(event_source_t *esp,
chDbgCheck((esp != NULL) && (elp != NULL)); chDbgCheck((esp != NULL) && (elp != NULL));
chSysLock(); chSysLock();
elp->el_next = esp->es_next; elp->next = esp->next;
esp->es_next = elp; esp->next = elp;
elp->el_listener = currp; elp->listener = currp;
elp->el_events = events; elp->events = events;
elp->el_flags = (eventflags_t)0; elp->flags = (eventflags_t)0;
elp->el_wflags = wflags; elp->wflags = wflags;
chSysUnlock(); chSysUnlock();
} }
@ -140,13 +140,13 @@ void chEvtUnregister(event_source_t *esp, event_listener_t *elp) {
/*lint -restore*/ /*lint -restore*/
chSysLock(); chSysLock();
/*lint -save -e9087 -e740 [11.3, 1.3] Cast required by list handling.*/ /*lint -save -e9087 -e740 [11.3, 1.3] Cast required by list handling.*/
while (p->el_next != (event_listener_t *)esp) { while (p->next != (event_listener_t *)esp) {
/*lint -restore*/ /*lint -restore*/
if (p->el_next == elp) { if (p->next == elp) {
p->el_next = elp->el_next; p->next = elp->next;
break; break;
} }
p = p->el_next; p = p->next;
} }
chSysUnlock(); chSysUnlock();
} }
@ -163,8 +163,8 @@ eventmask_t chEvtGetAndClearEvents(eventmask_t events) {
eventmask_t m; eventmask_t m;
chSysLock(); chSysLock();
m = currp->p_epending & events; m = currp->epending & events;
currp->p_epending &= ~events; currp->epending &= ~events;
chSysUnlock(); chSysUnlock();
return m; return m;
@ -182,8 +182,8 @@ eventmask_t chEvtGetAndClearEvents(eventmask_t events) {
eventmask_t chEvtAddEvents(eventmask_t events) { eventmask_t chEvtAddEvents(eventmask_t events) {
chSysLock(); chSysLock();
currp->p_epending |= events; currp->epending |= events;
events = currp->p_epending; events = currp->epending;
chSysUnlock(); chSysUnlock();
return events; return events;
@ -212,18 +212,18 @@ void chEvtBroadcastFlagsI(event_source_t *esp, eventflags_t flags) {
chDbgCheckClassI(); chDbgCheckClassI();
chDbgCheck(esp != NULL); chDbgCheck(esp != NULL);
elp = esp->es_next; elp = esp->next;
/*lint -save -e9087 -e740 [11.3, 1.3] Cast required by list handling.*/ /*lint -save -e9087 -e740 [11.3, 1.3] Cast required by list handling.*/
while (elp != (event_listener_t *)esp) { while (elp != (event_listener_t *)esp) {
/*lint -restore*/ /*lint -restore*/
elp->el_flags |= flags; elp->flags |= flags;
/* When flags == 0 the thread will always be signaled because the /* When flags == 0 the thread will always be signaled because the
source does not emit any flag.*/ source does not emit any flag.*/
if ((flags == (eventflags_t)0) || if ((flags == (eventflags_t)0) ||
((elp->el_flags & elp->el_wflags) != (eventflags_t)0)) { ((elp->flags & elp->wflags) != (eventflags_t)0)) {
chEvtSignalI(elp->el_listener, elp->el_events); chEvtSignalI(elp->listener, elp->events);
} }
elp = elp->el_next; elp = elp->next;
} }
} }
@ -242,8 +242,8 @@ eventflags_t chEvtGetAndClearFlags(event_listener_t *elp) {
eventflags_t flags; eventflags_t flags;
chSysLock(); chSysLock();
flags = elp->el_flags; flags = elp->flags;
elp->el_flags = (eventflags_t)0; elp->flags = (eventflags_t)0;
chSysUnlock(); chSysUnlock();
return flags; return flags;
@ -284,13 +284,13 @@ void chEvtSignalI(thread_t *tp, eventmask_t events) {
chDbgCheckClassI(); chDbgCheckClassI();
chDbgCheck(tp != NULL); chDbgCheck(tp != NULL);
tp->p_epending |= events; tp->epending |= events;
/* Test on the AND/OR conditions wait states.*/ /* Test on the AND/OR conditions wait states.*/
if (((tp->p_state == CH_STATE_WTOREVT) && if (((tp->state == CH_STATE_WTOREVT) &&
((tp->p_epending & tp->p_u.ewmask) != (eventmask_t)0)) || ((tp->epending & tp->u.ewmask) != (eventmask_t)0)) ||
((tp->p_state == CH_STATE_WTANDEVT) && ((tp->state == CH_STATE_WTANDEVT) &&
((tp->p_epending & tp->p_u.ewmask) == tp->p_u.ewmask))) { ((tp->epending & tp->u.ewmask) == tp->u.ewmask))) {
tp->p_u.rdymsg = MSG_OK; tp->u.rdymsg = MSG_OK;
(void) chSchReadyI(tp); (void) chSchReadyI(tp);
} }
} }
@ -330,8 +330,8 @@ void chEvtBroadcastFlags(event_source_t *esp, eventflags_t flags) {
eventflags_t chEvtGetAndClearFlagsI(event_listener_t *elp) { eventflags_t chEvtGetAndClearFlagsI(event_listener_t *elp) {
eventflags_t flags; eventflags_t flags;
flags = elp->el_flags; flags = elp->flags;
elp->el_flags = (eventflags_t)0; elp->flags = (eventflags_t)0;
return flags; return flags;
} }
@ -385,14 +385,14 @@ eventmask_t chEvtWaitOne(eventmask_t events) {
eventmask_t m; eventmask_t m;
chSysLock(); chSysLock();
m = ctp->p_epending & events; m = ctp->epending & events;
if (m == (eventmask_t)0) { if (m == (eventmask_t)0) {
ctp->p_u.ewmask = events; ctp->u.ewmask = events;
chSchGoSleepS(CH_STATE_WTOREVT); chSchGoSleepS(CH_STATE_WTOREVT);
m = ctp->p_epending & events; m = ctp->epending & events;
} }
m ^= m & (m - (eventmask_t)1); m ^= m & (m - (eventmask_t)1);
ctp->p_epending &= ~m; ctp->epending &= ~m;
chSysUnlock(); chSysUnlock();
return m; return m;
@ -415,13 +415,13 @@ eventmask_t chEvtWaitAny(eventmask_t events) {
eventmask_t m; eventmask_t m;
chSysLock(); chSysLock();
m = ctp->p_epending & events; m = ctp->epending & events;
if (m == (eventmask_t)0) { if (m == (eventmask_t)0) {
ctp->p_u.ewmask = events; ctp->u.ewmask = events;
chSchGoSleepS(CH_STATE_WTOREVT); chSchGoSleepS(CH_STATE_WTOREVT);
m = ctp->p_epending & events; m = ctp->epending & events;
} }
ctp->p_epending &= ~m; ctp->epending &= ~m;
chSysUnlock(); chSysUnlock();
return m; return m;
@ -442,11 +442,11 @@ eventmask_t chEvtWaitAll(eventmask_t events) {
thread_t *ctp = currp; thread_t *ctp = currp;
chSysLock(); chSysLock();
if ((ctp->p_epending & events) != events) { if ((ctp->epending & events) != events) {
ctp->p_u.ewmask = events; ctp->u.ewmask = events;
chSchGoSleepS(CH_STATE_WTANDEVT); chSchGoSleepS(CH_STATE_WTANDEVT);
} }
ctp->p_epending &= ~events; ctp->epending &= ~events;
chSysUnlock(); chSysUnlock();
return events; return events;
@ -481,21 +481,21 @@ eventmask_t chEvtWaitOneTimeout(eventmask_t events, systime_t time) {
eventmask_t m; eventmask_t m;
chSysLock(); chSysLock();
m = ctp->p_epending & events; m = ctp->epending & events;
if (m == (eventmask_t)0) { if (m == (eventmask_t)0) {
if (TIME_IMMEDIATE == time) { if (TIME_IMMEDIATE == time) {
chSysUnlock(); chSysUnlock();
return (eventmask_t)0; return (eventmask_t)0;
} }
ctp->p_u.ewmask = events; ctp->u.ewmask = events;
if (chSchGoSleepTimeoutS(CH_STATE_WTOREVT, time) < MSG_OK) { if (chSchGoSleepTimeoutS(CH_STATE_WTOREVT, time) < MSG_OK) {
chSysUnlock(); chSysUnlock();
return (eventmask_t)0; return (eventmask_t)0;
} }
m = ctp->p_epending & events; m = ctp->epending & events;
} }
m ^= m & (m - (eventmask_t)1); m ^= m & (m - (eventmask_t)1);
ctp->p_epending &= ~m; ctp->epending &= ~m;
chSysUnlock(); chSysUnlock();
return m; return m;
@ -524,20 +524,20 @@ eventmask_t chEvtWaitAnyTimeout(eventmask_t events, systime_t time) {
eventmask_t m; eventmask_t m;
chSysLock(); chSysLock();
m = ctp->p_epending & events; m = ctp->epending & events;
if (m == (eventmask_t)0) { if (m == (eventmask_t)0) {
if (TIME_IMMEDIATE == time) { if (TIME_IMMEDIATE == time) {
chSysUnlock(); chSysUnlock();
return (eventmask_t)0; return (eventmask_t)0;
} }
ctp->p_u.ewmask = events; ctp->u.ewmask = events;
if (chSchGoSleepTimeoutS(CH_STATE_WTOREVT, time) < MSG_OK) { if (chSchGoSleepTimeoutS(CH_STATE_WTOREVT, time) < MSG_OK) {
chSysUnlock(); chSysUnlock();
return (eventmask_t)0; return (eventmask_t)0;
} }
m = ctp->p_epending & events; m = ctp->epending & events;
} }
ctp->p_epending &= ~m; ctp->epending &= ~m;
chSysUnlock(); chSysUnlock();
return m; return m;
@ -564,18 +564,18 @@ eventmask_t chEvtWaitAllTimeout(eventmask_t events, systime_t time) {
thread_t *ctp = currp; thread_t *ctp = currp;
chSysLock(); chSysLock();
if ((ctp->p_epending & events) != events) { if ((ctp->epending & events) != events) {
if (TIME_IMMEDIATE == time) { if (TIME_IMMEDIATE == time) {
chSysUnlock(); chSysUnlock();
return (eventmask_t)0; return (eventmask_t)0;
} }
ctp->p_u.ewmask = events; ctp->u.ewmask = events;
if (chSchGoSleepTimeoutS(CH_STATE_WTANDEVT, time) < MSG_OK) { if (chSchGoSleepTimeoutS(CH_STATE_WTANDEVT, time) < MSG_OK) {
chSysUnlock(); chSysUnlock();
return (eventmask_t)0; return (eventmask_t)0;
} }
} }
ctp->p_epending &= ~events; ctp->epending &= ~events;
chSysUnlock(); chSysUnlock();
return events; return events;

View File

@ -1,294 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file chheap.c
* @brief Heaps code.
*
* @addtogroup heaps
* @details Heap Allocator related APIs.
* <h2>Operation mode</h2>
* The heap allocator implements a first-fit strategy and its APIs
* are functionally equivalent to the usual @p malloc() and @p free()
* library functions. The main difference is that the OS heap APIs
* are guaranteed to be thread safe.<br>
* @pre In order to use the heap APIs the @p CH_CFG_USE_HEAP option must
* be enabled in @p chconf.h.
* @{
*/
#include "ch.h"
#if (CH_CFG_USE_HEAP == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Module local definitions. */
/*===========================================================================*/
/*
* Defaults on the best synchronization mechanism available.
*/
#if (CH_CFG_USE_MUTEXES == TRUE) || defined(__DOXYGEN__)
#define H_LOCK(h) chMtxLock(&(h)->h_mtx)
#define H_UNLOCK(h) chMtxUnlock(&(h)->h_mtx)
#else
#define H_LOCK(h) (void) chSemWait(&(h)->h_sem)
#define H_UNLOCK(h) chSemSignal(&(h)->h_sem)
#endif
#define LIMIT(p) \
/*lint -save -e9087 [11.3] Safe cast.*/ \
(union heap_header *)((uint8_t *)(p) + \
sizeof(union heap_header) + (p)->h.size) \
/*lint -restore*/
/*===========================================================================*/
/* Module exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local variables. */
/*===========================================================================*/
/**
* @brief Default heap descriptor.
*/
static memory_heap_t default_heap;
/*===========================================================================*/
/* Module local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported functions. */
/*===========================================================================*/
/**
* @brief Initializes the default heap.
*
* @notapi
*/
void _heap_init(void) {
default_heap.h_provider = chCoreAlloc;
default_heap.h_free.h.u.next = NULL;
default_heap.h_free.h.size = 0;
#if (CH_CFG_USE_MUTEXES == TRUE) || defined(__DOXYGEN__)
chMtxObjectInit(&default_heap.h_mtx);
#else
chSemObjectInit(&default_heap.h_sem, (cnt_t)1);
#endif
}
/**
* @brief Initializes a memory heap from a static memory area.
* @pre Both the heap buffer base and the heap size must be aligned to
* the @p stkalign_t type size.
*
* @param[out] heapp pointer to the memory heap descriptor to be initialized
* @param[in] buf heap buffer base
* @param[in] size heap size
*
* @init
*/
void chHeapObjectInit(memory_heap_t *heapp, void *buf, size_t size) {
union heap_header *hp = buf;
chDbgCheck(MEM_IS_ALIGNED(buf) && MEM_IS_ALIGNED(size));
heapp->h_provider = NULL;
heapp->h_free.h.u.next = hp;
heapp->h_free.h.size = 0;
hp->h.u.next = NULL;
hp->h.size = size - sizeof(union heap_header);
#if (CH_CFG_USE_MUTEXES == TRUE) || defined(__DOXYGEN__)
chMtxObjectInit(&heapp->h_mtx);
#else
chSemObjectInit(&heapp->h_sem, (cnt_t)1);
#endif
}
/**
* @brief Allocates a block of memory from the heap by using the first-fit
* algorithm.
* @details The allocated block is guaranteed to be properly aligned for a
* pointer data type (@p stkalign_t).
*
* @param[in] heapp pointer to a heap descriptor or @p NULL in order to
* access the default heap.
* @param[in] size the size of the block to be allocated. Note that the
* allocated block may be a bit bigger than the requested
* size for alignment and fragmentation reasons.
* @return A pointer to the allocated block.
* @retval NULL if the block cannot be allocated.
*
* @api
*/
void *chHeapAlloc(memory_heap_t *heapp, size_t size) {
union heap_header *qp, *hp, *fp;
if (heapp == NULL) {
heapp = &default_heap;
}
size = MEM_ALIGN_NEXT(size);
qp = &heapp->h_free;
H_LOCK(heapp);
while (qp->h.u.next != NULL) {
hp = qp->h.u.next;
if (hp->h.size >= size) {
if (hp->h.size < (size + sizeof(union heap_header))) {
/* Gets the whole block even if it is slightly bigger than the
requested size because the fragment would be too small to be
useful.*/
qp->h.u.next = hp->h.u.next;
}
else {
/* Block bigger enough, must split it.*/
/*lint -save -e9087 [11.3] Safe cast.*/
fp = (void *)((uint8_t *)(hp) + sizeof(union heap_header) + size);
/*lint -restore*/
fp->h.u.next = hp->h.u.next;
fp->h.size = (hp->h.size - sizeof(union heap_header)) - size;
qp->h.u.next = fp;
hp->h.size = size;
}
hp->h.u.heap = heapp;
H_UNLOCK(heapp);
/*lint -save -e9087 [11.3] Safe cast.*/
return (void *)(hp + 1);
/*lint -restore*/
}
qp = hp;
}
H_UNLOCK(heapp);
/* More memory is required, tries to get it from the associated provider
else fails.*/
if (heapp->h_provider != NULL) {
hp = heapp->h_provider(size + sizeof(union heap_header));
if (hp != NULL) {
hp->h.u.heap = heapp;
hp->h.size = size;
hp++;
/*lint -save -e9087 [11.3] Safe cast.*/
return (void *)hp;
/*lint -restore*/
}
}
return NULL;
}
/**
* @brief Frees a previously allocated memory block.
*
* @param[in] p pointer to the memory block to be freed
*
* @api
*/
void chHeapFree(void *p) {
union heap_header *qp, *hp;
memory_heap_t *heapp;
chDbgCheck(p != NULL);
/*lint -save -e9087 [11.3] Safe cast.*/
hp = (union heap_header *)p - 1;
/*lint -restore*/
heapp = hp->h.u.heap;
qp = &heapp->h_free;
H_LOCK(heapp);
while (true) {
chDbgAssert((hp < qp) || (hp >= LIMIT(qp)), "within free block");
if (((qp == &heapp->h_free) || (hp > qp)) &&
((qp->h.u.next == NULL) || (hp < qp->h.u.next))) {
/* Insertion after qp.*/
hp->h.u.next = qp->h.u.next;
qp->h.u.next = hp;
/* Verifies if the newly inserted block should be merged.*/
if (LIMIT(hp) == hp->h.u.next) {
/* Merge with the next block.*/
hp->h.size += hp->h.u.next->h.size + sizeof(union heap_header);
hp->h.u.next = hp->h.u.next->h.u.next;
}
if ((LIMIT(qp) == hp)) {
/* Merge with the previous block.*/
qp->h.size += hp->h.size + sizeof(union heap_header);
qp->h.u.next = hp->h.u.next;
}
break;
}
qp = qp->h.u.next;
}
H_UNLOCK(heapp);
return;
}
/**
* @brief Reports the heap status.
* @note This function is meant to be used in the test suite, it should
* not be really useful for the application code.
*
* @param[in] heapp pointer to a heap descriptor or @p NULL in order to
* access the default heap.
* @param[in] sizep pointer to a variable that will receive the total
* fragmented free space
* @return The number of fragments in the heap.
*
* @api
*/
size_t chHeapStatus(memory_heap_t *heapp, size_t *sizep) {
union heap_header *qp;
size_t n, sz;
if (heapp == NULL) {
heapp = &default_heap;
}
H_LOCK(heapp);
sz = 0;
n = 0;
qp = &heapp->h_free;
while (qp->h.u.next != NULL) {
sz += qp->h.u.next->h.size;
n++;
qp = qp->h.u.next;
}
if (sizep != NULL) {
*sizep = sz;
}
H_UNLOCK(heapp);
return n;
}
#endif /* CH_CFG_USE_HEAP == TRUE */
/** @} */

View File

@ -1,434 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file chmboxes.c
* @brief Mailboxes code.
*
* @addtogroup mailboxes
* @details Asynchronous messages.
* <h2>Operation mode</h2>
* A mailbox is an asynchronous communication mechanism.<br>
* Operations defined for mailboxes:
* - <b>Post</b>: Posts a message on the mailbox in FIFO order.
* - <b>Post Ahead</b>: Posts a message on the mailbox with urgent
* priority.
* - <b>Fetch</b>: A message is fetched from the mailbox and removed
* from the queue.
* - <b>Reset</b>: The mailbox is emptied and all the stored messages
* are lost.
* .
* A message is a variable of type msg_t that is guaranteed to have
* the same size of and be compatible with (data) pointers (anyway an
* explicit cast is needed).
* If larger messages need to be exchanged then a pointer to a
* structure can be posted in the mailbox but the posting side has
* no predefined way to know when the message has been processed. A
* possible approach is to allocate memory (from a memory pool for
* example) from the posting side and free it on the fetching side.
* Another approach is to set a "done" flag into the structure pointed
* by the message.
* @pre In order to use the mailboxes APIs the @p CH_CFG_USE_MAILBOXES option
* must be enabled in @p chconf.h.
* @{
*/
#include "ch.h"
#if (CH_CFG_USE_MAILBOXES == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Module exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported functions. */
/*===========================================================================*/
/**
* @brief Initializes a @p mailbox_t object.
*
* @param[out] mbp the pointer to the @p mailbox_t structure to be
* initialized
* @param[in] buf pointer to the messages buffer as an array of @p msg_t
* @param[in] n number of elements in the buffer array
*
* @init
*/
void chMBObjectInit(mailbox_t *mbp, msg_t *buf, cnt_t n) {
chDbgCheck((mbp != NULL) && (buf != NULL) && (n > (cnt_t)0));
mbp->mb_buffer = buf;
mbp->mb_rdptr = buf;
mbp->mb_wrptr = buf;
mbp->mb_top = &buf[n];
chSemObjectInit(&mbp->mb_emptysem, n);
chSemObjectInit(&mbp->mb_fullsem, (cnt_t)0);
}
/**
* @brief Resets a @p mailbox_t object.
* @details All the waiting threads are resumed with status @p MSG_RESET and
* the queued messages are lost.
*
* @param[in] mbp the pointer to an initialized @p mailbox_t object
*
* @api
*/
void chMBReset(mailbox_t *mbp) {
chSysLock();
chMBResetI(mbp);
chSchRescheduleS();
chSysUnlock();
}
/**
* @brief Resets a @p mailbox_t object.
* @details All the waiting threads are resumed with status @p MSG_RESET and
* the queued messages are lost.
*
* @param[in] mbp the pointer to an initialized @p mailbox_t object
*
* @api
*/
void chMBResetI(mailbox_t *mbp) {
chDbgCheckClassI();
chDbgCheck(mbp != NULL);
mbp->mb_wrptr = mbp->mb_buffer;
mbp->mb_rdptr = mbp->mb_buffer;
chSemResetI(&mbp->mb_emptysem, (cnt_t)(mbp->mb_top - mbp->mb_buffer));
chSemResetI(&mbp->mb_fullsem, (cnt_t)0);
}
/**
* @brief Posts a message into a mailbox.
* @details The invoking thread waits until a empty slot in the mailbox becomes
* available or the specified time runs out.
*
* @param[in] mbp the pointer to an initialized @p mailbox_t object
* @param[in] msg the message to be posted on the mailbox
* @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 operation status.
* @retval MSG_OK if a message has been correctly posted.
* @retval MSG_RESET if the mailbox has been reset while waiting.
* @retval MSG_TIMEOUT if the operation has timed out.
*
* @api
*/
msg_t chMBPost(mailbox_t *mbp, msg_t msg, systime_t timeout) {
msg_t rdymsg;
chSysLock();
rdymsg = chMBPostS(mbp, msg, timeout);
chSysUnlock();
return rdymsg;
}
/**
* @brief Posts a message into a mailbox.
* @details The invoking thread waits until a empty slot in the mailbox becomes
* available or the specified time runs out.
*
* @param[in] mbp the pointer to an initialized @p mailbox_t object
* @param[in] msg the message to be posted on the mailbox
* @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 operation status.
* @retval MSG_OK if a message has been correctly posted.
* @retval MSG_RESET if the mailbox has been reset while waiting.
* @retval MSG_TIMEOUT if the operation has timed out.
*
* @sclass
*/
msg_t chMBPostS(mailbox_t *mbp, msg_t msg, systime_t timeout) {
msg_t rdymsg;
chDbgCheckClassS();
chDbgCheck(mbp != NULL);
rdymsg = chSemWaitTimeoutS(&mbp->mb_emptysem, timeout);
if (rdymsg == MSG_OK) {
*mbp->mb_wrptr++ = msg;
if (mbp->mb_wrptr >= mbp->mb_top) {
mbp->mb_wrptr = mbp->mb_buffer;
}
chSemSignalI(&mbp->mb_fullsem);
chSchRescheduleS();
}
return rdymsg;
}
/**
* @brief Posts a message into a mailbox.
* @details This variant is non-blocking, the function returns a timeout
* condition if the queue is full.
*
* @param[in] mbp the pointer to an initialized @p mailbox_t object
* @param[in] msg the message to be posted on the mailbox
* @return The operation status.
* @retval MSG_OK if a message has been correctly posted.
* @retval MSG_TIMEOUT if the mailbox is full and the message cannot be
* posted.
*
* @iclass
*/
msg_t chMBPostI(mailbox_t *mbp, msg_t msg) {
chDbgCheckClassI();
chDbgCheck(mbp != NULL);
if (chSemGetCounterI(&mbp->mb_emptysem) <= (cnt_t)0) {
return MSG_TIMEOUT;
}
chSemFastWaitI(&mbp->mb_emptysem);
*mbp->mb_wrptr++ = msg;
if (mbp->mb_wrptr >= mbp->mb_top) {
mbp->mb_wrptr = mbp->mb_buffer;
}
chSemSignalI(&mbp->mb_fullsem);
return MSG_OK;
}
/**
* @brief Posts an high priority message into a mailbox.
* @details The invoking thread waits until a empty slot in the mailbox becomes
* available or the specified time runs out.
*
* @param[in] mbp the pointer to an initialized @p mailbox_t object
* @param[in] msg the message to be posted on the mailbox
* @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 operation status.
* @retval MSG_OK if a message has been correctly posted.
* @retval MSG_RESET if the mailbox has been reset while waiting.
* @retval MSG_TIMEOUT if the operation has timed out.
*
* @api
*/
msg_t chMBPostAhead(mailbox_t *mbp, msg_t msg, systime_t timeout) {
msg_t rdymsg;
chSysLock();
rdymsg = chMBPostAheadS(mbp, msg, timeout);
chSysUnlock();
return rdymsg;
}
/**
* @brief Posts an high priority message into a mailbox.
* @details The invoking thread waits until a empty slot in the mailbox becomes
* available or the specified time runs out.
*
* @param[in] mbp the pointer to an initialized @p mailbox_t object
* @param[in] msg the message to be posted on the mailbox
* @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 operation status.
* @retval MSG_OK if a message has been correctly posted.
* @retval MSG_RESET if the mailbox has been reset while waiting.
* @retval MSG_TIMEOUT if the operation has timed out.
*
* @sclass
*/
msg_t chMBPostAheadS(mailbox_t *mbp, msg_t msg, systime_t timeout) {
msg_t rdymsg;
chDbgCheckClassS();
chDbgCheck(mbp != NULL);
rdymsg = chSemWaitTimeoutS(&mbp->mb_emptysem, timeout);
if (rdymsg == MSG_OK) {
if (--mbp->mb_rdptr < mbp->mb_buffer) {
mbp->mb_rdptr = mbp->mb_top - 1;
}
*mbp->mb_rdptr = msg;
chSemSignalI(&mbp->mb_fullsem);
chSchRescheduleS();
}
return rdymsg;
}
/**
* @brief Posts an high priority message into a mailbox.
* @details This variant is non-blocking, the function returns a timeout
* condition if the queue is full.
*
* @param[in] mbp the pointer to an initialized @p mailbox_t object
* @param[in] msg the message to be posted on the mailbox
* @return The operation status.
* @retval MSG_OK if a message has been correctly posted.
* @retval MSG_TIMEOUT if the mailbox is full and the message cannot be
* posted.
*
* @iclass
*/
msg_t chMBPostAheadI(mailbox_t *mbp, msg_t msg) {
chDbgCheckClassI();
chDbgCheck(mbp != NULL);
if (chSemGetCounterI(&mbp->mb_emptysem) <= (cnt_t)0) {
return MSG_TIMEOUT;
}
chSemFastWaitI(&mbp->mb_emptysem);
if (--mbp->mb_rdptr < mbp->mb_buffer) {
mbp->mb_rdptr = mbp->mb_top - 1;
}
*mbp->mb_rdptr = msg;
chSemSignalI(&mbp->mb_fullsem);
return MSG_OK;
}
/**
* @brief Retrieves a message from a mailbox.
* @details The invoking thread waits until a message is posted in the mailbox
* or the specified time runs out.
*
* @param[in] mbp the pointer to an initialized @p mailbox_t object
* @param[out] msgp pointer to a message variable for the received message
* @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 operation status.
* @retval MSG_OK if a message has been correctly fetched.
* @retval MSG_RESET if the mailbox has been reset while waiting.
* @retval MSG_TIMEOUT if the operation has timed out.
*
* @api
*/
msg_t chMBFetch(mailbox_t *mbp, msg_t *msgp, systime_t timeout) {
msg_t rdymsg;
chSysLock();
rdymsg = chMBFetchS(mbp, msgp, timeout);
chSysUnlock();
return rdymsg;
}
/**
* @brief Retrieves a message from a mailbox.
* @details The invoking thread waits until a message is posted in the mailbox
* or the specified time runs out.
*
* @param[in] mbp the pointer to an initialized @p mailbox_t object
* @param[out] msgp pointer to a message variable for the received message
* @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 operation status.
* @retval MSG_OK if a message has been correctly fetched.
* @retval MSG_RESET if the mailbox has been reset while waiting.
* @retval MSG_TIMEOUT if the operation has timed out.
*
* @sclass
*/
msg_t chMBFetchS(mailbox_t *mbp, msg_t *msgp, systime_t timeout) {
msg_t rdymsg;
chDbgCheckClassS();
chDbgCheck((mbp != NULL) && (msgp != NULL));
rdymsg = chSemWaitTimeoutS(&mbp->mb_fullsem, timeout);
if (rdymsg == MSG_OK) {
*msgp = *mbp->mb_rdptr++;
if (mbp->mb_rdptr >= mbp->mb_top) {
mbp->mb_rdptr = mbp->mb_buffer;
}
chSemSignalI(&mbp->mb_emptysem);
chSchRescheduleS();
}
return rdymsg;
}
/**
* @brief Retrieves a message from a mailbox.
* @details This variant is non-blocking, the function returns a timeout
* condition if the queue is empty.
*
* @param[in] mbp the pointer to an initialized @p mailbox_t object
* @param[out] msgp pointer to a message variable for the received message
* @return The operation status.
* @retval MSG_OK if a message has been correctly fetched.
* @retval MSG_TIMEOUT if the mailbox is empty and a message cannot be
* fetched.
*
* @iclass
*/
msg_t chMBFetchI(mailbox_t *mbp, msg_t *msgp) {
chDbgCheckClassI();
chDbgCheck((mbp != NULL) && (msgp != NULL));
if (chSemGetCounterI(&mbp->mb_fullsem) <= (cnt_t)0) {
return MSG_TIMEOUT;
}
chSemFastWaitI(&mbp->mb_fullsem);
*msgp = *mbp->mb_rdptr++;
if (mbp->mb_rdptr >= mbp->mb_top) {
mbp->mb_rdptr = mbp->mb_buffer;
}
chSemSignalI(&mbp->mb_emptysem);
return MSG_OK;
}
#endif /* CH_CFG_USE_MAILBOXES == TRUE */
/** @} */

View File

@ -1,163 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file chmemcore.c
* @brief Core memory manager code.
*
* @addtogroup memcore
* @details Core Memory Manager related APIs and services.
* <h2>Operation mode</h2>
* The core memory manager is a simplified allocator that only
* allows to allocate memory blocks without the possibility to
* free them.<br>
* This allocator is meant as a memory blocks provider for the
* other allocators such as:
* - C-Runtime allocator (through a compiler specific adapter module).
* - Heap allocator (see @ref heaps).
* - Memory pools allocator (see @ref pools).
* .
* By having a centralized memory provider the various allocators
* can coexist and share the main memory.<br>
* This allocator, alone, is also useful for very simple
* applications that just require a simple way to get memory
* blocks.
* @pre In order to use the core memory manager APIs the @p CH_CFG_USE_MEMCORE
* option must be enabled in @p chconf.h.
* @{
*/
#include "ch.h"
#if (CH_CFG_USE_MEMCORE == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Module exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local variables. */
/*===========================================================================*/
static uint8_t *nextmem;
static uint8_t *endmem;
/*===========================================================================*/
/* Module local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported functions. */
/*===========================================================================*/
/**
* @brief Low level memory manager initialization.
*
* @notapi
*/
void _core_init(void) {
#if CH_CFG_MEMCORE_SIZE == 0
extern uint8_t __heap_base__[];
extern uint8_t __heap_end__[];
/*lint -save -e9033 [10.8] Required cast operations.*/
nextmem = (uint8_t *)MEM_ALIGN_NEXT(__heap_base__);
endmem = (uint8_t *)MEM_ALIGN_PREV(__heap_end__);
/*lint restore*/
#else
static stkalign_t buffer[MEM_ALIGN_NEXT(CH_CFG_MEMCORE_SIZE) /
MEM_ALIGN_SIZE];
nextmem = (uint8_t *)&buffer[0];
endmem = (uint8_t *)&buffer[MEM_ALIGN_NEXT(CH_CFG_MEMCORE_SIZE) /
MEM_ALIGN_SIZE];
#endif
}
/**
* @brief Allocates a memory block.
* @details The size of the returned block is aligned to the alignment
* type so it is not possible to allocate less
* than <code>MEM_ALIGN_SIZE</code>.
*
* @param[in] size the size of the block to be allocated
* @return A pointer to the allocated memory block.
* @retval NULL allocation failed, core memory exhausted.
*
* @api
*/
void *chCoreAlloc(size_t size) {
void *p;
chSysLock();
p = chCoreAllocI(size);
chSysUnlock();
return p;
}
/**
* @brief Allocates a memory block.
* @details The size of the returned block is aligned to the alignment
* type so it is not possible to allocate less than
* <code>MEM_ALIGN_SIZE</code>.
*
* @param[in] size the size of the block to be allocated.
* @return A pointer to the allocated memory block.
* @retval NULL allocation failed, core memory exhausted.
*
* @iclass
*/
void *chCoreAllocI(size_t size) {
void *p;
chDbgCheckClassI();
size = MEM_ALIGN_NEXT(size);
/*lint -save -e9033 [10.8] The cast is safe.*/
if ((size_t)(endmem - nextmem) < size) {
/*lint -restore*/
return NULL;
}
p = nextmem;
nextmem += size;
return p;
}
/**
* @brief Core memory status.
*
* @return The size, in bytes, of the free core memory.
*
* @xclass
*/
size_t chCoreGetStatusX(void) {
/*lint -save -e9033 [10.8] The cast is safe.*/
return (size_t)(endmem - nextmem);
/*lint -restore*/
}
#endif /* CH_CFG_USE_MEMCORE == TRUE */
/** @} */

View File

@ -1,202 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file chmempools.c
* @brief Memory Pools code.
*
* @addtogroup pools
* @details Memory Pools related APIs and services.
* <h2>Operation mode</h2>
* The Memory Pools APIs allow to allocate/free fixed size objects in
* <b>constant time</b> and reliably without memory fragmentation
* problems.<br>
* Memory Pools do not enforce any alignment constraint on the
* contained object however the objects must be properly aligned
* to contain a pointer to void.
* @pre In order to use the memory pools APIs the @p CH_CFG_USE_MEMPOOLS option
* must be enabled in @p chconf.h.
* @{
*/
#include "ch.h"
#if (CH_CFG_USE_MEMPOOLS == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Module exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported functions. */
/*===========================================================================*/
/**
* @brief Initializes an empty memory pool.
*
* @param[out] mp pointer to a @p memory_pool_t structure
* @param[in] size the size of the objects contained in this memory pool,
* the minimum accepted size is the size of a pointer to
* void.
* @param[in] provider memory provider function for the memory pool or
* @p NULL if the pool is not allowed to grow
* automatically
*
* @init
*/
void chPoolObjectInit(memory_pool_t *mp, size_t size, memgetfunc_t provider) {
chDbgCheck((mp != NULL) && (size >= sizeof(void *)));
mp->mp_next = NULL;
mp->mp_object_size = size;
mp->mp_provider = provider;
}
/**
* @brief Loads a memory pool with an array of static objects.
* @pre The memory pool must be already been initialized.
* @pre The array elements must be of the right size for the specified
* memory pool.
* @post The memory pool contains the elements of the input array.
*
* @param[in] mp pointer to a @p memory_pool_t structure
* @param[in] p pointer to the array first element
* @param[in] n number of elements in the array
*
* @api
*/
void chPoolLoadArray(memory_pool_t *mp, void *p, size_t n) {
chDbgCheck((mp != NULL) && (n != 0U));
while (n != 0U) {
chPoolAdd(mp, p);
/*lint -save -e9087 [11.3] Safe cast.*/
p = (void *)(((uint8_t *)p) + mp->mp_object_size);
/*lint -restore*/
n--;
}
}
/**
* @brief Allocates an object from a memory pool.
* @pre The memory pool must be already been initialized.
*
* @param[in] mp pointer to a @p memory_pool_t structure
* @return The pointer to the allocated object.
* @retval NULL if pool is empty.
*
* @iclass
*/
void *chPoolAllocI(memory_pool_t *mp) {
void *objp;
chDbgCheckClassI();
chDbgCheck(mp != NULL);
objp = mp->mp_next;
/*lint -save -e9013 [15.7] There is no else because it is not needed.*/
if (objp != NULL) {
mp->mp_next = mp->mp_next->ph_next;
}
else if (mp->mp_provider != NULL) {
objp = mp->mp_provider(mp->mp_object_size);
}
/*lint -restore*/
return objp;
}
/**
* @brief Allocates an object from a memory pool.
* @pre The memory pool must be already been initialized.
*
* @param[in] mp pointer to a @p memory_pool_t structure
* @return The pointer to the allocated object.
* @retval NULL if pool is empty.
*
* @api
*/
void *chPoolAlloc(memory_pool_t *mp) {
void *objp;
chSysLock();
objp = chPoolAllocI(mp);
chSysUnlock();
return objp;
}
/**
* @brief Releases an object into a memory pool.
* @pre The memory pool must be already been initialized.
* @pre The freed object must be of the right size for the specified
* memory pool.
* @pre The object must be properly aligned to contain a pointer to void.
*
* @param[in] mp pointer to a @p memory_pool_t structure
* @param[in] objp the pointer to the object to be released
*
* @iclass
*/
void chPoolFreeI(memory_pool_t *mp, void *objp) {
struct pool_header *php = objp;
chDbgCheckClassI();
chDbgCheck((mp != NULL) && (objp != NULL));
php->ph_next = mp->mp_next;
mp->mp_next = php;
}
/**
* @brief Releases an object into a memory pool.
* @pre The memory pool must be already been initialized.
* @pre The freed object must be of the right size for the specified
* memory pool.
* @pre The object must be properly aligned to contain a pointer to void.
*
* @param[in] mp pointer to a @p memory_pool_t structure
* @param[in] objp the pointer to the object to be released
*
* @api
*/
void chPoolFree(memory_pool_t *mp, void *objp) {
chSysLock();
chPoolFreeI(mp, objp);
chSysUnlock();
}
#endif /* CH_CFG_USE_MEMPOOLS == TRUE */
/** @} */

View File

@ -90,13 +90,13 @@ msg_t chMsgSend(thread_t *tp, msg_t msg) {
chDbgCheck(tp != NULL); chDbgCheck(tp != NULL);
chSysLock(); chSysLock();
ctp->p_u.sentmsg = msg; ctp->u.sentmsg = msg;
msg_insert(ctp, &tp->p_msgqueue); msg_insert(ctp, &tp->msgqueue);
if (tp->p_state == CH_STATE_WTMSG) { if (tp->state == CH_STATE_WTMSG) {
(void) chSchReadyI(tp); (void) chSchReadyI(tp);
} }
chSchGoSleepS(CH_STATE_SNDMSGQ); chSchGoSleepS(CH_STATE_SNDMSGQ);
msg = ctp->p_u.rdymsg; msg = ctp->u.rdymsg;
chSysUnlock(); chSysUnlock();
return msg; return msg;
@ -123,8 +123,8 @@ thread_t *chMsgWait(void) {
if (!chMsgIsPendingI(currp)) { if (!chMsgIsPendingI(currp)) {
chSchGoSleepS(CH_STATE_WTMSG); chSchGoSleepS(CH_STATE_WTMSG);
} }
tp = queue_fifo_remove(&currp->p_msgqueue); tp = queue_fifo_remove(&currp->msgqueue);
tp->p_state = CH_STATE_SNDMSG; tp->state = CH_STATE_SNDMSG;
chSysUnlock(); chSysUnlock();
return tp; return tp;
@ -143,7 +143,7 @@ thread_t *chMsgWait(void) {
void chMsgRelease(thread_t *tp, msg_t msg) { void chMsgRelease(thread_t *tp, msg_t msg) {
chSysLock(); chSysLock();
chDbgAssert(tp->p_state == CH_STATE_SNDMSG, "invalid state"); chDbgAssert(tp->state == CH_STATE_SNDMSG, "invalid state");
chMsgReleaseS(tp, msg); chMsgReleaseS(tp, msg);
chSysUnlock(); chSysUnlock();
} }

View File

@ -104,10 +104,10 @@ void chMtxObjectInit(mutex_t *mp) {
chDbgCheck(mp != NULL); chDbgCheck(mp != NULL);
queue_init(&mp->m_queue); queue_init(&mp->queue);
mp->m_owner = NULL; mp->owner = NULL;
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
mp->m_cnt = (cnt_t)0; mp->cnt = (cnt_t)0;
#endif #endif
} }
@ -143,35 +143,35 @@ void chMtxLockS(mutex_t *mp) {
chDbgCheck(mp != NULL); chDbgCheck(mp != NULL);
/* Is the mutex already locked? */ /* Is the mutex already locked? */
if (mp->m_owner != NULL) { if (mp->owner != NULL) {
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
chDbgAssert(mp->m_cnt >= (cnt_t)1, "counter is not positive"); chDbgAssert(mp->cnt >= (cnt_t)1, "counter is not positive");
/* If the mutex is already owned by this thread, the counter is increased /* If the mutex is already owned by this thread, the counter is increased
and there is no need of more actions.*/ and there is no need of more actions.*/
if (mp->m_owner == ctp) { if (mp->owner == ctp) {
mp->m_cnt++; mp->cnt++;
} }
else { else {
#endif #endif
/* Priority inheritance protocol; explores the thread-mutex dependencies /* Priority inheritance protocol; explores the thread-mutex dependencies
boosting the priority of all the affected threads to equal the boosting the priority of all the affected threads to equal the
priority of the running thread requesting the mutex.*/ priority of the running thread requesting the mutex.*/
thread_t *tp = mp->m_owner; thread_t *tp = mp->owner;
/* Does the running thread have higher priority than the mutex /* Does the running thread have higher priority than the mutex
owning thread? */ owning thread? */
while (tp->p_prio < ctp->p_prio) { while (tp->prio < ctp->prio) {
/* Make priority of thread tp match the running thread's priority.*/ /* Make priority of thread tp match the running thread's priority.*/
tp->p_prio = ctp->p_prio; tp->prio = ctp->prio;
/* The following states need priority queues reordering.*/ /* The following states need priority queues reordering.*/
switch (tp->p_state) { switch (tp->state) {
case CH_STATE_WTMTX: case CH_STATE_WTMTX:
/* Re-enqueues the mutex owner with its new priority.*/ /* Re-enqueues the mutex owner with its new priority.*/
queue_prio_insert(queue_dequeue(tp), &tp->p_u.wtmtxp->m_queue); queue_prio_insert(queue_dequeue(tp), &tp->u.wtmtxp->queue);
tp = tp->p_u.wtmtxp->m_owner; tp = tp->u.wtmtxp->owner;
/*lint -e{9042} [16.1] Continues the while.*/ /*lint -e{9042} [16.1] Continues the while.*/
continue; continue;
#if (CH_CFG_USE_CONDVARS == TRUE) || \ #if (CH_CFG_USE_CONDVARS == TRUE) || \
@ -190,13 +190,13 @@ void chMtxLockS(mutex_t *mp) {
case CH_STATE_SNDMSGQ: case CH_STATE_SNDMSGQ:
#endif #endif
/* Re-enqueues tp with its new priority on the queue.*/ /* Re-enqueues tp with its new priority on the queue.*/
queue_prio_insert(queue_dequeue(tp), &tp->p_u.wtmtxp->m_queue); queue_prio_insert(queue_dequeue(tp), &tp->u.wtmtxp->queue);
break; break;
#endif #endif
case CH_STATE_READY: case CH_STATE_READY:
#if CH_DBG_ENABLE_ASSERTS == TRUE #if CH_DBG_ENABLE_ASSERTS == TRUE
/* Prevents an assertion in chSchReadyI().*/ /* Prevents an assertion in chSchReadyI().*/
tp->p_state = CH_STATE_CURRENT; tp->state = CH_STATE_CURRENT;
#endif #endif
/* Re-enqueues tp with its new priority on the ready list.*/ /* Re-enqueues tp with its new priority on the ready list.*/
(void) chSchReadyI(queue_dequeue(tp)); (void) chSchReadyI(queue_dequeue(tp));
@ -209,29 +209,29 @@ void chMtxLockS(mutex_t *mp) {
} }
/* Sleep on the mutex.*/ /* Sleep on the mutex.*/
queue_prio_insert(ctp, &mp->m_queue); queue_prio_insert(ctp, &mp->queue);
ctp->p_u.wtmtxp = mp; ctp->u.wtmtxp = mp;
chSchGoSleepS(CH_STATE_WTMTX); chSchGoSleepS(CH_STATE_WTMTX);
/* It is assumed that the thread performing the unlock operation assigns /* It is assumed that the thread performing the unlock operation assigns
the mutex to this thread.*/ the mutex to this thread.*/
chDbgAssert(mp->m_owner == ctp, "not owner"); chDbgAssert(mp->owner == ctp, "not owner");
chDbgAssert(ctp->p_mtxlist == mp, "not owned"); chDbgAssert(ctp->mtxlist == mp, "not owned");
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
chDbgAssert(mp->m_cnt == (cnt_t)1, "counter is not one"); chDbgAssert(mp->cnt == (cnt_t)1, "counter is not one");
} }
#endif #endif
} }
else { else {
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
chDbgAssert(mp->m_cnt == (cnt_t)0, "counter is not zero"); chDbgAssert(mp->cnt == (cnt_t)0, "counter is not zero");
mp->m_cnt++; mp->cnt++;
#endif #endif
/* It was not owned, inserted in the owned mutexes list.*/ /* It was not owned, inserted in the owned mutexes list.*/
mp->m_owner = ctp; mp->owner = ctp;
mp->m_next = ctp->p_mtxlist; mp->next = ctp->mtxlist;
ctp->p_mtxlist = mp; ctp->mtxlist = mp;
} }
} }
@ -284,13 +284,13 @@ bool chMtxTryLockS(mutex_t *mp) {
chDbgCheckClassS(); chDbgCheckClassS();
chDbgCheck(mp != NULL); chDbgCheck(mp != NULL);
if (mp->m_owner != NULL) { if (mp->owner != NULL) {
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
chDbgAssert(mp->m_cnt >= (cnt_t)1, "counter is not positive"); chDbgAssert(mp->cnt >= (cnt_t)1, "counter is not positive");
if (mp->m_owner == currp) { if (mp->owner == currp) {
mp->m_cnt++; mp->cnt++;
return true; return true;
} }
#endif #endif
@ -298,13 +298,13 @@ bool chMtxTryLockS(mutex_t *mp) {
} }
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
chDbgAssert(mp->m_cnt == (cnt_t)0, "counter is not zero"); chDbgAssert(mp->cnt == (cnt_t)0, "counter is not zero");
mp->m_cnt++; mp->cnt++;
#endif #endif
mp->m_owner = currp; mp->owner = currp;
mp->m_next = currp->p_mtxlist; mp->next = currp->mtxlist;
currp->p_mtxlist = mp; currp->mtxlist = mp;
return true; return true;
} }
@ -328,20 +328,20 @@ void chMtxUnlock(mutex_t *mp) {
chSysLock(); chSysLock();
chDbgAssert(ctp->p_mtxlist != NULL, "owned mutexes list empty"); chDbgAssert(ctp->mtxlist != NULL, "owned mutexes list empty");
chDbgAssert(ctp->p_mtxlist->m_owner == ctp, "ownership failure"); chDbgAssert(ctp->mtxlist->owner == ctp, "ownership failure");
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
chDbgAssert(mp->m_cnt >= (cnt_t)1, "counter is not positive"); chDbgAssert(mp->cnt >= (cnt_t)1, "counter is not positive");
if (--mp->m_cnt == (cnt_t)0) { if (--mp->cnt == (cnt_t)0) {
#endif #endif
chDbgAssert(ctp->p_mtxlist == mp, "not next in list"); chDbgAssert(ctp->mtxlist == mp, "not next in list");
/* Removes the top mutex from the thread's owned mutexes list and marks /* Removes the top mutex from the thread's owned mutexes list and marks
it as not owned. Note, it is assumed to be the same mutex passed as it as not owned. Note, it is assumed to be the same mutex passed as
parameter of this function.*/ parameter of this function.*/
ctp->p_mtxlist = mp->m_next; ctp->mtxlist = mp->next;
/* If a thread is waiting on the mutex then the fun part begins.*/ /* If a thread is waiting on the mutex then the fun part begins.*/
if (chMtxQueueNotEmptyS(mp)) { if (chMtxQueueNotEmptyS(mp)) {
@ -349,32 +349,32 @@ void chMtxUnlock(mutex_t *mp) {
/* Recalculates the optimal thread priority by scanning the owned /* Recalculates the optimal thread priority by scanning the owned
mutexes list.*/ mutexes list.*/
tprio_t newprio = ctp->p_realprio; tprio_t newprio = ctp->realprio;
lmp = ctp->p_mtxlist; lmp = ctp->mtxlist;
while (lmp != NULL) { while (lmp != NULL) {
/* If the highest priority thread waiting in the mutexes list has a /* If the highest priority thread waiting in the mutexes list has a
greater priority than the current thread base priority then the greater priority than the current thread base priority then the
final priority will have at least that priority.*/ final priority will have at least that priority.*/
if (chMtxQueueNotEmptyS(lmp) && if (chMtxQueueNotEmptyS(lmp) &&
(lmp->m_queue.p_next->p_prio > newprio)) { (lmp->queue.next->prio > newprio)) {
newprio = lmp->m_queue.p_next->p_prio; newprio = lmp->queue.next->prio;
} }
lmp = lmp->m_next; lmp = lmp->next;
} }
/* Assigns to the current thread the highest priority among all the /* Assigns to the current thread the highest priority among all the
waiting threads.*/ waiting threads.*/
ctp->p_prio = newprio; ctp->prio = newprio;
/* Awakens the highest priority thread waiting for the unlocked mutex and /* Awakens the highest priority thread waiting for the unlocked mutex and
assigns the mutex to it.*/ assigns the mutex to it.*/
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
mp->m_cnt = (cnt_t)1; mp->cnt = (cnt_t)1;
#endif #endif
tp = queue_fifo_remove(&mp->m_queue); tp = queue_fifo_remove(&mp->queue);
mp->m_owner = tp; mp->owner = tp;
mp->m_next = tp->p_mtxlist; mp->next = tp->mtxlist;
tp->p_mtxlist = mp; tp->mtxlist = mp;
/* Note, not using chSchWakeupS() becuase that function expects the /* Note, not using chSchWakeupS() becuase that function expects the
current thread to have the higher or equal priority than the ones current thread to have the higher or equal priority than the ones
@ -384,7 +384,7 @@ void chMtxUnlock(mutex_t *mp) {
chSchRescheduleS(); chSchRescheduleS();
} }
else { else {
mp->m_owner = NULL; mp->owner = NULL;
} }
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
} }
@ -414,20 +414,20 @@ void chMtxUnlockS(mutex_t *mp) {
chDbgCheckClassS(); chDbgCheckClassS();
chDbgCheck(mp != NULL); chDbgCheck(mp != NULL);
chDbgAssert(ctp->p_mtxlist != NULL, "owned mutexes list empty"); chDbgAssert(ctp->mtxlist != NULL, "owned mutexes list empty");
chDbgAssert(ctp->p_mtxlist->m_owner == ctp, "ownership failure"); chDbgAssert(ctp->mtxlist->owner == ctp, "ownership failure");
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
chDbgAssert(mp->m_cnt >= (cnt_t)1, "counter is not positive"); chDbgAssert(mp->cnt >= (cnt_t)1, "counter is not positive");
if (--mp->m_cnt == (cnt_t)0) { if (--mp->cnt == (cnt_t)0) {
#endif #endif
chDbgAssert(ctp->p_mtxlist == mp, "not next in list"); chDbgAssert(ctp->mtxlist == mp, "not next in list");
/* Removes the top mutex from the thread's owned mutexes list and marks /* Removes the top mutex from the thread's owned mutexes list and marks
it as not owned. Note, it is assumed to be the same mutex passed as it as not owned. Note, it is assumed to be the same mutex passed as
parameter of this function.*/ parameter of this function.*/
ctp->p_mtxlist = mp->m_next; ctp->mtxlist = mp->next;
/* If a thread is waiting on the mutex then the fun part begins.*/ /* If a thread is waiting on the mutex then the fun part begins.*/
if (chMtxQueueNotEmptyS(mp)) { if (chMtxQueueNotEmptyS(mp)) {
@ -435,36 +435,36 @@ void chMtxUnlockS(mutex_t *mp) {
/* Recalculates the optimal thread priority by scanning the owned /* Recalculates the optimal thread priority by scanning the owned
mutexes list.*/ mutexes list.*/
tprio_t newprio = ctp->p_realprio; tprio_t newprio = ctp->realprio;
lmp = ctp->p_mtxlist; lmp = ctp->mtxlist;
while (lmp != NULL) { while (lmp != NULL) {
/* If the highest priority thread waiting in the mutexes list has a /* If the highest priority thread waiting in the mutexes list has a
greater priority than the current thread base priority then the greater priority than the current thread base priority then the
final priority will have at least that priority.*/ final priority will have at least that priority.*/
if (chMtxQueueNotEmptyS(lmp) && if (chMtxQueueNotEmptyS(lmp) &&
(lmp->m_queue.p_next->p_prio > newprio)) { (lmp->queue.next->prio > newprio)) {
newprio = lmp->m_queue.p_next->p_prio; newprio = lmp->queue.next->prio;
} }
lmp = lmp->m_next; lmp = lmp->next;
} }
/* Assigns to the current thread the highest priority among all the /* Assigns to the current thread the highest priority among all the
waiting threads.*/ waiting threads.*/
ctp->p_prio = newprio; ctp->prio = newprio;
/* Awakens the highest priority thread waiting for the unlocked mutex and /* Awakens the highest priority thread waiting for the unlocked mutex and
assigns the mutex to it.*/ assigns the mutex to it.*/
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
mp->m_cnt = (cnt_t)1; mp->cnt = (cnt_t)1;
#endif #endif
tp = queue_fifo_remove(&mp->m_queue); tp = queue_fifo_remove(&mp->queue);
mp->m_owner = tp; mp->owner = tp;
mp->m_next = tp->p_mtxlist; mp->next = tp->mtxlist;
tp->p_mtxlist = mp; tp->mtxlist = mp;
(void) chSchReadyI(tp); (void) chSchReadyI(tp);
} }
else { else {
mp->m_owner = NULL; mp->owner = NULL;
} }
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
} }
@ -486,28 +486,28 @@ void chMtxUnlockAll(void) {
thread_t *ctp = currp; thread_t *ctp = currp;
chSysLock(); chSysLock();
if (ctp->p_mtxlist != NULL) { if (ctp->mtxlist != NULL) {
do { do {
mutex_t *mp = ctp->p_mtxlist; mutex_t *mp = ctp->mtxlist;
ctp->p_mtxlist = mp->m_next; ctp->mtxlist = mp->next;
if (chMtxQueueNotEmptyS(mp)) { if (chMtxQueueNotEmptyS(mp)) {
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
mp->m_cnt = (cnt_t)1; mp->cnt = (cnt_t)1;
#endif #endif
thread_t *tp = queue_fifo_remove(&mp->m_queue); thread_t *tp = queue_fifo_remove(&mp->queue);
mp->m_owner = tp; mp->owner = tp;
mp->m_next = tp->p_mtxlist; mp->next = tp->mtxlist;
tp->p_mtxlist = mp; tp->mtxlist = mp;
(void) chSchReadyI(tp); (void) chSchReadyI(tp);
} }
else { else {
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
mp->m_cnt = (cnt_t)0; mp->cnt = (cnt_t)0;
#endif #endif
mp->m_owner = NULL; mp->owner = NULL;
} }
} while (ctp->p_mtxlist != NULL); } while (ctp->mtxlist != NULL);
ctp->p_prio = ctp->p_realprio; ctp->prio = ctp->realprio;
chSchRescheduleS(); chSchRescheduleS();
} }
chSysUnlock(); chSysUnlock();

View File

@ -87,14 +87,14 @@
void chIQObjectInit(input_queue_t *iqp, uint8_t *bp, size_t size, void chIQObjectInit(input_queue_t *iqp, uint8_t *bp, size_t size,
qnotify_t infy, void *link) { qnotify_t infy, void *link) {
chThdQueueObjectInit(&iqp->q_waiting); chThdQueueObjectInit(&iqp->waiting);
iqp->q_counter = 0; iqp->counter = 0;
iqp->q_buffer = bp; iqp->buffer = bp;
iqp->q_rdptr = bp; iqp->rdptr = bp;
iqp->q_wrptr = bp; iqp->wrptr = bp;
iqp->q_top = bp + size; iqp->top = bp + size;
iqp->q_notify = infy; iqp->notify = infy;
iqp->q_link = link; iqp->link = link;
} }
/** /**
@ -112,10 +112,10 @@ void chIQResetI(input_queue_t *iqp) {
chDbgCheckClassI(); chDbgCheckClassI();
iqp->q_rdptr = iqp->q_buffer; iqp->rdptr = iqp->buffer;
iqp->q_wrptr = iqp->q_buffer; iqp->wrptr = iqp->buffer;
iqp->q_counter = 0; iqp->counter = 0;
chThdDequeueAllI(&iqp->q_waiting, Q_RESET); chThdDequeueAllI(&iqp->waiting, Q_RESET);
} }
/** /**
@ -139,13 +139,13 @@ msg_t chIQPutI(input_queue_t *iqp, uint8_t b) {
return Q_FULL; return Q_FULL;
} }
iqp->q_counter++; iqp->counter++;
*iqp->q_wrptr++ = b; *iqp->wrptr++ = b;
if (iqp->q_wrptr >= iqp->q_top) { if (iqp->wrptr >= iqp->top) {
iqp->q_wrptr = iqp->q_buffer; iqp->wrptr = iqp->buffer;
} }
chThdDequeueNextI(&iqp->q_waiting, Q_OK); chThdDequeueNextI(&iqp->waiting, Q_OK);
return Q_OK; return Q_OK;
} }
@ -174,22 +174,22 @@ msg_t chIQGetTimeout(input_queue_t *iqp, systime_t timeout) {
uint8_t b; uint8_t b;
chSysLock(); chSysLock();
if (iqp->q_notify != NULL) { if (iqp->notify != NULL) {
iqp->q_notify(iqp); iqp->notify(iqp);
} }
while (chIQIsEmptyI(iqp)) { while (chIQIsEmptyI(iqp)) {
msg_t msg = chThdEnqueueTimeoutS(&iqp->q_waiting, timeout); msg_t msg = chThdEnqueueTimeoutS(&iqp->waiting, timeout);
if (msg < Q_OK) { if (msg < Q_OK) {
chSysUnlock(); chSysUnlock();
return msg; return msg;
} }
} }
iqp->q_counter--; iqp->counter--;
b = *iqp->q_rdptr++; b = *iqp->rdptr++;
if (iqp->q_rdptr >= iqp->q_top) { if (iqp->rdptr >= iqp->top) {
iqp->q_rdptr = iqp->q_buffer; iqp->rdptr = iqp->buffer;
} }
chSysUnlock(); chSysUnlock();
@ -222,7 +222,7 @@ msg_t chIQGetTimeout(input_queue_t *iqp, systime_t timeout) {
*/ */
size_t chIQReadTimeout(input_queue_t *iqp, uint8_t *bp, size_t chIQReadTimeout(input_queue_t *iqp, uint8_t *bp,
size_t n, systime_t timeout) { size_t n, systime_t timeout) {
qnotify_t nfy = iqp->q_notify; qnotify_t nfy = iqp->notify;
size_t r = 0; size_t r = 0;
chDbgCheck(n > 0U); chDbgCheck(n > 0U);
@ -234,16 +234,16 @@ size_t chIQReadTimeout(input_queue_t *iqp, uint8_t *bp,
} }
while (chIQIsEmptyI(iqp)) { while (chIQIsEmptyI(iqp)) {
if (chThdEnqueueTimeoutS(&iqp->q_waiting, timeout) != Q_OK) { if (chThdEnqueueTimeoutS(&iqp->waiting, timeout) != Q_OK) {
chSysUnlock(); chSysUnlock();
return r; return r;
} }
} }
iqp->q_counter--; iqp->counter--;
*bp++ = *iqp->q_rdptr++; *bp++ = *iqp->rdptr++;
if (iqp->q_rdptr >= iqp->q_top) { if (iqp->rdptr >= iqp->top) {
iqp->q_rdptr = iqp->q_buffer; iqp->rdptr = iqp->buffer;
} }
chSysUnlock(); /* Gives a preemption chance in a controlled point.*/ chSysUnlock(); /* Gives a preemption chance in a controlled point.*/
@ -275,14 +275,14 @@ size_t chIQReadTimeout(input_queue_t *iqp, uint8_t *bp,
void chOQObjectInit(output_queue_t *oqp, uint8_t *bp, size_t size, void chOQObjectInit(output_queue_t *oqp, uint8_t *bp, size_t size,
qnotify_t onfy, void *link) { qnotify_t onfy, void *link) {
chThdQueueObjectInit(&oqp->q_waiting); chThdQueueObjectInit(&oqp->waiting);
oqp->q_counter = size; oqp->counter = size;
oqp->q_buffer = bp; oqp->buffer = bp;
oqp->q_rdptr = bp; oqp->rdptr = bp;
oqp->q_wrptr = bp; oqp->wrptr = bp;
oqp->q_top = bp + size; oqp->top = bp + size;
oqp->q_notify = onfy; oqp->notify = onfy;
oqp->q_link = link; oqp->link = link;
} }
/** /**
@ -300,10 +300,10 @@ void chOQResetI(output_queue_t *oqp) {
chDbgCheckClassI(); chDbgCheckClassI();
oqp->q_rdptr = oqp->q_buffer; oqp->rdptr = oqp->buffer;
oqp->q_wrptr = oqp->q_buffer; oqp->wrptr = oqp->buffer;
oqp->q_counter = chQSizeX(oqp); oqp->counter = chQSizeX(oqp);
chThdDequeueAllI(&oqp->q_waiting, Q_RESET); chThdDequeueAllI(&oqp->waiting, Q_RESET);
} }
/** /**
@ -332,21 +332,21 @@ msg_t chOQPutTimeout(output_queue_t *oqp, uint8_t b, systime_t timeout) {
chSysLock(); chSysLock();
while (chOQIsFullI(oqp)) { while (chOQIsFullI(oqp)) {
msg_t msg = chThdEnqueueTimeoutS(&oqp->q_waiting, timeout); msg_t msg = chThdEnqueueTimeoutS(&oqp->waiting, timeout);
if (msg < Q_OK) { if (msg < Q_OK) {
chSysUnlock(); chSysUnlock();
return msg; return msg;
} }
} }
oqp->q_counter--; oqp->counter--;
*oqp->q_wrptr++ = b; *oqp->wrptr++ = b;
if (oqp->q_wrptr >= oqp->q_top) { if (oqp->wrptr >= oqp->top) {
oqp->q_wrptr = oqp->q_buffer; oqp->wrptr = oqp->buffer;
} }
if (oqp->q_notify != NULL) { if (oqp->notify != NULL) {
oqp->q_notify(oqp); oqp->notify(oqp);
} }
chSysUnlock(); chSysUnlock();
@ -372,13 +372,13 @@ msg_t chOQGetI(output_queue_t *oqp) {
return Q_EMPTY; return Q_EMPTY;
} }
oqp->q_counter++; oqp->counter++;
b = *oqp->q_rdptr++; b = *oqp->rdptr++;
if (oqp->q_rdptr >= oqp->q_top) { if (oqp->rdptr >= oqp->top) {
oqp->q_rdptr = oqp->q_buffer; oqp->rdptr = oqp->buffer;
} }
chThdDequeueNextI(&oqp->q_waiting, Q_OK); chThdDequeueNextI(&oqp->waiting, Q_OK);
return (msg_t)b; return (msg_t)b;
} }
@ -409,7 +409,7 @@ msg_t chOQGetI(output_queue_t *oqp) {
*/ */
size_t chOQWriteTimeout(output_queue_t *oqp, const uint8_t *bp, size_t chOQWriteTimeout(output_queue_t *oqp, const uint8_t *bp,
size_t n, systime_t timeout) { size_t n, systime_t timeout) {
qnotify_t nfy = oqp->q_notify; qnotify_t nfy = oqp->notify;
size_t w = 0; size_t w = 0;
chDbgCheck(n > 0U); chDbgCheck(n > 0U);
@ -417,16 +417,16 @@ size_t chOQWriteTimeout(output_queue_t *oqp, const uint8_t *bp,
chSysLock(); chSysLock();
while (true) { while (true) {
while (chOQIsFullI(oqp)) { while (chOQIsFullI(oqp)) {
if (chThdEnqueueTimeoutS(&oqp->q_waiting, timeout) != Q_OK) { if (chThdEnqueueTimeoutS(&oqp->waiting, timeout) != Q_OK) {
chSysUnlock(); chSysUnlock();
return w; return w;
} }
} }
oqp->q_counter--; oqp->counter--;
*oqp->q_wrptr++ = *bp++; *oqp->wrptr++ = *bp++;
if (oqp->q_wrptr >= oqp->q_top) { if (oqp->wrptr >= oqp->top) {
oqp->q_wrptr = oqp->q_buffer; oqp->wrptr = oqp->buffer;
} }
if (nfy != NULL) { if (nfy != NULL) {

View File

@ -87,30 +87,26 @@ ROMCONST chdebug_t ch_debug = {
(uint8_t)sizeof (void *), (uint8_t)sizeof (void *),
(uint8_t)sizeof (systime_t), (uint8_t)sizeof (systime_t),
(uint8_t)sizeof (thread_t), (uint8_t)sizeof (thread_t),
(uint8_t)_offsetof(thread_t, p_prio), (uint8_t)_offsetof(thread_t, prio),
(uint8_t)_offsetof(thread_t, p_ctx), (uint8_t)_offsetof(thread_t, ctx),
(uint8_t)_offsetof(thread_t, p_newer), (uint8_t)_offsetof(thread_t, newer),
(uint8_t)_offsetof(thread_t, p_older), (uint8_t)_offsetof(thread_t, older),
(uint8_t)_offsetof(thread_t, p_name), (uint8_t)_offsetof(thread_t, name),
#if CH_DBG_ENABLE_STACK_CHECK == TRUE #if CH_DBG_ENABLE_STACK_CHECK == TRUE
(uint8_t)_offsetof(thread_t, p_stklimit), (uint8_t)_offsetof(thread_t, stklimit),
#else
(uint8_t)0,
#endif
(uint8_t)_offsetof(thread_t, p_state),
(uint8_t)_offsetof(thread_t, p_flags),
#if CH_CFG_USE_DYNAMIC == TRUE
(uint8_t)_offsetof(thread_t, p_refs),
#else #else
(uint8_t)0, (uint8_t)0,
#endif #endif
(uint8_t)_offsetof(thread_t, state),
(uint8_t)0, /* Flags no more part of the structure. */
(uint8_t)0, /* Refs no more part of the structure. */
#if CH_CFG_TIME_QUANTUM > 0 #if CH_CFG_TIME_QUANTUM > 0
(uint8_t)_offsetof(thread_t, p_preempt), (uint8_t)_offsetof(thread_t, preempt),
#else #else
(uint8_t)0, (uint8_t)0,
#endif #endif
#if CH_DBG_THREADS_PROFILING == TRUE #if CH_DBG_THREADS_PROFILING == TRUE
(uint8_t)_offsetof(thread_t, p_time) (uint8_t)_offsetof(thread_t, time)
#else #else
(uint8_t)0 (uint8_t)0
#endif #endif
@ -132,10 +128,7 @@ thread_t *chRegFirstThread(void) {
thread_t *tp; thread_t *tp;
chSysLock(); chSysLock();
tp = ch.rlist.r_newer; tp = ch.rlist.newer;
#if CH_CFG_USE_DYNAMIC == TRUE
tp->p_refs++;
#endif
chSysUnlock(); chSysUnlock();
return tp; return tp;
@ -156,22 +149,13 @@ thread_t *chRegNextThread(thread_t *tp) {
thread_t *ntp; thread_t *ntp;
chSysLock(); chSysLock();
ntp = tp->p_newer; ntp = tp->newer;
/*lint -save -e9087 -e740 [11.3, 1.3] Cast required by list handling.*/ /*lint -save -e9087 -e740 [11.3, 1.3] Cast required by list handling.*/
if (ntp == (thread_t *)&ch.rlist) { if (ntp == (thread_t *)&ch.rlist) {
/*lint -restore*/ /*lint -restore*/
ntp = NULL; ntp = NULL;
} }
#if CH_CFG_USE_DYNAMIC == TRUE
else {
chDbgAssert(ntp->p_refs < (trefs_t)255, "too many references");
ntp->p_refs++;
}
#endif
chSysUnlock(); chSysUnlock();
#if CH_CFG_USE_DYNAMIC == TRUE
chThdRelease(tp);
#endif
return ntp; return ntp;
} }

View File

@ -64,11 +64,11 @@ ch_system_t ch;
*/ */
void _scheduler_init(void) { void _scheduler_init(void) {
queue_init(&ch.rlist.r_queue); queue_init(&ch.rlist.queue);
ch.rlist.r_prio = NOPRIO; ch.rlist.prio = NOPRIO;
#if CH_CFG_USE_REGISTRY == TRUE #if CH_CFG_USE_REGISTRY == TRUE
ch.rlist.r_newer = (thread_t *)&ch.rlist; ch.rlist.newer = (thread_t *)&ch.rlist;
ch.rlist.r_older = (thread_t *)&ch.rlist; ch.rlist.older = (thread_t *)&ch.rlist;
#endif #endif
} }
@ -87,12 +87,12 @@ void queue_prio_insert(thread_t *tp, threads_queue_t *tqp) {
thread_t *cp = (thread_t *)tqp; thread_t *cp = (thread_t *)tqp;
do { do {
cp = cp->p_next; cp = cp->next;
} while ((cp != (thread_t *)tqp) && (cp->p_prio >= tp->p_prio)); } while ((cp != (thread_t *)tqp) && (cp->prio >= tp->prio));
tp->p_next = cp; tp->next = cp;
tp->p_prev = cp->p_prev; tp->prev = cp->prev;
tp->p_prev->p_next = tp; tp->prev->next = tp;
cp->p_prev = tp; cp->prev = tp;
} }
/** /**
@ -105,10 +105,10 @@ void queue_prio_insert(thread_t *tp, threads_queue_t *tqp) {
*/ */
void queue_insert(thread_t *tp, threads_queue_t *tqp) { void queue_insert(thread_t *tp, threads_queue_t *tqp) {
tp->p_next = (thread_t *)tqp; tp->next = (thread_t *)tqp;
tp->p_prev = tqp->p_prev; tp->prev = tqp->prev;
tp->p_prev->p_next = tp; tp->prev->next = tp;
tqp->p_prev = tp; tqp->prev = tp;
} }
/** /**
@ -122,10 +122,10 @@ void queue_insert(thread_t *tp, threads_queue_t *tqp) {
* @notapi * @notapi
*/ */
thread_t *queue_fifo_remove(threads_queue_t *tqp) { thread_t *queue_fifo_remove(threads_queue_t *tqp) {
thread_t *tp = tqp->p_next; thread_t *tp = tqp->next;
tqp->p_next = tp->p_next; tqp->next = tp->next;
tqp->p_next->p_prev = (thread_t *)tqp; tqp->next->prev = (thread_t *)tqp;
return tp; return tp;
} }
@ -141,10 +141,10 @@ thread_t *queue_fifo_remove(threads_queue_t *tqp) {
* @notapi * @notapi
*/ */
thread_t *queue_lifo_remove(threads_queue_t *tqp) { thread_t *queue_lifo_remove(threads_queue_t *tqp) {
thread_t *tp = tqp->p_prev; thread_t *tp = tqp->prev;
tqp->p_prev = tp->p_prev; tqp->prev = tp->prev;
tqp->p_prev->p_next = (thread_t *)tqp; tqp->prev->next = (thread_t *)tqp;
return tp; return tp;
} }
@ -161,8 +161,8 @@ thread_t *queue_lifo_remove(threads_queue_t *tqp) {
*/ */
thread_t *queue_dequeue(thread_t *tp) { thread_t *queue_dequeue(thread_t *tp) {
tp->p_prev->p_next = tp->p_next; tp->prev->next = tp->next;
tp->p_next->p_prev = tp->p_prev; tp->next->prev = tp->prev;
return tp; return tp;
} }
@ -177,8 +177,8 @@ thread_t *queue_dequeue(thread_t *tp) {
*/ */
void list_insert(thread_t *tp, threads_list_t *tlp) { void list_insert(thread_t *tp, threads_list_t *tlp) {
tp->p_next = tlp->p_next; tp->next = tlp->next;
tlp->p_next = tp; tlp->next = tp;
} }
/** /**
@ -192,19 +192,19 @@ void list_insert(thread_t *tp, threads_list_t *tlp) {
*/ */
thread_t *list_remove(threads_list_t *tlp) { thread_t *list_remove(threads_list_t *tlp) {
thread_t *tp = tlp->p_next; thread_t *tp = tlp->next;
tlp->p_next = tp->p_next; tlp->next = tp->next;
return tp; return tp;
} }
#endif /* CH_CFG_OPTIMIZE_SPEED */ #endif /* CH_CFG_OPTIMIZE_SPEED */
/** /**
* @brief Inserts a thread in the Ready List. * @brief Inserts a thread in the Ready List placing it behind its peers.
* @details The thread is positioned behind all threads with higher or equal * @details The thread is positioned behind all threads with higher or equal
* priority. * priority.
* @pre The thread must not be already inserted in any list through its * @pre The thread must not be already inserted in any list through its
* @p p_next and @p p_prev or list corruption would occur. * @p next and @p prev or list corruption would occur.
* @post This function does not reschedule so a call to a rescheduling * @post This function does not reschedule so a call to a rescheduling
* function must be performed before unlocking the kernel. Note that * function must be performed before unlocking the kernel. Note that
* interrupt handlers always reschedule on exit so an explicit * interrupt handlers always reschedule on exit so an explicit
@ -220,20 +220,59 @@ thread_t *chSchReadyI(thread_t *tp) {
chDbgCheckClassI(); chDbgCheckClassI();
chDbgCheck(tp != NULL); chDbgCheck(tp != NULL);
chDbgAssert((tp->p_state != CH_STATE_READY) && chDbgAssert((tp->state != CH_STATE_READY) &&
(tp->p_state != CH_STATE_FINAL), (tp->state != CH_STATE_FINAL),
"invalid state"); "invalid state");
tp->p_state = CH_STATE_READY; tp->state = CH_STATE_READY;
cp = (thread_t *)&ch.rlist.r_queue; cp = (thread_t *)&ch.rlist.queue;
do { do {
cp = cp->p_next; cp = cp->next;
} while (cp->p_prio >= tp->p_prio); } while (cp->prio >= tp->prio);
/* Insertion on p_prev.*/ /* Insertion on prev.*/
tp->p_next = cp; tp->next = cp;
tp->p_prev = cp->p_prev; tp->prev = cp->prev;
tp->p_prev->p_next = tp; tp->prev->next = tp;
cp->p_prev = tp; cp->prev = tp;
return tp;
}
/**
* @brief Inserts a thread in the Ready List placing it ahead its peers.
* @details The thread is positioned ahead all threads with higher or equal
* priority.
* @pre The thread must not be already inserted in any list through its
* @p next and @p prev or list corruption would occur.
* @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 made ready
* @return The thread pointer.
*
* @iclass
*/
thread_t *chSchReadyAheadI(thread_t *tp) {
thread_t *cp;
chDbgCheckClassI();
chDbgCheck(tp != NULL);
chDbgAssert((tp->state != CH_STATE_READY) &&
(tp->state != CH_STATE_FINAL),
"invalid state");
tp->state = CH_STATE_READY;
cp = (thread_t *)&ch.rlist.queue;
do {
cp = cp->next;
} while (cp->prio > tp->prio);
/* Insertion on prev.*/
tp->next = cp;
tp->prev = cp->prev;
tp->prev->next = tp;
cp->prev = tp;
return tp; return tp;
} }
@ -253,19 +292,21 @@ void chSchGoSleepS(tstate_t newstate) {
chDbgCheckClassS(); chDbgCheckClassS();
otp = currp; otp = currp;
otp->p_state = newstate; otp->state = newstate;
#if CH_CFG_TIME_QUANTUM > 0 #if CH_CFG_TIME_QUANTUM > 0
/* The thread is renouncing its remaining time slices so it will have a new /* The thread is renouncing its remaining time slices so it will have a new
time quantum when it will wakeup.*/ time quantum when it will wakeup.*/
otp->p_preempt = (tslices_t)CH_CFG_TIME_QUANTUM; otp->preempt = (tslices_t)CH_CFG_TIME_QUANTUM;
#endif #endif
setcurrp(queue_fifo_remove(&ch.rlist.r_queue)); currp = queue_fifo_remove(&ch.rlist.queue);
#if defined(CH_CFG_IDLE_ENTER_HOOK) if (currp->prio == IDLEPRIO) {
if (currp->p_prio == IDLEPRIO) {
CH_CFG_IDLE_ENTER_HOOK(); CH_CFG_IDLE_ENTER_HOOK();
} }
#endif
currp->p_state = CH_STATE_CURRENT; /* The extracted thread is marked as current.*/
currp->state = CH_STATE_CURRENT;
/* Swap operation as tail call.*/
chSysSwitch(currp, otp); chSysSwitch(currp, otp);
} }
@ -276,18 +317,18 @@ static void wakeup(void *p) {
thread_t *tp = (thread_t *)p; thread_t *tp = (thread_t *)p;
chSysLockFromISR(); chSysLockFromISR();
switch (tp->p_state) { switch (tp->state) {
case CH_STATE_READY: case CH_STATE_READY:
/* Handling the special case where the thread has been made ready by /* Handling the special case where the thread has been made ready by
another thread with higher priority.*/ another thread with higher priority.*/
chSysUnlockFromISR(); chSysUnlockFromISR();
return; return;
case CH_STATE_SUSPENDED: case CH_STATE_SUSPENDED:
*tp->p_u.wttrp = NULL; *tp->u.wttrp = NULL;
break; break;
#if CH_CFG_USE_SEMAPHORES == TRUE #if CH_CFG_USE_SEMAPHORES == TRUE
case CH_STATE_WTSEM: case CH_STATE_WTSEM:
chSemFastSignalI(tp->p_u.wtsemp); chSemFastSignalI(tp->u.wtsemp);
/* Falls into, intentional. */ /* Falls into, intentional. */
#endif #endif
#if (CH_CFG_USE_CONDVARS == TRUE) && (CH_CFG_USE_CONDVARS_TIMEOUT == TRUE) #if (CH_CFG_USE_CONDVARS == TRUE) && (CH_CFG_USE_CONDVARS_TIMEOUT == TRUE)
@ -301,7 +342,7 @@ static void wakeup(void *p) {
/* Any other state, nothing to do.*/ /* Any other state, nothing to do.*/
break; break;
} }
tp->p_u.rdymsg = MSG_TIMEOUT; tp->u.rdymsg = MSG_TIMEOUT;
(void) chSchReadyI(tp); (void) chSchReadyI(tp);
chSysUnlockFromISR(); chSysUnlockFromISR();
} }
@ -344,7 +385,7 @@ msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time) {
chSchGoSleepS(newstate); chSchGoSleepS(newstate);
} }
return currp->p_u.rdymsg; return currp->u.rdymsg;
} }
/** /**
@ -353,7 +394,7 @@ msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time) {
* running depending on its relative priority compared to the current * running depending on its relative priority compared to the current
* thread. * thread.
* @pre The thread must not be already inserted in any list through its * @pre The thread must not be already inserted in any list through its
* @p p_next and @p p_prev or list corruption would occur. * @p next and @p prev or list corruption would occur.
* @note It is equivalent to a @p chSchReadyI() followed by a * @note It is equivalent to a @p chSchReadyI() followed by a
* @p chSchRescheduleS() but much more efficient. * @p chSchRescheduleS() but much more efficient.
* @note The function assumes that the current thread has the highest * @note The function assumes that the current thread has the highest
@ -368,30 +409,32 @@ void chSchWakeupS(thread_t *ntp, msg_t msg) {
chDbgCheckClassS(); chDbgCheckClassS();
chDbgAssert((ch.rlist.r_queue.p_next == (thread_t *)&ch.rlist.r_queue) || chDbgAssert((ch.rlist.queue.next == (thread_t *)&ch.rlist.queue) ||
(ch.rlist.r_current->p_prio >= ch.rlist.r_queue.p_next->p_prio), (ch.rlist.current->prio >= ch.rlist.queue.next->prio),
"priority order violation"); "priority order violation");
/* Storing the message to be retrieved by the target thread when it will /* Storing the message to be retrieved by the target thread when it will
restart execution.*/ restart execution.*/
ntp->p_u.rdymsg = msg; ntp->u.rdymsg = msg;
/* If the waken thread has a not-greater priority than the current /* If the waken thread has a not-greater priority than the current
one then it is just inserted in the ready list else it made one then it is just inserted in the ready list else it made
running immediately and the invoking thread goes in the ready running immediately and the invoking thread goes in the ready
list instead.*/ list instead.*/
if (ntp->p_prio <= currp->p_prio) { if (ntp->prio <= currp->prio) {
(void) chSchReadyI(ntp); (void) chSchReadyI(ntp);
} }
else { else {
thread_t *otp = chSchReadyI(currp); thread_t *otp = chSchReadyI(currp);
setcurrp(ntp); currp = ntp;
#if defined(CH_CFG_IDLE_LEAVE_HOOK) if (otp->prio == IDLEPRIO) {
if (otp->p_prio == IDLEPRIO) {
CH_CFG_IDLE_LEAVE_HOOK(); CH_CFG_IDLE_LEAVE_HOOK();
} }
#endif
ntp->p_state = CH_STATE_CURRENT; /* The extracted thread is marked as current.*/
ntp->state = CH_STATE_CURRENT;
/* Swap operation as tail call.*/
chSysSwitch(ntp, otp); chSysSwitch(ntp, otp);
} }
} }
@ -426,15 +469,15 @@ void chSchRescheduleS(void) {
* @special * @special
*/ */
bool chSchIsPreemptionRequired(void) { bool chSchIsPreemptionRequired(void) {
tprio_t p1 = firstprio(&ch.rlist.r_queue); tprio_t p1 = firstprio(&ch.rlist.queue);
tprio_t p2 = currp->p_prio; tprio_t p2 = currp->prio;
#if CH_CFG_TIME_QUANTUM > 0 #if CH_CFG_TIME_QUANTUM > 0
/* If the running thread has not reached its time quantum, reschedule only /* If the running thread has not reached its time quantum, reschedule only
if the first thread on the ready queue has a higher priority. if the first thread on the ready queue has a higher priority.
Otherwise, if the running thread has used up its time quantum, reschedule Otherwise, if the running thread has used up its time quantum, reschedule
if the first thread on the ready queue has equal or higher priority.*/ if the first thread on the ready queue has equal or higher priority.*/
return (currp->p_preempt > (tslices_t)0) ? (p1 > p2) : (p1 >= p2); return (currp->preempt > (tslices_t)0) ? (p1 > p2) : (p1 >= p2);
#else #else
/* If the round robin preemption feature is not enabled then performs a /* If the round robin preemption feature is not enabled then performs a
simpler comparison.*/ simpler comparison.*/
@ -448,26 +491,30 @@ bool chSchIsPreemptionRequired(void) {
* threads having the same priority. The thread regains its time * threads having the same priority. The thread regains its time
* quantum. * quantum.
* @note Not a user function, it is meant to be invoked by the scheduler * @note Not a user function, it is meant to be invoked by the scheduler
* itself or from within the port layer. * itself.
* *
* @special * @special
*/ */
void chSchDoRescheduleBehind(void) { void chSchDoRescheduleBehind(void) {
thread_t *otp; thread_t *otp = currp;
otp = currp;
/* Picks the first thread from the ready queue and makes it current.*/ /* Picks the first thread from the ready queue and makes it current.*/
setcurrp(queue_fifo_remove(&ch.rlist.r_queue)); currp = queue_fifo_remove(&ch.rlist.queue);
#if defined(CH_CFG_IDLE_LEAVE_HOOK) if (otp->prio == IDLEPRIO) {
if (otp->p_prio == IDLEPRIO) {
CH_CFG_IDLE_LEAVE_HOOK(); CH_CFG_IDLE_LEAVE_HOOK();
} }
#endif
currp->p_state = CH_STATE_CURRENT; /* The extracted thread is marked as current.*/
currp->state = CH_STATE_CURRENT;
#if CH_CFG_TIME_QUANTUM > 0 #if CH_CFG_TIME_QUANTUM > 0
otp->p_preempt = (tslices_t)CH_CFG_TIME_QUANTUM; otp->preempt = (tslices_t)CH_CFG_TIME_QUANTUM;
#endif #endif
(void) chSchReadyI(otp);
/* Placing in ready list behind peers.*/
otp = chSchReadyI(otp);
/* Swap operation as tail call.*/
chSysSwitch(currp, otp); chSysSwitch(currp, otp);
} }
@ -476,34 +523,26 @@ void chSchDoRescheduleBehind(void) {
* @details The current thread is positioned in the ready list ahead of all * @details The current thread is positioned in the ready list ahead of all
* threads having the same priority. * threads having the same priority.
* @note Not a user function, it is meant to be invoked by the scheduler * @note Not a user function, it is meant to be invoked by the scheduler
* itself or from within the port layer. * itself.
* *
* @special * @special
*/ */
void chSchDoRescheduleAhead(void) { void chSchDoRescheduleAhead(void) {
thread_t *otp, *cp; thread_t *otp = currp;
otp = currp;
/* Picks the first thread from the ready queue and makes it current.*/ /* Picks the first thread from the ready queue and makes it current.*/
setcurrp(queue_fifo_remove(&ch.rlist.r_queue)); currp = queue_fifo_remove(&ch.rlist.queue);
#if defined(CH_CFG_IDLE_LEAVE_HOOK) if (otp->prio == IDLEPRIO) {
if (otp->p_prio == IDLEPRIO) {
CH_CFG_IDLE_LEAVE_HOOK(); CH_CFG_IDLE_LEAVE_HOOK();
} }
#endif
currp->p_state = CH_STATE_CURRENT;
otp->p_state = CH_STATE_READY; /* The extracted thread is marked as current.*/
cp = (thread_t *)&ch.rlist.r_queue; currp->state = CH_STATE_CURRENT;
do {
cp = cp->p_next;
} while (cp->p_prio > otp->p_prio);
/* Insertion on p_prev.*/
otp->p_next = cp;
otp->p_prev = cp->p_prev;
otp->p_prev->p_next = otp;
cp->p_prev = otp;
/* Placing in ready list ahead of peers.*/
otp = chSchReadyAheadI(otp);
/* Swap operation as tail call.*/
chSysSwitch(currp, otp); chSysSwitch(currp, otp);
} }
@ -518,25 +557,42 @@ void chSchDoRescheduleAhead(void) {
* @special * @special
*/ */
void chSchDoReschedule(void) { void chSchDoReschedule(void) {
thread_t *otp = currp;
/* Picks the first thread from the ready queue and makes it current.*/
currp = queue_fifo_remove(&ch.rlist.queue);
if (otp->prio == IDLEPRIO) {
CH_CFG_IDLE_LEAVE_HOOK();
}
/* The extracted thread is marked as current.*/
currp->state = CH_STATE_CURRENT;
#if CH_CFG_TIME_QUANTUM > 0 #if CH_CFG_TIME_QUANTUM > 0
/* If CH_CFG_TIME_QUANTUM is enabled then there are two different scenarios /* If CH_CFG_TIME_QUANTUM is enabled then there are two different scenarios
to handle on preemption: time quantum elapsed or not.*/ to handle on preemption: time quantum elapsed or not.*/
if (currp->p_preempt == (tslices_t)0) { if (currp->preempt == (tslices_t)0) {
/* The thread consumed its time quantum so it is enqueued behind threads /* The thread consumed its time quantum so it is enqueued behind threads
with same priority level, however, it acquires a new time quantum.*/ with same priority level, however, it acquires a new time quantum.*/
chSchDoRescheduleBehind(); otp = chSchReadyI(otp);
/* The thread being swapped out receives a new time quantum.*/
otp->preempt = (tslices_t)CH_CFG_TIME_QUANTUM;
} }
else { else {
/* The thread didn't consume all its time quantum so it is put ahead of /* The thread didn't consume all its time quantum so it is put ahead of
threads with equal priority and does not acquire a new time quantum.*/ threads with equal priority and does not acquire a new time quantum.*/
chSchDoRescheduleAhead(); otp = chSchReadyAheadI(otp);
} }
#else /* !(CH_CFG_TIME_QUANTUM > 0) */ #else /* !(CH_CFG_TIME_QUANTUM > 0) */
/* If the round-robin mechanism is disabled then the thread goes always /* If the round-robin mechanism is disabled then the thread goes always
ahead of its peers.*/ ahead of its peers.*/
chSchDoRescheduleAhead(); otp = chSchReadyAheadI(otp);
#endif /* !(CH_CFG_TIME_QUANTUM > 0) */ #endif /* !(CH_CFG_TIME_QUANTUM > 0) */
/* Swap operation as tail call.*/
chSysSwitch(currp, otp);
} }
/** @} */ /** @} */

View File

@ -98,8 +98,8 @@ void chSemObjectInit(semaphore_t *sp, cnt_t n) {
chDbgCheck((sp != NULL) && (n >= (cnt_t)0)); chDbgCheck((sp != NULL) && (n >= (cnt_t)0));
queue_init(&sp->s_queue); queue_init(&sp->queue);
sp->s_cnt = n; sp->cnt = n;
} }
/** /**
@ -149,14 +149,14 @@ void chSemResetI(semaphore_t *sp, cnt_t n) {
chDbgCheckClassI(); chDbgCheckClassI();
chDbgCheck((sp != NULL) && (n >= (cnt_t)0)); chDbgCheck((sp != NULL) && (n >= (cnt_t)0));
chDbgAssert(((sp->s_cnt >= (cnt_t)0) && queue_isempty(&sp->s_queue)) || chDbgAssert(((sp->cnt >= (cnt_t)0) && queue_isempty(&sp->queue)) ||
((sp->s_cnt < (cnt_t)0) && queue_notempty(&sp->s_queue)), ((sp->cnt < (cnt_t)0) && queue_notempty(&sp->queue)),
"inconsistent semaphore"); "inconsistent semaphore");
cnt = sp->s_cnt; cnt = sp->cnt;
sp->s_cnt = n; sp->cnt = n;
while (++cnt <= (cnt_t)0) { while (++cnt <= (cnt_t)0) {
chSchReadyI(queue_lifo_remove(&sp->s_queue))->p_u.rdymsg = MSG_RESET; chSchReadyI(queue_lifo_remove(&sp->queue))->u.rdymsg = MSG_RESET;
} }
} }
@ -198,16 +198,16 @@ msg_t chSemWaitS(semaphore_t *sp) {
chDbgCheckClassS(); chDbgCheckClassS();
chDbgCheck(sp != NULL); chDbgCheck(sp != NULL);
chDbgAssert(((sp->s_cnt >= (cnt_t)0) && queue_isempty(&sp->s_queue)) || chDbgAssert(((sp->cnt >= (cnt_t)0) && queue_isempty(&sp->queue)) ||
((sp->s_cnt < (cnt_t)0) && queue_notempty(&sp->s_queue)), ((sp->cnt < (cnt_t)0) && queue_notempty(&sp->queue)),
"inconsistent semaphore"); "inconsistent semaphore");
if (--sp->s_cnt < (cnt_t)0) { if (--sp->cnt < (cnt_t)0) {
currp->p_u.wtsemp = sp; currp->u.wtsemp = sp;
sem_insert(currp, &sp->s_queue); sem_insert(currp, &sp->queue);
chSchGoSleepS(CH_STATE_WTSEM); chSchGoSleepS(CH_STATE_WTSEM);
return currp->p_u.rdymsg; return currp->u.rdymsg;
} }
return MSG_OK; return MSG_OK;
@ -265,18 +265,18 @@ msg_t chSemWaitTimeoutS(semaphore_t *sp, systime_t time) {
chDbgCheckClassS(); chDbgCheckClassS();
chDbgCheck(sp != NULL); chDbgCheck(sp != NULL);
chDbgAssert(((sp->s_cnt >= (cnt_t)0) && queue_isempty(&sp->s_queue)) || chDbgAssert(((sp->cnt >= (cnt_t)0) && queue_isempty(&sp->queue)) ||
((sp->s_cnt < (cnt_t)0) && queue_notempty(&sp->s_queue)), ((sp->cnt < (cnt_t)0) && queue_notempty(&sp->queue)),
"inconsistent semaphore"); "inconsistent semaphore");
if (--sp->s_cnt < (cnt_t)0) { if (--sp->cnt < (cnt_t)0) {
if (TIME_IMMEDIATE == time) { if (TIME_IMMEDIATE == time) {
sp->s_cnt++; sp->cnt++;
return MSG_TIMEOUT; return MSG_TIMEOUT;
} }
currp->p_u.wtsemp = sp; currp->u.wtsemp = sp;
sem_insert(currp, &sp->s_queue); sem_insert(currp, &sp->queue);
return chSchGoSleepTimeoutS(CH_STATE_WTSEM, time); return chSchGoSleepTimeoutS(CH_STATE_WTSEM, time);
} }
@ -294,13 +294,13 @@ msg_t chSemWaitTimeoutS(semaphore_t *sp, systime_t time) {
void chSemSignal(semaphore_t *sp) { void chSemSignal(semaphore_t *sp) {
chDbgCheck(sp != NULL); chDbgCheck(sp != NULL);
chDbgAssert(((sp->s_cnt >= (cnt_t)0) && queue_isempty(&sp->s_queue)) || chDbgAssert(((sp->cnt >= (cnt_t)0) && queue_isempty(&sp->queue)) ||
((sp->s_cnt < (cnt_t)0) && queue_notempty(&sp->s_queue)), ((sp->cnt < (cnt_t)0) && queue_notempty(&sp->queue)),
"inconsistent semaphore"); "inconsistent semaphore");
chSysLock(); chSysLock();
if (++sp->s_cnt <= (cnt_t)0) { if (++sp->cnt <= (cnt_t)0) {
chSchWakeupS(queue_fifo_remove(&sp->s_queue), MSG_OK); chSchWakeupS(queue_fifo_remove(&sp->queue), MSG_OK);
} }
chSysUnlock(); chSysUnlock();
} }
@ -320,15 +320,15 @@ void chSemSignalI(semaphore_t *sp) {
chDbgCheckClassI(); chDbgCheckClassI();
chDbgCheck(sp != NULL); chDbgCheck(sp != NULL);
chDbgAssert(((sp->s_cnt >= (cnt_t)0) && queue_isempty(&sp->s_queue)) || chDbgAssert(((sp->cnt >= (cnt_t)0) && queue_isempty(&sp->queue)) ||
((sp->s_cnt < (cnt_t)0) && queue_notempty(&sp->s_queue)), ((sp->cnt < (cnt_t)0) && queue_notempty(&sp->queue)),
"inconsistent semaphore"); "inconsistent semaphore");
if (++sp->s_cnt <= (cnt_t)0) { if (++sp->cnt <= (cnt_t)0) {
/* Note, it is done this way in order to allow a tail call on /* Note, it is done this way in order to allow a tail call on
chSchReadyI().*/ chSchReadyI().*/
thread_t *tp = queue_fifo_remove(&sp->s_queue); thread_t *tp = queue_fifo_remove(&sp->queue);
tp->p_u.rdymsg = MSG_OK; tp->u.rdymsg = MSG_OK;
(void) chSchReadyI(tp); (void) chSchReadyI(tp);
} }
} }
@ -350,13 +350,13 @@ void chSemAddCounterI(semaphore_t *sp, cnt_t n) {
chDbgCheckClassI(); chDbgCheckClassI();
chDbgCheck((sp != NULL) && (n > (cnt_t)0)); chDbgCheck((sp != NULL) && (n > (cnt_t)0));
chDbgAssert(((sp->s_cnt >= (cnt_t)0) && queue_isempty(&sp->s_queue)) || chDbgAssert(((sp->cnt >= (cnt_t)0) && queue_isempty(&sp->queue)) ||
((sp->s_cnt < (cnt_t)0) && queue_notempty(&sp->s_queue)), ((sp->cnt < (cnt_t)0) && queue_notempty(&sp->queue)),
"inconsistent semaphore"); "inconsistent semaphore");
while (n > (cnt_t)0) { while (n > (cnt_t)0) {
if (++sp->s_cnt <= (cnt_t)0) { if (++sp->cnt <= (cnt_t)0) {
chSchReadyI(queue_fifo_remove(&sp->s_queue))->p_u.rdymsg = MSG_OK; chSchReadyI(queue_fifo_remove(&sp->queue))->u.rdymsg = MSG_OK;
} }
n--; n--;
} }
@ -379,23 +379,23 @@ msg_t chSemSignalWait(semaphore_t *sps, semaphore_t *spw) {
msg_t msg; msg_t msg;
chDbgCheck((sps != NULL) && (spw != NULL)); chDbgCheck((sps != NULL) && (spw != NULL));
chDbgAssert(((sps->s_cnt >= (cnt_t)0) && queue_isempty(&sps->s_queue)) || chDbgAssert(((sps->cnt >= (cnt_t)0) && queue_isempty(&sps->queue)) ||
((sps->s_cnt < (cnt_t)0) && queue_notempty(&sps->s_queue)), ((sps->cnt < (cnt_t)0) && queue_notempty(&sps->queue)),
"inconsistent semaphore"); "inconsistent semaphore");
chDbgAssert(((spw->s_cnt >= (cnt_t)0) && queue_isempty(&spw->s_queue)) || chDbgAssert(((spw->cnt >= (cnt_t)0) && queue_isempty(&spw->queue)) ||
((spw->s_cnt < (cnt_t)0) && queue_notempty(&spw->s_queue)), ((spw->cnt < (cnt_t)0) && queue_notempty(&spw->queue)),
"inconsistent semaphore"); "inconsistent semaphore");
chSysLock(); chSysLock();
if (++sps->s_cnt <= (cnt_t)0) { if (++sps->cnt <= (cnt_t)0) {
chSchReadyI(queue_fifo_remove(&sps->s_queue))->p_u.rdymsg = MSG_OK; chSchReadyI(queue_fifo_remove(&sps->queue))->u.rdymsg = MSG_OK;
} }
if (--spw->s_cnt < (cnt_t)0) { if (--spw->cnt < (cnt_t)0) {
thread_t *ctp = currp; thread_t *ctp = currp;
sem_insert(ctp, &spw->s_queue); sem_insert(ctp, &spw->queue);
ctp->p_u.wtsemp = spw; ctp->u.wtsemp = spw;
chSchGoSleepS(CH_STATE_WTSEM); chSchGoSleepS(CH_STATE_WTSEM);
msg = ctp->p_u.rdymsg; msg = ctp->u.rdymsg;
} }
else { else {
chSchRescheduleS(); chSchRescheduleS();

View File

@ -86,7 +86,7 @@ void _stats_increase_irq(void) {
void _stats_ctxswc(thread_t *ntp, thread_t *otp) { void _stats_ctxswc(thread_t *ntp, thread_t *otp) {
ch.kernel_stats.n_ctxswc++; ch.kernel_stats.n_ctxswc++;
chTMChainMeasurementToX(&otp->p_stats, &ntp->p_stats); chTMChainMeasurementToX(&otp->stats, &ntp->stats);
} }
/** /**

View File

@ -91,13 +91,11 @@ static void _idle_thread(void *p) {
* @special * @special
*/ */
void chSysInit(void) { void chSysInit(void) {
#if CH_DBG_ENABLE_STACK_CHECK == TRUE
extern stkalign_t __main_thread_stack_base__; extern stkalign_t __main_thread_stack_base__;
#endif
port_init();
_scheduler_init(); _scheduler_init();
_vt_init(); _vt_init();
#if CH_DBG_SYSTEM_STATE_CHECK == TRUE #if CH_DBG_SYSTEM_STATE_CHECK == TRUE
ch.dbg.isr_cnt = (cnt_t)0; ch.dbg.isr_cnt = (cnt_t)0;
ch.dbg.lock_cnt = (cnt_t)0; ch.dbg.lock_cnt = (cnt_t)0;
@ -114,30 +112,34 @@ void chSysInit(void) {
#if CH_DBG_STATISTICS == TRUE #if CH_DBG_STATISTICS == TRUE
_stats_init(); _stats_init();
#endif #endif
#if CH_DBG_ENABLE_TRACE == TRUE #if CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_NONE
_dbg_trace_init(); _dbg_trace_init();
#endif #endif
#if CH_CFG_NO_IDLE_THREAD == FALSE #if CH_CFG_NO_IDLE_THREAD == FALSE
/* Now this instructions flow becomes the main thread.*/ /* Now this instructions flow becomes the main thread.*/
setcurrp(_thread_init(&ch.mainthread, NORMALPRIO)); currp = _thread_init(&ch.mainthread, "main", NORMALPRIO);
#else #else
/* Now this instructions flow becomes the idle thread.*/ /* Now this instructions flow becomes the idle thread.*/
setcurrp(_thread_init(&ch.mainthread, IDLEPRIO)); currp = _thread_init(&ch.mainthread, "idle", IDLEPRIO));
#endif #endif
currp->p_state = CH_STATE_CURRENT; /* Setting up the base address of the static main thread stack.*/
#if CH_DBG_ENABLE_STACK_CHECK == TRUE currp->stklimit = &__main_thread_stack_base__;
/* This is a special case because the main thread thread_t structure is not
adjacent to its stack area.*/ /* Setting up the caller as current thread.*/
currp->p_stklimit = &__main_thread_stack_base__; currp->state = CH_STATE_CURRENT;
#endif
/* Port layer initialization last because it depend on some of the
initializations performed before.*/
port_init();
#if CH_DBG_STATISTICS == TRUE #if CH_DBG_STATISTICS == TRUE
/* Starting measurement for this thread.*/ /* Starting measurement for this thread.*/
chTMStartMeasurementX(&currp->p_stats); chTMStartMeasurementX(&currp->p_stats);
#endif #endif
/* It is alive now.*/
chSysEnable(); chSysEnable();
#if CH_CFG_USE_REGISTRY == TRUE #if CH_CFG_USE_REGISTRY == TRUE
@ -148,15 +150,19 @@ void chSysInit(void) {
#if CH_CFG_NO_IDLE_THREAD == FALSE #if CH_CFG_NO_IDLE_THREAD == FALSE
{ {
static const thread_descriptor_t idle_descriptor = {
"idle",
THD_WORKING_AREA_BASE(ch.idle_thread_wa),
THD_WORKING_AREA_END(ch.idle_thread_wa),
IDLEPRIO,
_idle_thread,
NULL
};
/* This thread has the lowest priority in the system, its role is just to /* This thread has the lowest priority in the system, its role is just to
serve interrupts in its context while keeping the lowest energy saving serve interrupts in its context while keeping the lowest energy saving
mode compatible with the system status.*/ mode compatible with the system status.*/
thread_t *tp = chThdCreateStatic(ch.idle_thread_wa, (void) chThdCreate(&idle_descriptor);
sizeof(ch.idle_thread_wa),
IDLEPRIO,
(tfunc_t)_idle_thread,
NULL);
chRegSetThreadNameX(tp, "idle");
} }
#endif #endif
} }
@ -177,9 +183,11 @@ void chSysHalt(const char *reason) {
port_disable(); port_disable();
#if defined(CH_CFG_SYSTEM_HALT_HOOK) || defined(__DOXYGEN__) /* Halt hook code, usually empty.*/
CH_CFG_SYSTEM_HALT_HOOK(reason); CH_CFG_SYSTEM_HALT_HOOK(reason);
#endif
/* Logging the event.*/
_dbg_trace_halt(reason);
/* Pointing to the passed message.*/ /* Pointing to the passed message.*/
ch.dbg.panic_msg = reason; ch.dbg.panic_msg = reason;
@ -224,17 +232,17 @@ bool chSysIntegrityCheckI(unsigned testmask) {
/* Scanning the ready list forward.*/ /* Scanning the ready list forward.*/
n = (cnt_t)0; n = (cnt_t)0;
tp = ch.rlist.r_queue.p_next; tp = ch.rlist.queue.next;
while (tp != (thread_t *)&ch.rlist.r_queue) { while (tp != (thread_t *)&ch.rlist.queue) {
n++; n++;
tp = tp->p_next; tp = tp->next;
} }
/* Scanning the ready list backward.*/ /* Scanning the ready list backward.*/
tp = ch.rlist.r_queue.p_prev; tp = ch.rlist.queue.prev;
while (tp != (thread_t *)&ch.rlist.r_queue) { while (tp != (thread_t *)&ch.rlist.queue) {
n--; n--;
tp = tp->p_prev; tp = tp->prev;
} }
/* The number of elements must match.*/ /* The number of elements must match.*/
@ -249,17 +257,17 @@ bool chSysIntegrityCheckI(unsigned testmask) {
/* Scanning the timers list forward.*/ /* Scanning the timers list forward.*/
n = (cnt_t)0; n = (cnt_t)0;
vtp = ch.vtlist.vt_next; vtp = ch.vtlist.next;
while (vtp != (virtual_timer_t *)&ch.vtlist) { while (vtp != (virtual_timer_t *)&ch.vtlist) {
n++; n++;
vtp = vtp->vt_next; vtp = vtp->next;
} }
/* Scanning the timers list backward.*/ /* Scanning the timers list backward.*/
vtp = ch.vtlist.vt_prev; vtp = ch.vtlist.prev;
while (vtp != (virtual_timer_t *)&ch.vtlist) { while (vtp != (virtual_timer_t *)&ch.vtlist) {
n--; n--;
vtp = vtp->vt_prev; vtp = vtp->prev;
} }
/* The number of elements must match.*/ /* The number of elements must match.*/
@ -274,17 +282,17 @@ bool chSysIntegrityCheckI(unsigned testmask) {
/* Scanning the ready list forward.*/ /* Scanning the ready list forward.*/
n = (cnt_t)0; n = (cnt_t)0;
tp = ch.rlist.r_newer; tp = ch.rlist.newer;
while (tp != (thread_t *)&ch.rlist) { while (tp != (thread_t *)&ch.rlist) {
n++; n++;
tp = tp->p_newer; tp = tp->newer;
} }
/* Scanning the ready list backward.*/ /* Scanning the ready list backward.*/
tp = ch.rlist.r_older; tp = ch.rlist.older;
while (tp != (thread_t *)&ch.rlist) { while (tp != (thread_t *)&ch.rlist) {
n--; n--;
tp = tp->p_older; tp = tp->older;
} }
/* The number of elements must match.*/ /* The number of elements must match.*/
@ -320,18 +328,16 @@ void chSysTimerHandlerI(void) {
#if CH_CFG_TIME_QUANTUM > 0 #if CH_CFG_TIME_QUANTUM > 0
/* Running thread has not used up quantum yet? */ /* Running thread has not used up quantum yet? */
if (currp->p_preempt > (tslices_t)0) { if (currp->preempt > (tslices_t)0) {
/* Decrement remaining quantum.*/ /* Decrement remaining quantum.*/
currp->p_preempt--; currp->preempt--;
} }
#endif #endif
#if CH_DBG_THREADS_PROFILING == TRUE #if CH_DBG_THREADS_PROFILING == TRUE
currp->p_time++; currp->time++;
#endif #endif
chVTDoTickI(); chVTDoTickI();
#if defined(CH_CFG_SYSTEM_TICK_HOOK)
CH_CFG_SYSTEM_TICK_HOOK(); CH_CFG_SYSTEM_TICK_HOOK();
#endif
} }
/** /**

View File

@ -45,10 +45,6 @@
* - <b>SetPriority</b>, a thread changes its own priority level. * - <b>SetPriority</b>, a thread changes its own priority level.
* - <b>Yield</b>, a thread voluntarily renounces to its time slot. * - <b>Yield</b>, a thread voluntarily renounces to its time slot.
* . * .
* The threads subsystem is implicitly included in kernel however
* some of its part may be excluded by disabling them in @p chconf.h,
* see the @p CH_CFG_USE_WAITEXIT and @p CH_CFG_USE_DYNAMIC configuration
* options.
* @{ * @{
*/ */
@ -83,51 +79,42 @@
* @note This is an internal functions, do not use it in application code. * @note This is an internal functions, do not use it in application code.
* *
* @param[in] tp pointer to the thread * @param[in] tp pointer to the thread
* @param[in] name thread name
* @param[in] prio the priority level for the new thread * @param[in] prio the priority level for the new thread
* @return The same thread pointer passed as parameter. * @return The same thread pointer passed as parameter.
* *
* @notapi * @notapi
*/ */
thread_t *_thread_init(thread_t *tp, tprio_t prio) { thread_t *_thread_init(thread_t *tp, const char *name, tprio_t prio) {
tp->p_prio = prio; tp->prio = prio;
tp->p_state = CH_STATE_WTSTART;
tp->p_flags = CH_FLAG_MODE_STATIC;
#if CH_CFG_TIME_QUANTUM > 0 #if CH_CFG_TIME_QUANTUM > 0
tp->p_preempt = (tslices_t)CH_CFG_TIME_QUANTUM; tp->preempt = (tslices_t)CH_CFG_TIME_QUANTUM;
#endif #endif
#if CH_CFG_USE_MUTEXES == TRUE #if CH_CFG_USE_MUTEXES == TRUE
tp->p_realprio = prio; tp->realprio = prio;
tp->p_mtxlist = NULL; tp->mtxlist = NULL;
#endif #endif
#if CH_CFG_USE_EVENTS == TRUE #if CH_CFG_USE_EVENTS == TRUE
tp->p_epending = (eventmask_t)0; tp->epending = (eventmask_t)0;
#endif #endif
#if CH_DBG_THREADS_PROFILING == TRUE #if CH_DBG_THREADS_PROFILING == TRUE
tp->p_time = (systime_t)0; tp->time = (systime_t)0;
#endif
#if CH_CFG_USE_DYNAMIC == TRUE
tp->p_refs = (trefs_t)1;
#endif #endif
#if CH_CFG_USE_REGISTRY == TRUE #if CH_CFG_USE_REGISTRY == TRUE
tp->p_name = NULL; tp->name = name;
REG_INSERT(tp); REG_INSERT(tp);
#endif #endif
#if CH_CFG_USE_WAITEXIT == TRUE #if CH_CFG_USE_WAITEXIT == TRUE
list_init(&tp->p_waiting); list_init(&tp->waiting);
#endif #endif
#if CH_CFG_USE_MESSAGES == TRUE #if CH_CFG_USE_MESSAGES == TRUE
queue_init(&tp->p_msgqueue); queue_init(&tp->msgqueue);
#endif
#if CH_DBG_ENABLE_STACK_CHECK == TRUE
tp->p_stklimit = (stkalign_t *)(tp + 1);
#endif #endif
#if CH_DBG_STATISTICS == TRUE #if CH_DBG_STATISTICS == TRUE
chTMObjectInit(&tp->p_stats); chTMObjectInit(&tp->stats);
#endif #endif
#if defined(CH_CFG_THREAD_INIT_HOOK)
CH_CFG_THREAD_INIT_HOOK(tp); CH_CFG_THREAD_INIT_HOOK(tp);
#endif
return tp; return tp;
} }
@ -162,30 +149,126 @@ void _thread_memfill(uint8_t *startp, uint8_t *endp, uint8_t v) {
* @p CH_DBG_FILL_THREADS debug option because it would keep * @p CH_DBG_FILL_THREADS debug option because it would keep
* the kernel locked for too much time. * the kernel locked for too much time.
* *
* @param[out] wsp pointer to a working area dedicated to the thread stack * @param[out] tdp pointer to the thread descriptor
* @param[in] size size of the working area
* @param[in] prio the priority level for the new thread
* @param[in] pf the thread function
* @param[in] arg an argument passed to the thread function. It can be
* @p NULL.
* @return The pointer to the @p thread_t structure allocated for * @return The pointer to the @p thread_t structure allocated for
* the thread into the working space area. * the thread into the working space area.
* *
* @iclass * @iclass
*/ */
thread_t *chThdCreateI(void *wsp, size_t size, thread_t *chThdCreateSuspendedI(const thread_descriptor_t *tdp) {
tprio_t prio, tfunc_t pf, void *arg) { thread_t *tp;
/* The thread structure is laid out in the lower part of the thread
workspace.*/
thread_t *tp = wsp;
chDbgCheckClassI(); chDbgCheckClassI();
chDbgCheck((wsp != NULL) && (size >= THD_WORKING_AREA_SIZE(0)) && chDbgCheck(tdp != NULL);
(prio <= HIGHPRIO) && (pf != NULL)); chDbgCheck(MEM_IS_ALIGNED(tdp->wbase, PORT_WORKING_AREA_ALIGN) &&
MEM_IS_ALIGNED(tdp->wend, PORT_STACK_ALIGN) &&
(tdp->wend > tdp->wbase) &&
((size_t)((tdp->wend - tdp->wbase) *
sizeof (stkalign_t)) >= THD_WORKING_AREA_SIZE(0)));
chDbgCheck((tdp->prio <= HIGHPRIO) && (tdp->funcp != NULL));
PORT_SETUP_CONTEXT(tp, wsp, size, pf, arg); /* The thread structure is laid out in the upper part of the thread
workspace. The thread position structure is aligned to the required
stack alignment because it represents the stack top.*/
tp = (thread_t *)((uint8_t *)tdp->wend -
MEM_ALIGN_NEXT(sizeof (thread_t), PORT_STACK_ALIGN));
return _thread_init(tp, prio); /* Initial state.*/
tp->state = CH_STATE_WTSTART;
/* Stack boundary.*/
tp->stklimit = tdp->wbase;
/* Setting up the port-dependent part of the working area.*/
PORT_SETUP_CONTEXT(tp, tdp->wbase, tp, tdp->funcp, tdp->arg);
/* The driver object is initialized but not started.*/
return _thread_init(tp, tdp->name, tdp->prio);
}
/**
* @brief Creates a new thread into a static memory area.
* @details The new thread is initialized but not inserted in the ready list,
* the initial state is @p CH_STATE_WTSTART.
* @post The initialized thread can be subsequently started by invoking
* @p chThdStart(), @p chThdStartI() or @p chSchWakeupS()
* depending on the execution context.
* @note A thread can terminate by calling @p chThdExit() or by simply
* returning from its main function.
*
* @param[out] tdp pointer to the thread descriptor
* @return The pointer to the @p thread_t structure allocated for
* the thread into the working space area.
*
* @api
*/
thread_t *chThdCreateSuspended(const thread_descriptor_t *tdp) {
thread_t *tp;
#if CH_DBG_FILL_THREADS == TRUE
_thread_memfill((uint8_t *)tdp->wbase,
(uint8_t *)tdp->wend,
CH_DBG_STACK_FILL_VALUE);
#endif
chSysLock();
tp = chThdCreateSuspendedI(tdp);
chSysUnlock();
return tp;
}
/**
* @brief Creates a new thread into a static memory area.
* @details The new thread is initialized and make ready to execute.
* @post The initialized thread can be subsequently started by invoking
* @p chThdStart(), @p chThdStartI() or @p chSchWakeupS()
* depending on the execution context.
* @note A thread can terminate by calling @p chThdExit() or by simply
* returning from its main function.
* @note Threads created using this function do not obey to the
* @p CH_DBG_FILL_THREADS debug option because it would keep
* the kernel locked for too much time.
*
* @param[out] tdp pointer to the thread descriptor
* @return The pointer to the @p thread_t structure allocated for
* the thread into the working space area.
*
* @iclass
*/
thread_t *chThdCreateI(const thread_descriptor_t *tdp) {
return chSchReadyI(chThdCreateSuspendedI(tdp));
}
/**
* @brief Creates a new thread into a static memory area.
* @details The new thread is initialized and make ready to execute.
* @note A thread can terminate by calling @p chThdExit() or by simply
* returning from its main function.
*
* @param[out] tdp pointer to the thread descriptor
* @return The pointer to the @p thread_t structure allocated for
* the thread into the working space area.
*
* @iclass
*/
thread_t *chThdCreate(const thread_descriptor_t *tdp) {
thread_t *tp;
#if CH_DBG_FILL_THREADS == TRUE
_thread_memfill((uint8_t *)tdp->wbase,
(uint8_t *)tdp->wend,
CH_DBG_STACK_FILL_VALUE);
#endif
chSysLock();
tp = chThdCreateSuspendedI(tdp);
chSchWakeupS(tp, MSG_OK);
chSysUnlock();
return tp;
} }
/** /**
@ -208,17 +291,35 @@ thread_t *chThdCreateStatic(void *wsp, size_t size,
tprio_t prio, tfunc_t pf, void *arg) { tprio_t prio, tfunc_t pf, void *arg) {
thread_t *tp; thread_t *tp;
chDbgCheck((wsp != NULL) &&
MEM_IS_ALIGNED(wsp, PORT_WORKING_AREA_ALIGN) &&
(size >= THD_WORKING_AREA_SIZE(0)) &&
MEM_IS_ALIGNED(size, PORT_STACK_ALIGN) &&
(prio <= HIGHPRIO) && (pf != NULL));
#if CH_DBG_FILL_THREADS == TRUE #if CH_DBG_FILL_THREADS == TRUE
_thread_memfill((uint8_t *)wsp, _thread_memfill((uint8_t *)wsp,
(uint8_t *)wsp + sizeof(thread_t),
CH_DBG_THREAD_FILL_VALUE);
_thread_memfill((uint8_t *)wsp + sizeof(thread_t),
(uint8_t *)wsp + size, (uint8_t *)wsp + size,
CH_DBG_STACK_FILL_VALUE); CH_DBG_STACK_FILL_VALUE);
#endif #endif
chSysLock(); chSysLock();
tp = chThdCreateI(wsp, size, prio, pf, arg);
/* The thread structure is laid out in the upper part of the thread
workspace. The thread position structure is aligned to the required
stack alignment because it represents the stack top.*/
tp = (thread_t *)((uint8_t *)wsp + size -
MEM_ALIGN_NEXT(sizeof (thread_t), PORT_STACK_ALIGN));
/* Stack boundary.*/
tp->stklimit = (stkalign_t *)wsp;
/* Setting up the port-dependent part of the working area.*/
PORT_SETUP_CONTEXT(tp, wsp, tp, pf, arg);
tp = _thread_init(tp, "noname", prio);
/* Starting the thread immediately.*/
chSchWakeupS(tp, MSG_OK); chSchWakeupS(tp, MSG_OK);
chSysUnlock(); chSysUnlock();
@ -262,14 +363,14 @@ tprio_t chThdSetPriority(tprio_t newprio) {
chSysLock(); chSysLock();
#if CH_CFG_USE_MUTEXES == TRUE #if CH_CFG_USE_MUTEXES == TRUE
oldprio = currp->p_realprio; oldprio = currp->realprio;
if ((currp->p_prio == currp->p_realprio) || (newprio > currp->p_prio)) { if ((currp->prio == currp->realprio) || (newprio > currp->prio)) {
currp->p_prio = newprio; currp->prio = newprio;
} }
currp->p_realprio = newprio; currp->realprio = newprio;
#else #else
oldprio = currp->p_prio; oldprio = currp->prio;
currp->p_prio = newprio; currp->prio = newprio;
#endif #endif
chSchRescheduleS(); chSchRescheduleS();
chSysUnlock(); chSysUnlock();
@ -277,25 +378,6 @@ tprio_t chThdSetPriority(tprio_t newprio) {
return oldprio; return oldprio;
} }
/**
* @brief Requests a thread termination.
* @pre The target thread must be written to invoke periodically
* @p chThdShouldTerminate() and terminate cleanly if it returns
* @p true.
* @post The specified thread will terminate after detecting the termination
* condition.
*
* @param[in] tp pointer to the thread
*
* @api
*/
void chThdTerminate(thread_t *tp) {
chSysLock();
tp->p_flags |= CH_FLAG_TERMINATE;
chSysUnlock();
}
/** /**
* @brief Suspends the invoking thread for the specified time. * @brief Suspends the invoking thread for the specified time.
* *
@ -417,21 +499,15 @@ void chThdExit(msg_t msg) {
void chThdExitS(msg_t msg) { void chThdExitS(msg_t msg) {
thread_t *tp = currp; thread_t *tp = currp;
tp->p_u.exitcode = msg; tp->u.exitcode = msg;
#if defined(CH_CFG_THREAD_EXIT_HOOK)
CH_CFG_THREAD_EXIT_HOOK(tp); CH_CFG_THREAD_EXIT_HOOK(tp);
#endif
#if CH_CFG_USE_WAITEXIT == TRUE #if CH_CFG_USE_WAITEXIT == TRUE
while (list_notempty(&tp->p_waiting)) { while (list_notempty(&tp->waiting)) {
(void) chSchReadyI(list_remove(&tp->p_waiting)); (void) chSchReadyI(list_remove(&tp->waiting));
} }
#endif #endif
#if CH_CFG_USE_REGISTRY == TRUE #if CH_CFG_USE_REGISTRY == TRUE
/* Static threads are immediately removed from the registry because
there is no memory to recover.*/
if ((tp->p_flags & CH_FLAG_MODE_MASK) == CH_FLAG_MODE_STATIC) {
REG_REMOVE(tp); REG_REMOVE(tp);
}
#endif #endif
chSchGoSleepS(CH_STATE_FINAL); chSchGoSleepS(CH_STATE_FINAL);
@ -443,28 +519,12 @@ void chThdExitS(msg_t msg) {
/** /**
* @brief Blocks the execution of the invoking thread until the specified * @brief Blocks the execution of the invoking thread until the specified
* thread terminates then the exit code is returned. * thread terminates then the exit code is returned.
* @details This function waits for the specified thread to terminate then
* decrements its reference counter, if the counter reaches zero then
* the thread working area is returned to the proper allocator.<br>
* The memory used by the exited thread is handled in different ways
* depending on the API that spawned the thread:
* - If the thread was spawned by @p chThdCreateStatic() or by
* @p chThdCreateI() then nothing happens and the thread working
* area is not released or modified in any way. This is the
* default, totally static, behavior.
* - If the thread was spawned by @p chThdCreateFromHeap() then
* the working area is returned to the system heap.
* - If the thread was spawned by @p chThdCreateFromMemoryPool()
* then the working area is returned to the owning memory pool.
* .
* @pre The configuration option @p CH_CFG_USE_WAITEXIT must be enabled in * @pre The configuration option @p CH_CFG_USE_WAITEXIT must be enabled in
* order to use this function. * order to use this function.
* @post Enabling @p chThdWait() requires 2-4 (depending on the * @post Enabling @p chThdWait() requires 2-4 (depending on the
* architecture) extra bytes in the @p thread_t structure. * architecture) extra bytes in the @p thread_t structure.
* @post After invoking @p chThdWait() the thread pointer becomes invalid * @post After invoking @p chThdWait() the thread pointer becomes invalid
* and must not be used as parameter for further system calls. * and must not be used as parameter for further system calls.
* @note If @p CH_CFG_USE_DYNAMIC is not specified this function just waits for
* the thread termination, no memory allocators are involved.
* *
* @param[in] tp pointer to the thread * @param[in] tp pointer to the thread
* @return The exit code from the terminated thread. * @return The exit code from the terminated thread.
@ -478,21 +538,13 @@ msg_t chThdWait(thread_t *tp) {
chSysLock(); chSysLock();
chDbgAssert(tp != currp, "waiting self"); chDbgAssert(tp != currp, "waiting self");
#if CH_CFG_USE_DYNAMIC == TRUE if (tp->state != CH_STATE_FINAL) {
chDbgAssert(tp->p_refs > (trefs_t)0, "not referenced"); list_insert(currp, &tp->waiting);
#endif
if (tp->p_state != CH_STATE_FINAL) {
list_insert(currp, &tp->p_waiting);
chSchGoSleepS(CH_STATE_WTEXIT); chSchGoSleepS(CH_STATE_WTEXIT);
} }
msg = tp->p_u.exitcode; msg = tp->u.exitcode;
chSysUnlock(); chSysUnlock();
#if CH_CFG_USE_DYNAMIC == TRUE
/* Releasing a lock if it is a dynamic thread.*/
chThdRelease(tp);
#endif
return msg; return msg;
} }
#endif /* CH_CFG_USE_WAITEXIT */ #endif /* CH_CFG_USE_WAITEXIT */
@ -513,10 +565,10 @@ msg_t chThdSuspendS(thread_reference_t *trp) {
chDbgAssert(*trp == NULL, "not NULL"); chDbgAssert(*trp == NULL, "not NULL");
*trp = tp; *trp = tp;
tp->p_u.wttrp = trp; tp->u.wttrp = trp;
chSchGoSleepS(CH_STATE_SUSPENDED); chSchGoSleepS(CH_STATE_SUSPENDED);
return chThdGetSelfX()->p_u.rdymsg; return chThdGetSelfX()->u.rdymsg;
} }
/** /**
@ -548,7 +600,7 @@ msg_t chThdSuspendTimeoutS(thread_reference_t *trp, systime_t timeout) {
} }
*trp = tp; *trp = tp;
tp->p_u.wttrp = trp; tp->u.wttrp = trp;
return chSchGoSleepTimeoutS(CH_STATE_SUSPENDED, timeout); return chSchGoSleepTimeoutS(CH_STATE_SUSPENDED, timeout);
} }
@ -568,11 +620,10 @@ void chThdResumeI(thread_reference_t *trp, msg_t msg) {
if (*trp != NULL) { if (*trp != NULL) {
thread_t *tp = *trp; thread_t *tp = *trp;
chDbgAssert(tp->p_state == CH_STATE_SUSPENDED, chDbgAssert(tp->state == CH_STATE_SUSPENDED, "not CH_STATE_SUSPENDED");
"not THD_STATE_SUSPENDED");
*trp = NULL; *trp = NULL;
tp->p_u.rdymsg = msg; tp->u.rdymsg = msg;
(void) chSchReadyI(tp); (void) chSchReadyI(tp);
} }
} }
@ -592,8 +643,7 @@ void chThdResumeS(thread_reference_t *trp, msg_t msg) {
if (*trp != NULL) { if (*trp != NULL) {
thread_t *tp = *trp; thread_t *tp = *trp;
chDbgAssert(tp->p_state == CH_STATE_SUSPENDED, chDbgAssert(tp->state == CH_STATE_SUSPENDED, "not CH_STATE_SUSPENDED");
"not THD_STATE_SUSPENDED");
*trp = NULL; *trp = NULL;
chSchWakeupS(tp, msg); chSchWakeupS(tp, msg);

View File

@ -60,13 +60,13 @@
*/ */
void _vt_init(void) { void _vt_init(void) {
ch.vtlist.vt_next = (virtual_timer_t *)&ch.vtlist; ch.vtlist.next = (virtual_timer_t *)&ch.vtlist;
ch.vtlist.vt_prev = (virtual_timer_t *)&ch.vtlist; ch.vtlist.prev = (virtual_timer_t *)&ch.vtlist;
ch.vtlist.vt_delta = (systime_t)-1; ch.vtlist.delta = (systime_t)-1;
#if CH_CFG_ST_TIMEDELTA == 0 #if CH_CFG_ST_TIMEDELTA == 0
ch.vtlist.vt_systime = (systime_t)0; ch.vtlist.systime = (systime_t)0;
#else /* CH_CFG_ST_TIMEDELTA > 0 */ #else /* CH_CFG_ST_TIMEDELTA > 0 */
ch.vtlist.vt_lasttime = (systime_t)0; ch.vtlist.lasttime = (systime_t)0;
#endif /* CH_CFG_ST_TIMEDELTA > 0 */ #endif /* CH_CFG_ST_TIMEDELTA > 0 */
} }
@ -100,8 +100,8 @@ void chVTDoSetI(virtual_timer_t *vtp, systime_t delay,
chDbgCheckClassI(); chDbgCheckClassI();
chDbgCheck((vtp != NULL) && (vtfunc != NULL) && (delay != TIME_IMMEDIATE)); chDbgCheck((vtp != NULL) && (vtfunc != NULL) && (delay != TIME_IMMEDIATE));
vtp->vt_par = par; vtp->par = par;
vtp->vt_func = vtfunc; vtp->func = vtfunc;
#if CH_CFG_ST_TIMEDELTA > 0 #if CH_CFG_ST_TIMEDELTA > 0
{ {
@ -114,30 +114,30 @@ void chVTDoSetI(virtual_timer_t *vtp, systime_t delay,
} }
/* Special case where the timers list is empty.*/ /* Special case where the timers list is empty.*/
if (&ch.vtlist == (virtual_timers_list_t *)ch.vtlist.vt_next) { if (&ch.vtlist == (virtual_timers_list_t *)ch.vtlist.next) {
/* The delta list is empty, the current time becomes the new /* The delta list is empty, the current time becomes the new
delta list base time, the timer is inserted.*/ delta list base time, the timer is inserted.*/
ch.vtlist.vt_lasttime = now; ch.vtlist.lasttime = now;
ch.vtlist.vt_next = vtp; ch.vtlist.next = vtp;
ch.vtlist.vt_prev = vtp; ch.vtlist.prev = vtp;
vtp->vt_next = (virtual_timer_t *)&ch.vtlist; vtp->next = (virtual_timer_t *)&ch.vtlist;
vtp->vt_prev = (virtual_timer_t *)&ch.vtlist; vtp->prev = (virtual_timer_t *)&ch.vtlist;
vtp->vt_delta = delay; vtp->delta = delay;
/* Being the first element in the list the alarm timer is started.*/ /* Being the first element in the list the alarm timer is started.*/
port_timer_start_alarm(ch.vtlist.vt_lasttime + delay); port_timer_start_alarm(ch.vtlist.lasttime + delay);
return; return;
} }
/* Special case where the timer will be placed as first element in a /* Special case where the timer will be placed as first element in a
non-empty list, the alarm needs to be recalculated.*/ non-empty list, the alarm needs to be recalculated.*/
delta = now + delay - ch.vtlist.vt_lasttime; delta = now + delay - ch.vtlist.lasttime;
if (delta < ch.vtlist.vt_next->vt_delta) { if (delta < ch.vtlist.next->delta) {
/* New alarm deadline.*/ /* New alarm deadline.*/
port_timer_set_alarm(ch.vtlist.vt_lasttime + delta); port_timer_set_alarm(ch.vtlist.lasttime + delta);
} }
} }
#else /* CH_CFG_ST_TIMEDELTA == 0 */ #else /* CH_CFG_ST_TIMEDELTA == 0 */
@ -147,23 +147,23 @@ void chVTDoSetI(virtual_timer_t *vtp, systime_t delay,
/* The delta list is scanned in order to find the correct position for /* The delta list is scanned in order to find the correct position for
this timer. */ this timer. */
p = ch.vtlist.vt_next; p = ch.vtlist.next;
while (p->vt_delta < delta) { while (p->delta < delta) {
delta -= p->vt_delta; delta -= p->delta;
p = p->vt_next; p = p->next;
} }
/* The timer is inserted in the delta list.*/ /* The timer is inserted in the delta list.*/
vtp->vt_next = p; vtp->next = p;
vtp->vt_prev = vtp->vt_next->vt_prev; vtp->prev = vtp->next->prev;
vtp->vt_prev->vt_next = vtp; vtp->prev->next = vtp;
p->vt_prev = vtp; p->prev = vtp;
vtp->vt_delta = delta vtp->delta = delta
/* Special case when the timer is in last position in the list, the /* Special case when the timer is in last position in the list, the
value in the header must be restored.*/; value in the header must be restored.*/;
p->vt_delta -= delta; p->delta -= delta;
ch.vtlist.vt_delta = (systime_t)-1; ch.vtlist.delta = (systime_t)-1;
} }
/** /**
@ -178,71 +178,71 @@ void chVTDoResetI(virtual_timer_t *vtp) {
chDbgCheckClassI(); chDbgCheckClassI();
chDbgCheck(vtp != NULL); chDbgCheck(vtp != NULL);
chDbgAssert(vtp->vt_func != NULL, "timer not set or already triggered"); chDbgAssert(vtp->func != NULL, "timer not set or already triggered");
#if CH_CFG_ST_TIMEDELTA == 0 #if CH_CFG_ST_TIMEDELTA == 0
/* The delta of the timer is added to the next timer.*/ /* The delta of the timer is added to the next timer.*/
vtp->vt_next->vt_delta += vtp->vt_delta; vtp->next->delta += vtp->delta;
/* Removing the element from the delta list.*/ /* Removing the element from the delta list.*/
vtp->vt_prev->vt_next = vtp->vt_next; vtp->prev->next = vtp->next;
vtp->vt_next->vt_prev = vtp->vt_prev; vtp->next->prev = vtp->prev;
vtp->vt_func = NULL; vtp->func = NULL;
/* The above code changes the value in the header when the removed element /* The above code changes the value in the header when the removed element
is the last of the list, restoring it.*/ is the last of the list, restoring it.*/
ch.vtlist.vt_delta = (systime_t)-1; ch.vtlist.delta = (systime_t)-1;
#else /* CH_CFG_ST_TIMEDELTA > 0 */ #else /* CH_CFG_ST_TIMEDELTA > 0 */
systime_t nowdelta, delta; systime_t nowdelta, delta;
/* If the timer is not the first of the list then it is simply unlinked /* If the timer is not the first of the list then it is simply unlinked
else the operation is more complex.*/ else the operation is more complex.*/
if (ch.vtlist.vt_next != vtp) { if (ch.vtlist.next != vtp) {
/* Removing the element from the delta list.*/ /* Removing the element from the delta list.*/
vtp->vt_prev->vt_next = vtp->vt_next; vtp->prev->next = vtp->next;
vtp->vt_next->vt_prev = vtp->vt_prev; vtp->next->prev = vtp->prev;
vtp->vt_func = NULL; vtp->func = NULL;
/* Adding delta to the next element, if it is not the last one.*/ /* Adding delta to the next element, if it is not the last one.*/
if (&ch.vtlist != (virtual_timers_list_t *)vtp->vt_next) if (&ch.vtlist != (virtual_timers_list_t *)vtp->next)
vtp->vt_next->vt_delta += vtp->vt_delta; vtp->next->delta += vtp->delta;
return; return;
} }
/* Removing the first timer from the list.*/ /* Removing the first timer from the list.*/
ch.vtlist.vt_next = vtp->vt_next; ch.vtlist.next = vtp->next;
ch.vtlist.vt_next->vt_prev = (virtual_timer_t *)&ch.vtlist; ch.vtlist.next->prev = (virtual_timer_t *)&ch.vtlist;
vtp->vt_func = NULL; vtp->func = NULL;
/* If the list become empty then the alarm timer is stopped and done.*/ /* If the list become empty then the alarm timer is stopped and done.*/
if (&ch.vtlist == (virtual_timers_list_t *)ch.vtlist.vt_next) { if (&ch.vtlist == (virtual_timers_list_t *)ch.vtlist.next) {
port_timer_stop_alarm(); port_timer_stop_alarm();
return; return;
} }
/* The delta of the removed timer is added to the new first timer.*/ /* The delta of the removed timer is added to the new first timer.*/
ch.vtlist.vt_next->vt_delta += vtp->vt_delta; ch.vtlist.next->delta += vtp->delta;
/* If the new first timer has a delta of zero then the alarm is not /* If the new first timer has a delta of zero then the alarm is not
modified, the already programmed alarm will serve it.*/ modified, the already programmed alarm will serve it.*/
/* if (ch.vtlist.vt_next->vt_delta == 0) { /* if (ch.vtlist.next->delta == 0) {
return; return;
}*/ }*/
/* Distance in ticks between the last alarm event and current time.*/ /* Distance in ticks between the last alarm event and current time.*/
nowdelta = chVTGetSystemTimeX() - ch.vtlist.vt_lasttime; nowdelta = chVTGetSystemTimeX() - ch.vtlist.lasttime;
/* If the current time surpassed the time of the next element in list /* If the current time surpassed the time of the next element in list
then the event interrupt is already pending, just return.*/ then the event interrupt is already pending, just return.*/
if (nowdelta >= ch.vtlist.vt_next->vt_delta) { if (nowdelta >= ch.vtlist.next->delta) {
return; return;
} }
/* Distance from the next scheduled event and now.*/ /* Distance from the next scheduled event and now.*/
delta = ch.vtlist.vt_next->vt_delta - nowdelta; delta = ch.vtlist.next->delta - nowdelta;
/* Making sure to not schedule an event closer than CH_CFG_ST_TIMEDELTA /* Making sure to not schedule an event closer than CH_CFG_ST_TIMEDELTA
ticks from now.*/ ticks from now.*/
@ -250,7 +250,7 @@ void chVTDoResetI(virtual_timer_t *vtp) {
delta = (systime_t)CH_CFG_ST_TIMEDELTA; delta = (systime_t)CH_CFG_ST_TIMEDELTA;
} }
port_timer_set_alarm(ch.vtlist.vt_lasttime + nowdelta + delta); port_timer_set_alarm(ch.vtlist.lasttime + nowdelta + delta);
#endif /* CH_CFG_ST_TIMEDELTA > 0 */ #endif /* CH_CFG_ST_TIMEDELTA > 0 */
} }

View File

@ -28,6 +28,8 @@
#ifndef _CHCONF_H_ #ifndef _CHCONF_H_
#define _CHCONF_H_ #define _CHCONF_H_
#define _CHIBIOS_RT_CONF_
/*===========================================================================*/ /*===========================================================================*/
/** /**
* @name System timers settings * @name System timers settings
@ -46,7 +48,7 @@
* @details Frequency of the system timer that drives the system ticks. This * @details Frequency of the system timer that drives the system ticks. This
* setting also defines the system tick time unit. * setting also defines the system tick time unit.
*/ */
#define CH_CFG_ST_FREQUENCY 10000 #define CH_CFG_ST_FREQUENCY 1000
/** /**
* @brief Time delta constant for the tick-less mode. * @brief Time delta constant for the tick-less mode.
@ -56,7 +58,7 @@
* The value one is not valid, timeouts are rounded up to * The value one is not valid, timeouts are rounded up to
* this value. * this value.
*/ */
#define CH_CFG_ST_TIMEDELTA 2 #define CH_CFG_ST_TIMEDELTA 0
/** @} */ /** @} */
@ -138,7 +140,7 @@
* *
* @note The default is @p TRUE. * @note The default is @p TRUE.
*/ */
#define CH_CFG_USE_TM TRUE #define CH_CFG_USE_TM FALSE
/** /**
* @brief Threads registry APIs. * @brief Threads registry APIs.
@ -190,6 +192,7 @@
* memory footprint. * memory footprint.
* *
* @note The default is @p FALSE. * @note The default is @p FALSE.
* @note Requires @p CH_CFG_USE_MUTEXES.
*/ */
#define CH_CFG_USE_MUTEXES_RECURSIVE FALSE #define CH_CFG_USE_MUTEXES_RECURSIVE FALSE
@ -333,7 +336,7 @@
* *
* @note The default is @p FALSE. * @note The default is @p FALSE.
*/ */
#define CH_DBG_SYSTEM_STATE_CHECK FALSE #define CH_DBG_SYSTEM_STATE_CHECK TRUE
/** /**
* @brief Debug option, parameters checks. * @brief Debug option, parameters checks.
@ -342,7 +345,7 @@
* *
* @note The default is @p FALSE. * @note The default is @p FALSE.
*/ */
#define CH_DBG_ENABLE_CHECKS FALSE #define CH_DBG_ENABLE_CHECKS TRUE
/** /**
* @brief Debug option, consistency checks. * @brief Debug option, consistency checks.
@ -352,16 +355,23 @@
* *
* @note The default is @p FALSE. * @note The default is @p FALSE.
*/ */
#define CH_DBG_ENABLE_ASSERTS FALSE #define CH_DBG_ENABLE_ASSERTS TRUE
/** /**
* @brief Debug option, trace buffer. * @brief Debug option, trace buffer.
* @details If enabled then the context switch circular trace buffer is * @details If enabled then the context switch circular trace buffer is
* activated. * activated.
* *
* @note The default is @p FALSE. * @note The default is @p CH_DBG_TRACE_MASK_NONE.
*/ */
#define CH_DBG_ENABLE_TRACE FALSE #define CH_DBG_TRACE_MASK CH_DBG_TRACE_MASK_ALL
/**
* @brief Trace buffer entries.
* @note The trace buffer is only allocated if @p CH_DBG_TRACE_MASK is
* different from @p CH_DBG_TRACE_MASK_NONE.
*/
#define CH_DBG_TRACE_BUFFER_SIZE 128
/** /**
* @brief Debug option, stack checks. * @brief Debug option, stack checks.
@ -373,7 +383,7 @@
* @note The default failure mode is to halt the system with the global * @note The default failure mode is to halt the system with the global
* @p panic_msg variable set to @p NULL. * @p panic_msg variable set to @p NULL.
*/ */
#define CH_DBG_ENABLE_STACK_CHECK FALSE #define CH_DBG_ENABLE_STACK_CHECK TRUE
/** /**
* @brief Debug option, stacks initialization. * @brief Debug option, stacks initialization.
@ -383,7 +393,7 @@
* *
* @note The default is @p FALSE. * @note The default is @p FALSE.
*/ */
#define CH_DBG_FILL_THREADS FALSE #define CH_DBG_FILL_THREADS TRUE
/** /**
* @brief Debug option, threads profiling. * @brief Debug option, threads profiling.
@ -426,10 +436,6 @@
/** /**
* @brief Threads finalization hook. * @brief Threads finalization hook.
* @details User finalization code added to the @p chThdExit() API. * @details User finalization code added to the @p chThdExit() API.
*
* @note It is inserted into lock zone.
* @note It is also invoked when the threads simply return in order to
* terminate.
*/ */
#define CH_CFG_THREAD_EXIT_HOOK(tp) { \ #define CH_CFG_THREAD_EXIT_HOOK(tp) { \
/* Add threads finalization code here.*/ \ /* Add threads finalization code here.*/ \
@ -443,6 +449,20 @@
/* Context switch code here.*/ \ /* Context switch code here.*/ \
} }
/**
* @brief ISR enter hook.
*/
#define CH_CFG_IRQ_PROLOGUE_HOOK() { \
/* IRQ prologue code here.*/ \
}
/**
* @brief ISR exit hook.
*/
#define CH_CFG_IRQ_EPILOGUE_HOOK() { \
/* IRQ epilogue code here.*/ \
}
/** /**
* @brief Idle thread enter hook. * @brief Idle thread enter hook.
* @note This hook is invoked within a critical zone, no OS functions * @note This hook is invoked within a critical zone, no OS functions
@ -450,6 +470,7 @@
* @note This macro can be used to activate a power saving mode. * @note This macro can be used to activate a power saving mode.
*/ */
#define CH_CFG_IDLE_ENTER_HOOK() { \ #define CH_CFG_IDLE_ENTER_HOOK() { \
/* Idle-enter code here.*/ \
} }
/** /**
@ -459,6 +480,7 @@
* @note This macro can be used to deactivate a power saving mode. * @note This macro can be used to deactivate a power saving mode.
*/ */
#define CH_CFG_IDLE_LEAVE_HOOK() { \ #define CH_CFG_IDLE_LEAVE_HOOK() { \
/* Idle-leave code here.*/ \
} }
/** /**
@ -487,6 +509,15 @@
/* System halt code here.*/ \ /* System halt code here.*/ \
} }
/**
* @brief Trace hook.
* @details This hook is invoked each time a new record is written in the
* trace buffer.
*/
#define CH_CFG_TRACE_HOOK(tep) { \
/* Trace code here.*/ \
}
/** @} */ /** @} */
/*===========================================================================*/ /*===========================================================================*/

View File

@ -1,79 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file templates/chcore.c
* @brief Port related template code.
* @details This file is a template of the system driver functions provided by
* a port. Some of the following functions may be implemented as
* macros in chcore.h if the implementer decides that there is an
* advantage in doing so, for example because performance concerns.
*
* @addtogroup core
* @details Non portable code templates.
* @{
*/
#include "ch.h"
/*===========================================================================*/
/* Module local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported functions. */
/*===========================================================================*/
/**
* @brief Port-related initialization code.
* @note This function is usually empty.
*/
void _port_init(void) {
}
/**
* @brief Performs a context switch between two threads.
* @details This is the most critical code in any port, this function
* is responsible for the context switch between 2 threads.
* @note The implementation of this code affects <b>directly</b> the context
* switch performance so optimize here as much as you can.
*
* @param[in] ntp the thread to be switched in
* @param[in] otp the thread to be switched out
*/
void _port_switch(thread_t *ntp, thread_t *otp) {
}
/** @} */

View File

@ -1,412 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file templates/chcore.h
* @brief Port related template macros and structures.
* @details This file is a template of the system driver macros provided by
* a port.
*
* @addtogroup core
* @{
*/
#ifndef _CHCORE_H_
#define _CHCORE_H_
/*===========================================================================*/
/* Module constants. */
/*===========================================================================*/
/**
* @name Architecture and Compiler
* @{
*/
/**
* @brief Macro defining an XXX architecture.
*/
#define PORT_ARCHITECTURE_XXX
/**
* @brief Macro defining the specific XXX architecture.
*/
#define PORT_ARCHITECTURE_XXX_YYY
/**
* @brief Name of the implemented architecture.
*/
#define PORT_ARCHITECTURE_NAME "XXX Architecture"
/**
* @brief Compiler name and version.
*/
#if defined(__GNUC__) || defined(__DOXYGEN__)
#define PORT_COMPILER_NAME "GCC " __VERSION__
#else
#error "unsupported compiler"
#endif
/**
* @brief This port supports a realtime counter.
*/
#define PORT_SUPPORTS_RT FALSE
/**
* @brief Port-specific information string.
*/
#define PORT_INFO "no info"
/** @} */
/*===========================================================================*/
/* Module pre-compile time settings. */
/*===========================================================================*/
/**
* @brief Stack size for the system idle thread.
* @details This size depends on the idle thread implementation, usually
* the idle thread should take no more space than those reserved
* by @p PORT_INT_REQUIRED_STACK.
*/
#if !defined(PORT_IDLE_THREAD_STACK_SIZE) || defined(__DOXYGEN__)
#define PORT_IDLE_THREAD_STACK_SIZE 32
#endif
/**
* @brief Per-thread stack overhead for interrupts servicing.
* @details This constant is used in the calculation of the correct working
* area size.
*/
#if !defined(PORT_INT_REQUIRED_STACK) || defined(__DOXYGEN__)
#define PORT_INT_REQUIRED_STACK 256
#endif
/**
* @brief Enables an alternative timer implementation.
* @details Usually the port uses a timer interface defined in the file
* @p chcore_timer.h, if this option is enabled then the file
* @p chcore_timer_alt.h is included instead.
*/
#if !defined(PORT_USE_ALT_TIMER)
#define PORT_USE_ALT_TIMER FALSE
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Module data structures and types. */
/*===========================================================================*/
/* The following code is not processed when the file is included from an
asm module.*/
#if !defined(_FROM_ASM_)
/**
* @brief Type of stack and memory alignment enforcement.
* @note In this architecture the stack alignment is enforced to 64 bits.
*/
typedef uint64_t stkalign_t;
/**
* @brief Interrupt saved context.
* @details This structure represents the stack frame saved during a
* preemption-capable interrupt handler.
* @note R2 and R13 are not saved because those are assumed to be immutable
* during the system life cycle.
*/
struct port_extctx {
};
/**
* @brief System saved context.
* @details This structure represents the inner stack frame during a context
* switching.
* @note R2 and R13 are not saved because those are assumed to be immutable
* during the system life cycle.
* @note LR is stored in the caller context so it is not present in this
* structure.
*/
struct port_intctx {
};
/**
* @brief Platform dependent part of the @p thread_t structure.
* @details This structure usually contains just the saved stack pointer
* defined as a pointer to a @p port_intctx structure.
*/
struct context {
struct port_intctx *sp;
};
#endif /* !defined(_FROM_ASM_) */
/*===========================================================================*/
/* Module macros. */
/*===========================================================================*/
/**
* @brief Platform dependent part of the @p chThdCreateI() API.
* @details This code usually setup the context switching frame represented
* by an @p port_intctx structure.
*/
#define PORT_SETUP_CONTEXT(tp, workspace, wsize, pf, arg) { \
}
/**
* @brief Computes the thread working area global size.
* @note There is no need to perform alignments in this macro.
*/
#define PORT_WA_SIZE(n) (sizeof(struct port_intctx) + \
sizeof(struct port_extctx) + \
((size_t)(n)) + ((size_t)(PORT_INT_REQUIRED_STACK)))
/**
* @brief Priority level verification macro.
*/
#define PORT_IRQ_IS_VALID_PRIORITY(n) false
/**
* @brief Priority level verification macro.
*/
#define PORT_IRQ_IS_VALID_KERNEL_PRIORITY(n) false
/**
* @brief IRQ prologue code.
* @details This macro must be inserted at the start of all IRQ handlers
* enabled to invoke system APIs.
*/
#define PORT_IRQ_PROLOGUE()
/**
* @brief IRQ epilogue code.
* @details This macro must be inserted at the end of all IRQ handlers
* enabled to invoke system APIs.
*/
#define PORT_IRQ_EPILOGUE()
/**
* @brief IRQ handler function declaration.
* @note @p id can be a function name or a vector number depending on the
* port implementation.
*/
#define PORT_IRQ_HANDLER(id) void id(void)
/**
* @brief Fast IRQ handler function declaration.
* @note @p id can be a function name or a vector number depending on the
* port implementation.
*/
#define PORT_FAST_IRQ_HANDLER(id) void id(void)
/**
* @brief Performs a context switch between two threads.
* @details This is the most critical code in any port, this function
* is responsible for the context switch between 2 threads.
* @note The implementation of this code affects <b>directly</b> the context
* switch performance so optimize here as much as you can.
*
* @param[in] ntp the thread to be switched in
* @param[in] otp the thread to be switched out
*/
#if !CH_DBG_ENABLE_STACK_CHECK || defined(__DOXYGEN__)
#define port_switch(ntp, otp) _port_switch(ntp, otp)
#else
#define port_switch(ntp, otp) { \
register struct port_intctx *sp asm ("%r1"); \
if ((stkalign_t *)(sp - 1) < otp->p_stklimit) \
chSysHalt("stack overflow"); \
_port_switch(ntp, otp); \
}
#endif
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
/* The following code is not processed when the file is included from an
asm module.*/
#if !defined(_FROM_ASM_)
#ifdef __cplusplus
extern "C" {
#endif
void _port_init(void);
void _port_switch(thread_t *ntp, thread_t *otp);
#ifdef __cplusplus
}
#endif
#endif /* !defined(_FROM_ASM_) */
/*===========================================================================*/
/* Module inline functions. */
/*===========================================================================*/
/* The following code is not processed when the file is included from an
asm module.*/
#if !defined(_FROM_ASM_)
/**
* @brief Returns a word encoding the current interrupts status.
*
* @return The interrupts status.
*/
static inline syssts_t port_get_irq_status(void) {
return 0;
}
/**
* @brief Checks the interrupt status.
*
* @param[in] sts the interrupt status word
*
* @return The interrupt status.
* @retval false the word specified a disabled interrupts status.
* @retval true the word specified an enabled interrupts status.
*/
static inline bool port_irq_enabled(syssts_t sts) {
(void)sts;
return false;
}
/**
* @brief Determines the current execution context.
*
* @return The execution context.
* @retval false not running in ISR mode.
* @retval true running in ISR mode.
*/
static inline bool port_is_isr_context(void) {
return false;
}
/**
* @brief Kernel-lock action.
* @details Usually this function just disables interrupts but may perform more
* actions.
*/
static inline void port_lock(void) {
}
/**
* @brief Kernel-unlock action.
* @details Usually this function just enables interrupts but may perform more
* actions.
*/
static inline void port_unlock(void) {
}
/**
* @brief Kernel-lock action from an interrupt handler.
* @details This function is invoked before invoking I-class APIs from
* interrupt handlers. The implementation is architecture dependent,
* in its simplest form it is void.
*/
static inline void port_lock_from_isr(void) {
}
/**
* @brief Kernel-unlock action from an interrupt handler.
* @details This function is invoked after invoking I-class APIs from interrupt
* handlers. The implementation is architecture dependent, in its
* simplest form it is void.
*/
static inline void port_unlock_from_isr(void) {
}
/**
* @brief Disables all the interrupt sources.
* @note Of course non-maskable interrupt sources are not included.
*/
static inline void port_disable(void) {
}
/**
* @brief Disables the interrupt sources below kernel-level priority.
* @note Interrupt sources above kernel level remains enabled.
*/
static inline void port_suspend(void) {
}
/**
* @brief Enables all the interrupt sources.
*/
static inline void port_enable(void) {
}
/**
* @brief Enters an architecture-dependent IRQ-waiting mode.
* @details The function is meant to return when an interrupt becomes pending.
* The simplest implementation is an empty function or macro but this
* would not take advantage of architecture-specific power saving
* modes.
*/
static inline void port_wait_for_interrupt(void) {
#if PPC_ENABLE_WFI_IDLE
#endif
}
/**
* @brief Returns the current value of the realtime counter.
*
* @return The realtime counter value.
*/
static inline rtcnt_t port_rt_get_counter_value(void) {
return 0;
}
#endif /* !defined(_FROM_ASM_) */
/*===========================================================================*/
/* Module late inclusions. */
/*===========================================================================*/
/* The following code is not processed when the file is included from an
asm module.*/
#if !defined(_FROM_ASM_)
#if CH_CFG_ST_TIMEDELTA > 0
#if !PORT_USE_ALT_TIMER
#include "chcore_timer.h"
#else /* PORT_USE_ALT_TIMER */
#include "chcore_timer_alt.h"
#endif /* PORT_USE_ALT_TIMER */
#endif /* CH_CFG_ST_TIMEDELTA > 0 */
#endif /* !defined(_FROM_ASM_) */
#endif /* _CHCORE_H_ */
/** @} */

View File

@ -1,102 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2015 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file templates/chtypes.h
* @brief System types template.
* @details The types defined in this file may change depending on the target
* architecture. You may also try to optimize the size of the various
* types in order to privilege size or performance, be careful in
* doing so.
*
* @addtogroup types
* @{
*/
#ifndef _CHTYPES_H_
#define _CHTYPES_H_
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
/**
* @name Common constants
*/
/**
* @brief Generic 'false' boolean constant.
*/
#if !defined(FALSE) || defined(__DOXYGEN__)
#define FALSE 0
#endif
/**
* @brief Generic 'true' boolean constant.
*/
#if !defined(TRUE) || defined(__DOXYGEN__)
#define TRUE (!FALSE)
#endif
/** @} */
/**
* @name Kernel types
* @{
*/
typedef uint32_t rtcnt_t; /**< Realtime counter. */
typedef uint64_t rttime_t; /**< Realtime accumulator. */
typedef uint32_t syssts_t; /**< System status word. */
typedef uint8_t tmode_t; /**< Thread flags. */
typedef uint8_t tstate_t; /**< Thread state. */
typedef uint8_t trefs_t; /**< Thread references counter. */
typedef uint8_t tslices_t; /**< Thread time slices counter.*/
typedef uint32_t tprio_t; /**< Thread priority. */
typedef int32_t msg_t; /**< Inter-thread message. */
typedef int32_t eventid_t; /**< Numeric event identifier. */
typedef uint32_t eventmask_t; /**< Mask of event identifiers. */
typedef uint32_t eventflags_t; /**< Mask of event flags. */
typedef int32_t cnt_t; /**< Generic signed counter. */
typedef uint32_t ucnt_t; /**< Generic unsigned counter. */
/** @} */
/**
* @brief ROM constant modifier.
* @note It is set to use the "const" keyword in this port.
*/
#define ROMCONST const
/**
* @brief Makes functions not inlineable.
* @note If the compiler does not support such attribute then the
* realtime counter precision could be degraded.
*/
#define NOINLINE __attribute__((noinline))
/**
* @brief Optimized thread function declaration macro.
*/
#define PORT_THD_FUNCTION(tname, arg) msg_t tname(void *arg)
/**
* @brief Packed variable specifier.
*/
#define PACKED_VAR __attribute__((packed))
#endif /* _CHTYPES_H_ */
/** @} */

View File

@ -51,7 +51,7 @@ thread_reference_t gtr1;
*/ */
THD_WORKING_AREA(wa_test_support, 128); THD_WORKING_AREA(wa_test_support, 128);
THD_FUNCTION(test_support, arg) { THD_FUNCTION(test_support, arg) {
#if NIL_CFG_USE_EVENTS == TRUE #if CH_CFG_USE_EVENTS == TRUE
thread_t *tp = (thread_t *)arg; thread_t *tp = (thread_t *)arg;
#else #else
(void)arg; (void)arg;
@ -68,7 +68,7 @@ THD_FUNCTION(test_support, arg) {
chSemSignalI(&gsem1); chSemSignalI(&gsem1);
chSemResetI(&gsem2, 0); chSemResetI(&gsem2, 0);
chThdResumeI(&gtr1, MSG_OK); chThdResumeI(&gtr1, MSG_OK);
#if NIL_CFG_USE_EVENTS == TRUE #if CH_CFG_USE_EVENTS == TRUE
chEvtSignalI(tp, 0x55); chEvtSignalI(tp, 0x55);
#endif #endif
chSchRescheduleS(); chSchRescheduleS();

View File

@ -25,7 +25,7 @@
#ifndef _TEST_ROOT_H_ #ifndef _TEST_ROOT_H_
#define _TEST_ROOT_H_ #define _TEST_ROOT_H_
#include "nil.h" #include "ch.h"
#include "test_sequence_001.h" #include "test_sequence_001.h"
#include "test_sequence_002.h" #include "test_sequence_002.h"

View File

@ -327,7 +327,7 @@ static const testcase_t test_002_004 = {
}; };
#endif /* TRUE */ #endif /* TRUE */
#if (NIL_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__) #if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__)
/** /**
* @page test_002_005 Events functionality * @page test_002_005 Events functionality
* *
@ -408,7 +408,7 @@ static const testcase_t test_002_005 = {
NULL, NULL,
test_002_005_execute test_002_005_execute
}; };
#endif /* NIL_CFG_USE_EVENTS == TRUE */ #endif /* CH_CFG_USE_EVENTS == TRUE */
/**************************************************************************** /****************************************************************************
* Exported data. * Exported data.
@ -430,7 +430,7 @@ const testcase_t * const test_sequence_002[] = {
#if TRUE || defined(__DOXYGEN__) #if TRUE || defined(__DOXYGEN__)
&test_002_004, &test_002_004,
#endif #endif
#if (NIL_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__) #if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__)
&test_002_005, &test_002_005,
#endif #endif
NULL NULL

View File

@ -35,7 +35,6 @@
#include "testevt.h" #include "testevt.h"
#include "testheap.h" #include "testheap.h"
#include "testpools.h" #include "testpools.h"
#include "testdyn.h"
#include "testqueues.h" #include "testqueues.h"
#include "testbmk.h" #include "testbmk.h"
@ -52,7 +51,6 @@ static ROMCONST struct testcase * ROMCONST *patterns[] = {
patternevt, patternevt,
patternheap, patternheap,
patternpools, patternpools,
patterndyn,
patternqueues, patternqueues,
patternbmk, patternbmk,
NULL NULL
@ -193,17 +191,6 @@ bool _test_assert_time_window(unsigned point, systime_t start, systime_t end) {
* Threads utils. * Threads utils.
*/ */
/**
* @brief Sets a termination request in all the test-spawned threads.
*/
void test_terminate_threads(void) {
int i;
for (i = 0; i < MAX_THREADS; i++)
if (threads[i])
chThdTerminate(threads[i]);
}
/** /**
* @brief Waits for the completion of all the test-spawned threads. * @brief Waits for the completion of all the test-spawned threads.
*/ */

View File

@ -90,7 +90,6 @@ extern "C" {
bool _test_assert(unsigned point, bool condition); bool _test_assert(unsigned point, bool condition);
bool _test_assert_sequence(unsigned point, char *expected); bool _test_assert_sequence(unsigned point, char *expected);
bool _test_assert_time_window(unsigned point, systime_t start, systime_t end); bool _test_assert_time_window(unsigned point, systime_t start, systime_t end);
void test_terminate_threads(void);
void test_wait_threads(void); void test_wait_threads(void);
systime_t test_wait_tick(void); systime_t test_wait_tick(void);
void test_start_timer(unsigned ms); void test_start_timer(unsigned ms);

View File

@ -8,7 +8,6 @@ TESTSRC = ${CHIBIOS}/test/rt/test.c \
${CHIBIOS}/test/rt/testevt.c \ ${CHIBIOS}/test/rt/testevt.c \
${CHIBIOS}/test/rt/testheap.c \ ${CHIBIOS}/test/rt/testheap.c \
${CHIBIOS}/test/rt/testpools.c \ ${CHIBIOS}/test/rt/testpools.c \
${CHIBIOS}/test/rt/testdyn.c \
${CHIBIOS}/test/rt/testqueues.c \ ${CHIBIOS}/test/rt/testqueues.c \
${CHIBIOS}/test/rt/testsys.c \ ${CHIBIOS}/test/rt/testsys.c \
${CHIBIOS}/test/rt/testbmk.c ${CHIBIOS}/test/rt/testbmk.c

View File

@ -211,7 +211,7 @@ static THD_FUNCTION(thread4, p) {
chSysLock(); chSysLock();
do { do {
chSchGoSleepS(CH_STATE_SUSPENDED); chSchGoSleepS(CH_STATE_SUSPENDED);
msg = self->p_u.rdymsg; msg = self->u.rdymsg;
} while (msg == MSG_OK); } while (msg == MSG_OK);
chSysUnlock(); chSysUnlock();
} }
@ -344,8 +344,7 @@ ROMCONST struct testcase testbmk6 = {
static THD_FUNCTION(thread3, p) { static THD_FUNCTION(thread3, p) {
(void)p; while (!*(bool *)p)
while (!chThdShouldTerminateX())
chSemWait(&sem1); chSemWait(&sem1);
} }
@ -356,12 +355,13 @@ static void bmk7_setup(void) {
static void bmk7_execute(void) { static void bmk7_execute(void) {
uint32_t n; uint32_t n;
bool terminate = false;
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+5, thread3, NULL); threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+5, thread3, &terminate);
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()+4, thread3, NULL); threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()+4, thread3, &terminate);
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()+3, thread3, NULL); threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()+3, thread3, &terminate);
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()+2, thread3, NULL); threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()+2, thread3, &terminate);
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()+1, thread3, NULL); threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()+1, thread3, &terminate);
n = 0; n = 0;
test_wait_tick(); test_wait_tick();
@ -373,7 +373,7 @@ static void bmk7_execute(void) {
_sim_check_for_interrupts(); _sim_check_for_interrupts();
#endif #endif
} while (!test_timer_done); } while (!test_timer_done);
test_terminate_threads(); terminate = true;
chSemReset(&sem1, 0); chSemReset(&sem1, 0);
test_wait_threads(); test_wait_threads();
@ -401,39 +401,44 @@ ROMCONST struct testcase testbmk7 = {
* The performance is calculated by measuring the number of iterations after * The performance is calculated by measuring the number of iterations after
* a second of continuous operations. * a second of continuous operations.
*/ */
typedef struct {
bool terminate;
uint32_t n;
} params_t;
static THD_FUNCTION(thread8, p) { static THD_FUNCTION(thread8, p) {
params_t *pp = (params_t *)p;
do { do {
chThdYield(); chThdYield();
chThdYield(); chThdYield();
chThdYield(); chThdYield();
chThdYield(); chThdYield();
(*(uint32_t *)p) += 4; pp->n += 4;
#if defined(SIMULATOR) #if defined(SIMULATOR)
_sim_check_for_interrupts(); _sim_check_for_interrupts();
#endif #endif
} while(!chThdShouldTerminateX()); } while (!pp->terminate);
} }
static void bmk8_execute(void) { static void bmk8_execute(void) {
uint32_t n; params_t params = {false, 0};
n = 0; params.n = 0;
test_wait_tick(); test_wait_tick();
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, thread8, (void *)&n); threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, thread8, (void *)&params);
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-1, thread8, (void *)&n); threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-1, thread8, (void *)&params);
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-1, thread8, (void *)&n); threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-1, thread8, (void *)&params);
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-1, thread8, (void *)&n); threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-1, thread8, (void *)&params);
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread8, (void *)&n); threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread8, (void *)&params);
chThdSleepSeconds(1); chThdSleepSeconds(1);
test_terminate_threads(); params.terminate = true;
test_wait_threads(); test_wait_threads();
test_print("--- Score : "); test_print("--- Score : ");
test_printn(n); test_printn(params.n);
test_println(" ctxswc/S"); test_println(" ctxswc/S");
} }

View File

@ -81,10 +81,9 @@ static void dyn1_setup(void) {
static void dyn1_execute(void) { static void dyn1_execute(void) {
size_t n, sz; size_t n, sz;
void *p1;
tprio_t prio = chThdGetPriorityX(); tprio_t prio = chThdGetPriorityX();
(void)chHeapStatus(&heap1, &sz); (void)chHeapStatus(&heap1, &sz, NULL);
/* Starting threads from the heap. */ /* Starting threads from the heap. */
threads[0] = chThdCreateFromHeap(&heap1, threads[0] = chThdCreateFromHeap(&heap1,
THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE), THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE),
@ -92,13 +91,10 @@ static void dyn1_execute(void) {
threads[1] = chThdCreateFromHeap(&heap1, threads[1] = chThdCreateFromHeap(&heap1,
THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE), THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE),
prio-2, thread, "B"); prio-2, thread, "B");
/* Allocating the whole heap in order to make the thread creation fail.*/ /* Large working area in order to make the thread creation fail.*/
(void)chHeapStatus(&heap1, &n);
p1 = chHeapAlloc(&heap1, n);
threads[2] = chThdCreateFromHeap(&heap1, threads[2] = chThdCreateFromHeap(&heap1,
THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE), THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE * 16),
prio-3, thread, "C"); prio-3, thread, "C");
chHeapFree(p1);
test_assert(1, (threads[0] != NULL) && test_assert(1, (threads[0] != NULL) &&
(threads[1] != NULL) && (threads[1] != NULL) &&
@ -112,7 +108,7 @@ static void dyn1_execute(void) {
test_assert_sequence(2, "AB"); test_assert_sequence(2, "AB");
/* Heap status checked again.*/ /* Heap status checked again.*/
test_assert(3, chHeapStatus(&heap1, &n) == 1, "heap fragmented"); test_assert(3, chHeapStatus(&heap1, &n, NULL) == 1, "heap fragmented");
test_assert(4, n == sz, "heap size changed"); test_assert(4, n == sz, "heap size changed");
} }
@ -212,11 +208,11 @@ static void dyn3_execute(void) {
/* Testing references increase/decrease and final detach.*/ /* Testing references increase/decrease and final detach.*/
tp = chThdCreateFromHeap(&heap1, WA_SIZE, prio-1, thread, "A"); tp = chThdCreateFromHeap(&heap1, WA_SIZE, prio-1, thread, "A");
test_assert(1, tp->p_refs == 1, "wrong initial reference counter"); test_assert(1, tp->refs == 1, "wrong initial reference counter");
chThdAddRef(tp); chThdAddRef(tp);
test_assert(2, tp->p_refs == 2, "references increase failure"); test_assert(2, tp->refs == 2, "references increase failure");
chThdRelease(tp); chThdRelease(tp);
test_assert(3, tp->p_refs == 1, "references decrease failure"); test_assert(3, tp->refs == 1, "references decrease failure");
/* Verify the new threads count.*/ /* Verify the new threads count.*/
test_assert(4, regfind(tp), "thread missing from registry"); test_assert(4, regfind(tp), "thread missing from registry");
@ -224,12 +220,12 @@ static void dyn3_execute(void) {
/* Detach and let the thread execute and terminate.*/ /* Detach and let the thread execute and terminate.*/
chThdRelease(tp); chThdRelease(tp);
test_assert(6, tp->p_refs == 0, "detach failure"); test_assert(6, tp->refs == 0, "detach failure");
test_assert(7, tp->p_state == CH_STATE_READY, "invalid state"); test_assert(7, tp->state == CH_STATE_READY, "invalid state");
test_assert(8, regfind(tp), "thread disappeared"); test_assert(8, regfind(tp), "thread disappeared");
test_assert(9, regfind(tp), "thread disappeared"); test_assert(9, regfind(tp), "thread disappeared");
chThdSleepMilliseconds(50); /* The thread just terminates. */ chThdSleepMilliseconds(50); /* The thread just terminates. */
test_assert(10, tp->p_state == CH_STATE_FINAL, "invalid state"); test_assert(10, tp->state == CH_STATE_FINAL, "invalid state");
/* Clearing the zombie by scanning the registry.*/ /* Clearing the zombie by scanning the registry.*/
test_assert(11, regfind(tp), "thread disappeared"); test_assert(11, regfind(tp), "thread disappeared");

View File

@ -77,7 +77,7 @@ static void heap1_execute(void) {
* Test on the default heap in order to cover the core allocator at * Test on the default heap in order to cover the core allocator at
* least one time. * least one time.
*/ */
(void)chHeapStatus(NULL, &sz); (void)chHeapStatus(NULL, &sz, NULL);
p1 = chHeapAlloc(NULL, SIZE); p1 = chHeapAlloc(NULL, SIZE);
test_assert(1, p1 != NULL, "allocation failed"); test_assert(1, p1 != NULL, "allocation failed");
chHeapFree(p1); chHeapFree(p1);
@ -85,7 +85,7 @@ static void heap1_execute(void) {
test_assert(2, p1 == NULL, "allocation not failed"); test_assert(2, p1 == NULL, "allocation not failed");
/* Initial local heap state.*/ /* Initial local heap state.*/
(void)chHeapStatus(&test_heap, &sz); (void)chHeapStatus(&test_heap, &sz, NULL);
/* Same order.*/ /* Same order.*/
p1 = chHeapAlloc(&test_heap, SIZE); p1 = chHeapAlloc(&test_heap, SIZE);
@ -94,7 +94,7 @@ static void heap1_execute(void) {
chHeapFree(p1); /* Does not merge.*/ chHeapFree(p1); /* Does not merge.*/
chHeapFree(p2); /* Merges backward.*/ chHeapFree(p2); /* Merges backward.*/
chHeapFree(p3); /* Merges both sides.*/ chHeapFree(p3); /* Merges both sides.*/
test_assert(3, chHeapStatus(&test_heap, &n) == 1, "heap fragmented"); test_assert(3, chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
/* Reverse order.*/ /* Reverse order.*/
p1 = chHeapAlloc(&test_heap, SIZE); p1 = chHeapAlloc(&test_heap, SIZE);
@ -103,39 +103,39 @@ static void heap1_execute(void) {
chHeapFree(p3); /* Merges forward.*/ chHeapFree(p3); /* Merges forward.*/
chHeapFree(p2); /* Merges forward.*/ chHeapFree(p2); /* Merges forward.*/
chHeapFree(p1); /* Merges forward.*/ chHeapFree(p1); /* Merges forward.*/
test_assert(4, chHeapStatus(&test_heap, &n) == 1, "heap fragmented"); test_assert(4, chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
/* Small fragments handling.*/ /* Small fragments handling.*/
p1 = chHeapAlloc(&test_heap, SIZE + 1); p1 = chHeapAlloc(&test_heap, SIZE + 1);
p2 = chHeapAlloc(&test_heap, SIZE); p2 = chHeapAlloc(&test_heap, SIZE);
chHeapFree(p1); chHeapFree(p1);
test_assert(5, chHeapStatus(&test_heap, &n) == 2, "invalid state"); test_assert(5, chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
p1 = chHeapAlloc(&test_heap, SIZE); p1 = chHeapAlloc(&test_heap, SIZE);
/* Note, the first situation happens when the alignment size is smaller /* Note, the first situation happens when the alignment size is smaller
than the header size, the second in the other cases.*/ than the header size, the second in the other cases.*/
test_assert(6, (chHeapStatus(&test_heap, &n) == 1) || test_assert(6, (chHeapStatus(&test_heap, &n, NULL) == 1) ||
(chHeapStatus(&test_heap, &n) == 2), "heap fragmented"); (chHeapStatus(&test_heap, &n, NULL) == 2), "heap fragmented");
chHeapFree(p2); chHeapFree(p2);
chHeapFree(p1); chHeapFree(p1);
test_assert(7, chHeapStatus(&test_heap, &n) == 1, "heap fragmented"); test_assert(7, chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
/* Skip fragment handling.*/ /* Skip fragment handling.*/
p1 = chHeapAlloc(&test_heap, SIZE); p1 = chHeapAlloc(&test_heap, SIZE);
p2 = chHeapAlloc(&test_heap, SIZE); p2 = chHeapAlloc(&test_heap, SIZE);
chHeapFree(p1); chHeapFree(p1);
test_assert(8, chHeapStatus(&test_heap, &n) == 2, "invalid state"); test_assert(8, chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
p1 = chHeapAlloc(&test_heap, SIZE * 2); /* Skips first fragment.*/ p1 = chHeapAlloc(&test_heap, SIZE * 2); /* Skips first fragment.*/
chHeapFree(p1); chHeapFree(p1);
chHeapFree(p2); chHeapFree(p2);
test_assert(9, chHeapStatus(&test_heap, &n) == 1, "heap fragmented"); test_assert(9, chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
/* Allocate all handling.*/ /* Allocate all handling.*/
(void)chHeapStatus(&test_heap, &n); (void)chHeapStatus(&test_heap, &n, NULL);
p1 = chHeapAlloc(&test_heap, n); p1 = chHeapAlloc(&test_heap, n);
test_assert(10, chHeapStatus(&test_heap, &n) == 0, "not empty"); test_assert(10, chHeapStatus(&test_heap, &n, NULL) == 0, "not empty");
chHeapFree(p1); chHeapFree(p1);
test_assert(11, chHeapStatus(&test_heap, &n) == 1, "heap fragmented"); test_assert(11, chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
test_assert(12, n == sz, "size changed"); test_assert(12, n == sz, "size changed");
} }

Some files were not shown because too many files have changed in this diff Show More