diff options
Diffstat (limited to 'os/kernel')
47 files changed, 10169 insertions, 0 deletions
diff --git a/os/kernel/include/ch.h b/os/kernel/include/ch.h new file mode 100644 index 000000000..db7c45501 --- /dev/null +++ b/os/kernel/include/ch.h @@ -0,0 +1,143 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 ch.h
+ * @brief ChibiOS/RT main include file.
+ * @details This header includes all the required kernel headers so it is the
+ * only kernel header you usually want to include in your application.
+ *
+ * @addtogroup kernel_info
+ * @details Kernel related info.
+ * @{
+ */
+
+#ifndef _CH_H_
+#define _CH_H_
+
+/**
+ * @brief ChibiOS/RT identification macro.
+ */
+#define _CHIBIOS_RT_
+
+/**
+ * @brief Kernel version string.
+ */
+#define CH_KERNEL_VERSION "2.7.0unstable"
+
+/**
+ * @name Kernel version
+ * @{
+ */
+/**
+ * @brief Kernel version major number.
+ */
+#define CH_KERNEL_MAJOR 2
+
+/**
+ * @brief Kernel version minor number.
+ */
+#define CH_KERNEL_MINOR 7
+
+/**
+ * @brief Kernel version patch number.
+ */
+#define CH_KERNEL_PATCH 0
+/** @} */
+
+/**
+ * @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
+
+/**
+ * @brief Generic success constant.
+ * @details This constant is functionally equivalent to @p FALSE but more
+ * readable, it can be used as return value of all those functions
+ * returning a @p bool_t as a status indicator.
+ */
+#if !defined(CH_SUCCESS) || defined(__DOXYGEN__)
+#define CH_SUCCESS FALSE
+#endif
+
+/**
+ * @brief Generic failure constant.
+ * @details This constant is functionally equivalent to @p TRUE but more
+ * readable, it can be used as return value of all those functions
+ * returning a @p bool_t as a status indicator.
+ */
+#if !defined(CH_FAILED) || defined(__DOXYGEN__)
+#define CH_FAILED TRUE
+#endif
+/** @} */
+
+#include "chconf.h"
+#include "chtypes.h"
+#include "chlists.h"
+#include "chcore.h"
+#include "chsys.h"
+#include "chvt.h"
+#include "chschd.h"
+#include "chsem.h"
+#include "chbsem.h"
+#include "chmtx.h"
+#include "chcond.h"
+#include "chevents.h"
+#include "chmsg.h"
+#include "chmboxes.h"
+#include "chmemcore.h"
+#include "chheap.h"
+#include "chmempools.h"
+#include "chthreads.h"
+#include "chdynamic.h"
+#include "chregistry.h"
+#include "chinline.h"
+#include "chqueues.h"
+#include "chstreams.h"
+#include "chfiles.h"
+#include "chdebug.h"
+
+#if !defined(__DOXYGEN__)
+extern WORKING_AREA(_idle_thread_wa, PORT_IDLE_THREAD_STACK_SIZE);
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void _idle_thread(void *p);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CH_H_ */
+
+/** @} */
diff --git a/os/kernel/include/chbsem.h b/os/kernel/include/chbsem.h new file mode 100644 index 000000000..856a3c3b3 --- /dev/null +++ b/os/kernel/include/chbsem.h @@ -0,0 +1,251 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 macros 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
+ * the 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_USE_SEMAPHORES
+ * option must be enabled in @p chconf.h.
+ * @{
+ */
+
+#ifndef _CHBSEM_H_
+#define _CHBSEM_H_
+
+#if CH_USE_SEMAPHORES || defined(__DOXYGEN__)
+
+/**
+ * @extends Semaphore
+ *
+ * @brief Binary semaphore type.
+ */
+typedef struct {
+ Semaphore bs_sem;
+} BinarySemaphore;
+
+/**
+ * @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 chSemInit().
+ *
+ * @param[in] name the name of the semaphore variable
+ * @param[in] taken the semaphore initial state
+ */
+#define BSEMAPHORE_DECL(name, taken) \
+ BinarySemaphore name = _BSEMAPHORE_DATA(name, taken)
+
+/**
+ * @name Macro Functions
+ * @{
+ */
+/**
+ * @brief Initializes a binary semaphore.
+ *
+ * @param[out] bsp pointer to a @p BinarySemaphore 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
+ */
+#define chBSemInit(bsp, taken) chSemInit(&(bsp)->bs_sem, (taken) ? 0 : 1)
+
+/**
+ * @brief Wait operation on the binary semaphore.
+ *
+ * @param[in] bsp pointer to a @p BinarySemaphore structure
+ * @return A message specifying how the invoking thread has been
+ * released from the semaphore.
+ * @retval RDY_OK if the binary semaphore has been successfully taken.
+ * @retval RDY_RESET if the binary semaphore has been reset using
+ * @p bsemReset().
+ *
+ * @api
+ */
+#define chBSemWait(bsp) chSemWait(&(bsp)->bs_sem)
+
+/**
+ * @brief Wait operation on the binary semaphore.
+ *
+ * @param[in] bsp pointer to a @p BinarySemaphore structure
+ * @return A message specifying how the invoking thread has been
+ * released from the semaphore.
+ * @retval RDY_OK if the binary semaphore has been successfully taken.
+ * @retval RDY_RESET if the binary semaphore has been reset using
+ * @p bsemReset().
+ *
+ * @sclass
+ */
+#define chBSemWaitS(bsp) chSemWaitS(&(bsp)->bs_sem)
+
+/**
+ * @brief Wait operation on the binary semaphore.
+ *
+ * @param[in] bsp pointer to a @p BinarySemaphore 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 RDY_OK if the binary semaphore has been successfully taken.
+ * @retval RDY_RESET if the binary semaphore has been reset using
+ * @p bsemReset().
+ * @retval RDY_TIMEOUT if the binary semaphore has not been signaled or reset
+ * within the specified timeout.
+ *
+ * @api
+ */
+#define chBSemWaitTimeout(bsp, time) chSemWaitTimeout(&(bsp)->bs_sem, (time))
+
+/**
+ * @brief Wait operation on the binary semaphore.
+ *
+ * @param[in] bsp pointer to a @p BinarySemaphore 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 RDY_OK if the binary semaphore has been successfully taken.
+ * @retval RDY_RESET if the binary semaphore has been reset using
+ * @p bsemReset().
+ * @retval RDY_TIMEOUT if the binary semaphore has not been signaled or reset
+ * within the specified timeout.
+ *
+ * @sclass
+ */
+#define chBSemWaitTimeoutS(bsp, time) chSemWaitTimeoutS(&(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 RDY_RESET instead of @p RDY_OK.
+ *
+ * @param[in] bsp pointer to a @p BinarySemaphore 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
+ */
+#define chBSemReset(bsp, taken) chSemReset(&(bsp)->bs_sem, (taken) ? 0 : 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 RDY_RESET instead of @p RDY_OK.
+ * @note This function does not reschedule.
+ *
+ * @param[in] bsp pointer to a @p BinarySemaphore 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
+ */
+#define chBSemResetI(bsp, taken) chSemResetI(&(bsp)->bs_sem, (taken) ? 0 : 1)
+
+/**
+ * @brief Performs a signal operation on a binary semaphore.
+ *
+ * @param[in] bsp pointer to a @p BinarySemaphore structure
+ *
+ * @api
+ */
+#define chBSemSignal(bsp) { \
+ chSysLock(); \
+ chBSemSignalI((bsp)); \
+ chSchRescheduleS(); \
+ chSysUnlock(); \
+}
+
+/**
+ * @brief Performs a signal operation on a binary semaphore.
+ * @note This function does not reschedule.
+ *
+ * @param[in] bsp pointer to a @p BinarySemaphore structure
+ *
+ * @iclass
+ */
+#define chBSemSignalI(bsp) { \
+ if ((bsp)->bs_sem.s_cnt < 1) \
+ chSemSignalI(&(bsp)->bs_sem); \
+}
+
+/**
+ * @brief Returns the binary semaphore current state.
+ *
+ * @param[in] bsp pointer to a @p BinarySemaphore 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
+ */
+#define chBSemGetStateI(bsp) ((bsp)->bs_sem.s_cnt > 0 ? FALSE : TRUE)
+/** @} */
+
+#endif /* CH_USE_SEMAPHORES */
+
+#endif /* _CHBSEM_H_ */
+
+/** @} */
diff --git a/os/kernel/include/chcond.h b/os/kernel/include/chcond.h new file mode 100644 index 000000000..7557243cd --- /dev/null +++ b/os/kernel/include/chcond.h @@ -0,0 +1,91 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 Leon Woestenberg.
+ */
+
+/**
+ * @file chcond.h
+ * @brief Condition Variables macros and structures.
+ *
+ * @addtogroup condvars
+ * @{
+ */
+
+#ifndef _CHCOND_H_
+#define _CHCOND_H_
+
+#if CH_USE_CONDVARS || defined(__DOXYGEN__)
+
+/*
+ * Module dependencies check.
+ */
+#if !CH_USE_MUTEXES
+#error "CH_USE_CONDVARS requires CH_USE_MUTEXES"
+#endif
+
+/**
+ * @brief CondVar structure.
+ */
+typedef struct CondVar {
+ ThreadsQueue c_queue; /**< @brief CondVar threads queue.*/
+} CondVar;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void chCondInit(CondVar *cp);
+ void chCondSignal(CondVar *cp);
+ void chCondSignalI(CondVar *cp);
+ void chCondBroadcast(CondVar *cp);
+ void chCondBroadcastI(CondVar *cp);
+ msg_t chCondWait(CondVar *cp);
+ msg_t chCondWaitS(CondVar *cp);
+#if CH_USE_CONDVARS_TIMEOUT
+ msg_t chCondWaitTimeout(CondVar *cp, systime_t time);
+ msg_t chCondWaitTimeoutS(CondVar *cp, systime_t time);
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @brief Data part of a static condition variable initializer.
+ * @details This macro should be used when statically initializing a condition
+ * variable that is part of a bigger structure.
+ *
+ * @param[in] name the name of the condition variable
+ */
+#define _CONDVAR_DATA(name) {_THREADSQUEUE_DATA(name.c_queue)}
+
+/**
+ * @brief Static condition variable initializer.
+ * @details Statically initialized condition variables require no explicit
+ * initialization using @p chCondInit().
+ *
+ * @param[in] name the name of the condition variable
+ */
+#define CONDVAR_DECL(name) CondVar name = _CONDVAR_DATA(name)
+
+#endif /* CH_USE_CONDVARS */
+
+#endif /* _CHCOND_H_ */
+
+/** @} */
diff --git a/os/kernel/include/chdebug.h b/os/kernel/include/chdebug.h new file mode 100644 index 000000000..4a75474e2 --- /dev/null +++ b/os/kernel/include/chdebug.h @@ -0,0 +1,247 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 chdebug.h
+ * @brief Debug macros and structures.
+ *
+ * @addtogroup debug
+ * @{
+ */
+
+#ifndef _CHDEBUG_H_
+#define _CHDEBUG_H_
+
+#if CH_DBG_ENABLE_ASSERTS || CH_DBG_ENABLE_CHECKS || \
+ CH_DBG_ENABLE_STACK_CHECK || CH_DBG_SYSTEM_STATE_CHECK
+#define CH_DBG_ENABLED TRUE
+#else
+#define CH_DBG_ENABLED FALSE
+#endif
+
+#define __QUOTE_THIS(p) #p
+
+/*===========================================================================*/
+/**
+ * @name Debug related settings
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief Trace buffer entries.
+ */
+#ifndef CH_TRACE_BUFFER_SIZE
+#define CH_TRACE_BUFFER_SIZE 64
+#endif
+
+/**
+ * @brief Fill value for thread stack area in debug mode.
+ */
+#ifndef CH_STACK_FILL_VALUE
+#define CH_STACK_FILL_VALUE 0x55
+#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.
+ */
+#ifndef CH_THREAD_FILL_VALUE
+#define CH_THREAD_FILL_VALUE 0xFF
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/* System state checker related code and variables. */
+/*===========================================================================*/
+
+#if !CH_DBG_SYSTEM_STATE_CHECK
+#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();
+#else
+#define dbg_enter_lock() (dbg_lock_cnt = 1)
+#define dbg_leave_lock() (dbg_lock_cnt = 0)
+#endif
+
+/*===========================================================================*/
+/* Trace related structures and macros. */
+/*===========================================================================*/
+
+#if CH_DBG_ENABLE_TRACE || defined(__DOXYGEN__)
+/**
+ * @brief Trace buffer record.
+ */
+typedef struct {
+ systime_t se_time; /**< @brief Time of the switch event. */
+ Thread *se_tp; /**< @brief Switched in thread. */
+ void *se_wtobjp; /**< @brief Object where going to sleep.*/
+ uint8_t se_state; /**< @brief Switched out thread state. */
+} ch_swc_event_t;
+
+/**
+ * @brief Trace buffer header.
+ */
+typedef struct {
+ unsigned tb_size; /**< @brief Trace buffer size (entries).*/
+ ch_swc_event_t *tb_ptr; /**< @brief Pointer to the buffer front.*/
+ /** @brief Ring buffer.*/
+ ch_swc_event_t tb_buffer[CH_TRACE_BUFFER_SIZE];
+} ch_trace_buffer_t;
+
+#if !defined(__DOXYGEN__)
+extern ch_trace_buffer_t dbg_trace_buffer;
+#endif
+
+#endif /* CH_DBG_ENABLE_TRACE */
+
+#if !CH_DBG_ENABLE_TRACE
+/* When the trace feature is disabled this function is replaced by an empty
+ macro.*/
+#define dbg_trace(otp)
+#endif
+
+/*===========================================================================*/
+/* Parameters checking related macros. */
+/*===========================================================================*/
+
+#if CH_DBG_ENABLE_CHECKS || defined(__DOXYGEN__)
+/**
+ * @name Macro Functions
+ * @{
+ */
+/**
+ * @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
+ * @param[in] func the undecorated function name
+ *
+ * @api
+ */
+#if !defined(chDbgCheck)
+#define chDbgCheck(c, func) { \
+ if (!(c)) \
+ chDbgPanic(__QUOTE_THIS(func)"()"); \
+}
+#endif /* !defined(chDbgCheck) */
+/** @} */
+#else /* !CH_DBG_ENABLE_CHECKS */
+#define chDbgCheck(c, func) { \
+ (void)(c), (void)__QUOTE_THIS(func)"()"; \
+}
+#endif /* !CH_DBG_ENABLE_CHECKS */
+
+/*===========================================================================*/
+/* Assertions related macros. */
+/*===========================================================================*/
+
+#if CH_DBG_ENABLE_ASSERTS || defined(__DOXYGEN__)
+/**
+ * @name Macro Functions
+ * @{
+ */
+/**
+ * @brief Condition assertion.
+ * @details If the condition check fails then the kernel panics with the
+ * specified message and halts.
+ * @note The condition is tested only if the @p CH_DBG_ENABLE_ASSERTS switch
+ * is specified in @p chconf.h else the macro does nothing.
+ * @note The convention for the message is the following:<br>
+ * @<function_name@>(), #@<assert_number@>
+ * @note The remark string is not currently used except for putting a
+ * comment in the code about the assertion.
+ *
+ * @param[in] c the condition to be verified to be true
+ * @param[in] m the text message
+ * @param[in] r a remark string
+ *
+ * @api
+ */
+#if !defined(chDbgAssert)
+#define chDbgAssert(c, m, r) { \
+ if (!(c)) \
+ chDbgPanic(m); \
+}
+#endif /* !defined(chDbgAssert) */
+/** @} */
+#else /* !CH_DBG_ENABLE_ASSERTS */
+#define chDbgAssert(c, m, r) {(void)(c);}
+#endif /* !CH_DBG_ENABLE_ASSERTS */
+
+/*===========================================================================*/
+/* Panic related macros. */
+/*===========================================================================*/
+
+#if !CH_DBG_ENABLED
+/* When the debug features are disabled this function is replaced by an empty
+ macro.*/
+#define chDbgPanic(msg) {}
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#if CH_DBG_SYSTEM_STATE_CHECK
+ extern cnt_t dbg_isr_cnt;
+ extern cnt_t dbg_lock_cnt;
+ void dbg_check_disable(void);
+ void dbg_check_suspend(void);
+ void dbg_check_enable(void);
+ void dbg_check_lock(void);
+ void dbg_check_unlock(void);
+ void dbg_check_lock_from_isr(void);
+ void dbg_check_unlock_from_isr(void);
+ void dbg_check_enter_isr(void);
+ void dbg_check_leave_isr(void);
+ void chDbgCheckClassI(void);
+ void chDbgCheckClassS(void);
+#endif
+#if CH_DBG_ENABLE_TRACE || defined(__DOXYGEN__)
+ void _trace_init(void);
+ void dbg_trace(Thread *otp);
+#endif
+#if CH_DBG_ENABLED
+ extern const char *dbg_panic_msg;
+ void chDbgPanic(const char *msg);
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CHDEBUG_H_ */
+
+/** @} */
diff --git a/os/kernel/include/chdynamic.h b/os/kernel/include/chdynamic.h new file mode 100644 index 000000000..3ac79a5f4 --- /dev/null +++ b/os/kernel/include/chdynamic.h @@ -0,0 +1,68 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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_USE_DYNAMIC || defined(__DOXYGEN__)
+
+/*
+ * Module dependencies check.
+ */
+#if CH_USE_DYNAMIC && !CH_USE_WAITEXIT
+#error "CH_USE_DYNAMIC requires CH_USE_WAITEXIT"
+#endif
+#if CH_USE_DYNAMIC && !CH_USE_HEAP && !CH_USE_MEMPOOLS
+#error "CH_USE_DYNAMIC requires CH_USE_HEAP and/or CH_USE_MEMPOOLS"
+#endif
+
+/*
+ * Dynamic threads APIs.
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+ Thread *chThdAddRef(Thread *tp);
+ void chThdRelease(Thread *tp);
+#if CH_USE_HEAP
+ Thread *chThdCreateFromHeap(MemoryHeap *heapp, size_t size,
+ tprio_t prio, tfunc_t pf, void *arg);
+#endif
+#if CH_USE_MEMPOOLS
+ Thread *chThdCreateFromMemoryPool(MemoryPool *mp, tprio_t prio,
+ tfunc_t pf, void *arg);
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CH_USE_DYNAMIC */
+
+#endif /* _CHDYNAMIC_H_ */
+
+/** @} */
diff --git a/os/kernel/include/chevents.h b/os/kernel/include/chevents.h new file mode 100644 index 000000000..ec5c1cb93 --- /dev/null +++ b/os/kernel/include/chevents.h @@ -0,0 +1,205 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 Scott (skute).
+ */
+
+/**
+ * @file chevents.h
+ * @brief Events macros and structures.
+ *
+ * @addtogroup events
+ * @{
+ */
+
+#ifndef _CHEVENTS_H_
+#define _CHEVENTS_H_
+
+#if CH_USE_EVENTS || defined(__DOXYGEN__)
+
+typedef struct EventListener EventListener;
+
+/**
+ * @brief Event Listener structure.
+ */
+struct EventListener {
+ EventListener *el_next; /**< @brief Next Event Listener
+ registered on the Event
+ Source. */
+ Thread *el_listener; /**< @brief Thread interested in the
+ Event Source. */
+ eventmask_t el_mask; /**< @brief Event flags mask associated
+ by the thread to the Event
+ Source. */
+ flagsmask_t el_flags; /**< @brief Flags added to the listener
+ by the event source.*/
+};
+
+/**
+ * @brief Event Source structure.
+ */
+typedef struct EventSource {
+ EventListener *es_next; /**< @brief First Event Listener
+ registered on the Event
+ Source. */
+} EventSource;
+
+/**
+ * @brief Event Handler callback function.
+ */
+typedef void (*evhandler_t)(eventid_t);
+
+/**
+ * @brief Data part of a static event source initializer.
+ * @details This macro should be used when statically initializing an event
+ * source that is part of a bigger structure.
+ * @param name the name of the event source variable
+ */
+#define _EVENTSOURCE_DATA(name) {(void *)(&name)}
+
+/**
+ * @brief Static event source initializer.
+ * @details Statically initialized event sources require no explicit
+ * initialization using @p chEvtInit().
+ *
+ * @param name the name of the event source variable
+ */
+#define EVENTSOURCE_DECL(name) EventSource name = _EVENTSOURCE_DATA(name)
+
+/**
+ * @brief All events allowed mask.
+ */
+#define ALL_EVENTS ((eventmask_t)-1)
+
+/**
+ * @brief Returns an event mask from an event identifier.
+ */
+#define EVENT_MASK(eid) ((eventmask_t)(1 << (eid)))
+
+/**
+ * @name Macro Functions
+ * @{
+ */
+/**
+ * @brief Registers an Event Listener on an Event Source.
+ * @note Multiple Event Listeners can use the same event identifier, the
+ * listener will share the callback function.
+ *
+ * @param[in] esp pointer to the @p EventSource structure
+ * @param[out] elp pointer to the @p EventListener structure
+ * @param[in] eid numeric identifier assigned to the Event Listener. The
+ * identifier is used as index for the event callback
+ * function.
+ * The value must range between zero and the size, in bit,
+ * of the @p eventid_t type minus one.
+ *
+ * @api
+ */
+#define chEvtRegister(esp, elp, eid) \
+ chEvtRegisterMask(esp, elp, EVENT_MASK(eid))
+
+/**
+ * @brief Initializes an Event Source.
+ * @note This function can be invoked before the kernel is initialized
+ * because it just prepares a @p EventSource structure.
+ *
+ * @param[in] esp pointer to the @p EventSource structure
+ *
+ * @init
+ */
+#define chEvtInit(esp) \
+ ((esp)->es_next = (EventListener *)(void *)(esp))
+
+/**
+ * @brief Verifies if there is at least one @p EventListener registered.
+ *
+ * @param[in] esp pointer to the @p EventSource structure
+ *
+ * @iclass
+ */
+#define chEvtIsListeningI(esp) \
+ ((void *)(esp) != (void *)(esp)->es_next)
+
+/**
+ * @brief Signals all the Event Listeners registered on the specified Event
+ * Source.
+ *
+ * @param[in] esp pointer to the @p EventSource structure
+ *
+ * @api
+ */
+#define chEvtBroadcast(esp) chEvtBroadcastFlags(esp, 0)
+
+/**
+ * @brief Signals all the Event Listeners registered on the specified Event
+ * Source.
+ * @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] esp pointer to the @p EventSource structure
+ *
+ * @iclass
+ */
+#define chEvtBroadcastI(esp) chEvtBroadcastFlagsI(esp, 0)
+/** @} */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void chEvtRegisterMask(EventSource *esp,
+ EventListener *elp,
+ eventmask_t mask);
+ void chEvtUnregister(EventSource *esp, EventListener *elp);
+ eventmask_t chEvtGetAndClearEvents(eventmask_t mask);
+ eventmask_t chEvtAddEvents(eventmask_t mask);
+ flagsmask_t chEvtGetAndClearFlags(EventListener *elp);
+ flagsmask_t chEvtGetAndClearFlagsI(EventListener *elp);
+ void chEvtSignal(Thread *tp, eventmask_t mask);
+ void chEvtSignalI(Thread *tp, eventmask_t mask);
+ void chEvtBroadcastFlags(EventSource *esp, flagsmask_t flags);
+ void chEvtBroadcastFlagsI(EventSource *esp, flagsmask_t flags);
+ void chEvtDispatch(const evhandler_t *handlers, eventmask_t mask);
+#if CH_OPTIMIZE_SPEED || !CH_USE_EVENTS_TIMEOUT
+ eventmask_t chEvtWaitOne(eventmask_t mask);
+ eventmask_t chEvtWaitAny(eventmask_t mask);
+ eventmask_t chEvtWaitAll(eventmask_t mask);
+#endif
+#if CH_USE_EVENTS_TIMEOUT
+ eventmask_t chEvtWaitOneTimeout(eventmask_t mask, systime_t time);
+ eventmask_t chEvtWaitAnyTimeout(eventmask_t mask, systime_t time);
+ eventmask_t chEvtWaitAllTimeout(eventmask_t mask, systime_t time);
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#if !CH_OPTIMIZE_SPEED && CH_USE_EVENTS_TIMEOUT
+#define chEvtWaitOne(mask) chEvtWaitOneTimeout(mask, TIME_INFINITE)
+#define chEvtWaitAny(mask) chEvtWaitAnyTimeout(mask, TIME_INFINITE)
+#define chEvtWaitAll(mask) chEvtWaitAllTimeout(mask, TIME_INFINITE)
+#endif
+
+#endif /* CH_USE_EVENTS */
+
+#endif /* _CHEVENTS_H_ */
+
+/** @} */
diff --git a/os/kernel/include/chfiles.h b/os/kernel/include/chfiles.h new file mode 100644 index 000000000..ad2974ad8 --- /dev/null +++ b/os/kernel/include/chfiles.h @@ -0,0 +1,165 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 chfiles.h
+ * @brief Data files.
+ * @details This header defines abstract interfaces useful to access generic
+ * data files in a standardized way.
+ *
+ * @addtogroup data_files
+ * @details This module define an abstract interface for generic data files by
+ * extending the @p BaseSequentialStream interface. Note that no code
+ * is present, data files are just abstract interface-like structures,
+ * you should look at the systems as to a set of abstract C++ classes
+ * (even if written in C). This system has the advantage to make the
+ * access to streams independent from the implementation logic.<br>
+ * The data files interface can be used as base class for high level
+ * object types such as an API for a File System implementation.
+ * @{
+ */
+
+#ifndef _CHFILES_H_
+#define _CHFILES_H_
+
+/**
+ * @brief No error return code.
+ */
+#define FILE_OK 0
+
+/**
+ * @brief Error code from the file stream methods.
+ */
+#define FILE_ERROR 0xFFFFFFFFUL
+
+/**
+ * @brief File offset type.
+ */
+typedef uint32_t fileoffset_t;
+
+/**
+ * @brief BaseFileStream specific methods.
+ */
+#define _base_file_stream_methods \
+ _base_sequential_stream_methods \
+ /* File close method.*/ \
+ uint32_t (*close)(void *instance); \
+ /* Get last error code method.*/ \
+ int (*geterror)(void *instance); \
+ /* File get size method.*/ \
+ fileoffset_t (*getsize)(void *instance); \
+ /* File get current position method.*/ \
+ fileoffset_t (*getposition)(void *instance); \
+ /* File seek method.*/ \
+ uint32_t (*lseek)(void *instance, fileoffset_t offset);
+
+/**
+ * @brief @p BaseFileStream specific data.
+ * @note It is empty because @p BaseFileStream is only an interface
+ * without implementation.
+ */
+#define _base_file_stream_data \
+ _base_sequential_stream_data
+
+/**
+ * @extends BaseSequentialStreamVMT
+ *
+ * @brief @p BaseFileStream virtual methods table.
+ */
+struct BaseFileStreamVMT {
+ _base_file_stream_methods
+};
+
+/**
+ * @extends BaseSequentialStream
+ *
+ * @brief Base file stream class.
+ * @details This class represents a generic file data stream.
+ */
+typedef struct {
+ /** @brief Virtual Methods Table.*/
+ const struct BaseFileStreamVMT *vmt;
+ _base_file_stream_data
+} BaseFileStream;
+
+/**
+ * @name Macro Functions (BaseFileStream)
+ * @{
+ */
+/**
+ * @brief Base file Stream close.
+ * @details The function closes a file stream.
+ *
+ * @param[in] ip pointer to a @p BaseFileStream or derived class
+ * @return The operation status.
+ * @retval FILE_OK no error.
+ * @retval FILE_ERROR operation failed.
+ *
+ * @api
+ */
+#define chFileStreamClose(ip) ((ip)->vmt->close(ip))
+
+/**
+ * @brief Returns an implementation dependent error code.
+ *
+ * @param[in] ip pointer to a @p BaseFileStream or derived class
+ * @return Implementation dependent error code.
+ *
+ * @api
+ */
+#define chFileStreamGetError(ip) ((ip)->vmt->geterror(ip))
+
+/**
+ * @brief Returns the current file size.
+ *
+ * @param[in] ip pointer to a @p BaseFileStream or derived class
+ * @return The file size.
+ *
+ * @api
+ */
+#define chFileStreamGetSize(ip) ((ip)->vmt->getsize(ip))
+
+/**
+ * @brief Returns the current file pointer position.
+ *
+ * @param[in] ip pointer to a @p BaseFileStream or derived class
+ * @return The current position inside the file.
+ *
+ * @api
+ */
+#define chFileStreamGetPosition(ip) ((ip)->vmt->getposition(ip))
+
+/**
+ * @brief Moves the file current pointer to an absolute position.
+ *
+ * @param[in] ip pointer to a @p BaseFileStream or derived class
+ * @param[in] offset new absolute position
+ * @return The operation status.
+ * @retval FILE_OK no error.
+ * @retval FILE_ERROR operation failed.
+ *
+ * @api
+ */
+#define chFileStreamSeek(ip, offset) ((ip)->vmt->lseek(ip, offset))
+/** @} */
+
+#endif /* _CHFILES_H_ */
+
+/** @} */
diff --git a/os/kernel/include/chheap.h b/os/kernel/include/chheap.h new file mode 100644 index 000000000..8a54d7290 --- /dev/null +++ b/os/kernel/include/chheap.h @@ -0,0 +1,93 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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_USE_HEAP || defined(__DOXYGEN__)
+
+/*
+ * Module dependencies check.
+ */
+#if !CH_USE_MEMCORE && !CH_USE_MALLOC_HEAP
+#error "CH_USE_HEAP requires CH_USE_MEMCORE or CH_USE_MALLOC_HEAP"
+#endif
+
+#if !CH_USE_MUTEXES && !CH_USE_SEMAPHORES
+#error "CH_USE_HEAP requires CH_USE_MUTEXES and/or CH_USE_SEMAPHORES"
+#endif
+
+typedef struct memory_heap MemoryHeap;
+
+/**
+ * @brief Memory heap block header.
+ */
+union heap_header {
+ stkalign_t align;
+ struct {
+ union {
+ union heap_header *next; /**< @brief Next block in free list. */
+ MemoryHeap *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_USE_MUTEXES
+ Mutex h_mtx; /**< @brief Heap access mutex. */
+#else
+ Semaphore h_sem; /**< @brief Heap access semaphore. */
+#endif
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void _heap_init(void);
+#if !CH_USE_MALLOC_HEAP
+ void chHeapInit(MemoryHeap *heapp, void *buf, size_t size);
+#endif
+ void *chHeapAlloc(MemoryHeap *heapp, size_t size);
+ void chHeapFree(void *p);
+ size_t chHeapStatus(MemoryHeap *heapp, size_t *sizep);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CH_USE_HEAP */
+
+#endif /* _CHHEAP_H_ */
+
+/** @} */
diff --git a/os/kernel/include/chinline.h b/os/kernel/include/chinline.h new file mode 100644 index 000000000..46ac45a84 --- /dev/null +++ b/os/kernel/include/chinline.h @@ -0,0 +1,87 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 chinline.h
+ * @brief Kernel inlined functions.
+ * @details In this file there are a set of inlined functions if the
+ * @p CH_OPTIMIZE_SPEED is enabled.
+ */
+
+#ifndef _CHINLINE_H_
+#define _CHINLINE_H_
+
+/* If the performance code path has been chosen then all the following
+ functions are inlined into the various kernel modules.*/
+#if CH_OPTIMIZE_SPEED
+static INLINE void prio_insert(Thread *tp, ThreadsQueue *tqp) {
+
+ Thread *cp = (Thread *)tqp;
+ do {
+ cp = cp->p_next;
+ } while ((cp != (Thread *)tqp) && (cp->p_prio >= tp->p_prio));
+ tp->p_next = cp;
+ tp->p_prev = cp->p_prev;
+ tp->p_prev->p_next = cp->p_prev = tp;
+}
+
+static INLINE void queue_insert(Thread *tp, ThreadsQueue *tqp) {
+
+ tp->p_next = (Thread *)tqp;
+ tp->p_prev = tqp->p_prev;
+ tp->p_prev->p_next = tqp->p_prev = tp;
+}
+
+static INLINE Thread *fifo_remove(ThreadsQueue *tqp) {
+ Thread *tp = tqp->p_next;
+
+ (tqp->p_next = tp->p_next)->p_prev = (Thread *)tqp;
+ return tp;
+}
+
+static INLINE Thread *lifo_remove(ThreadsQueue *tqp) {
+ Thread *tp = tqp->p_prev;
+
+ (tqp->p_prev = tp->p_prev)->p_next = (Thread *)tqp;
+ return tp;
+}
+
+static INLINE Thread *dequeue(Thread *tp) {
+
+ tp->p_prev->p_next = tp->p_next;
+ tp->p_next->p_prev = tp->p_prev;
+ return tp;
+}
+
+static INLINE void list_insert(Thread *tp, ThreadsList *tlp) {
+
+ tp->p_next = tlp->p_next;
+ tlp->p_next = tp;
+}
+
+static INLINE Thread *list_remove(ThreadsList *tlp) {
+
+ Thread *tp = tlp->p_next;
+ tlp->p_next = tp->p_next;
+ return tp;
+}
+#endif /* CH_OPTIMIZE_SPEED */
+
+#endif /* _CHINLINE_H_ */
diff --git a/os/kernel/include/chlists.h b/os/kernel/include/chlists.h new file mode 100644 index 000000000..caf2560b4 --- /dev/null +++ b/os/kernel/include/chlists.h @@ -0,0 +1,127 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 chlists.h
+ * @brief Thread queues/lists macros and structures.
+ * @note All the macros present in this module, while public, are not
+ * an OS API and should not be directly used in the user applications
+ * code.
+ *
+ * @addtogroup internals
+ * @{
+ */
+
+#ifndef _CHLISTS_H_
+#define _CHLISTS_H_
+
+typedef struct Thread Thread;
+
+/**
+ * @brief Threads queue initialization.
+ *
+ * @notapi
+ */
+#define queue_init(tqp) ((tqp)->p_next = (tqp)->p_prev = (Thread *)(tqp));
+
+/**
+ * @brief Threads list initialization.
+ *
+ * @notapi
+ */
+#define list_init(tlp) ((tlp)->p_next = (Thread *)(tlp))
+
+/**
+ * @brief Evaluates to @p TRUE if the specified threads queue or list is
+ * empty.
+ *
+ * @notapi
+ */
+#define isempty(p) ((p)->p_next == (Thread *)(p))
+
+/**
+ * @brief Evaluates to @p TRUE if the specified threads queue or list is
+ * not empty.
+ *
+ * @notapi
+ */
+#define notempty(p) ((p)->p_next != (Thread *)(p))
+
+/**
+ * @brief Data part of a static threads queue initializer.
+ * @details This macro should be used when statically initializing a threads
+ * queue that is part of a bigger structure.
+ *
+ * @param[in] name the name of the threads queue variable
+ */
+#define _THREADSQUEUE_DATA(name) {(Thread *)&name, (Thread *)&name}
+
+/**
+ * @brief Static threads queue initializer.
+ * @details Statically initialized threads queues require no explicit
+ * initialization using @p queue_init().
+ *
+ * @param[in] name the name of the threads queue variable
+ */
+#define THREADSQUEUE_DECL(name) ThreadsQueue name = _THREADSQUEUE_DATA(name)
+
+/**
+ * @extends ThreadsList
+ *
+ * @brief Generic threads bidirectional linked list header and element.
+ */
+typedef struct {
+ Thread *p_next; /**< First @p Thread in the queue, or
+ @p ThreadQueue when empty. */
+ Thread *p_prev; /**< Last @p Thread in the queue, or
+ @p ThreadQueue when empty. */
+} ThreadsQueue;
+
+/**
+ * @brief Generic threads single link list, it works like a stack.
+ */
+typedef struct {
+
+ Thread *p_next; /**< Last pushed @p Thread on the stack
+ list, or pointer to itself if
+ empty. */
+} ThreadsList;
+
+#if !CH_OPTIMIZE_SPEED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void prio_insert(Thread *tp, ThreadsQueue *tqp);
+ void queue_insert(Thread *tp, ThreadsQueue *tqp);
+ Thread *fifo_remove(ThreadsQueue *tqp);
+ Thread *lifo_remove(ThreadsQueue *tqp);
+ Thread *dequeue(Thread *tp);
+ void list_insert(Thread *tp, ThreadsList *tlp);
+ Thread *list_remove(ThreadsList *tlp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !CH_OPTIMIZE_SPEED */
+
+#endif /* _CHLISTS_H_ */
+
+/** @} */
diff --git a/os/kernel/include/chmboxes.h b/os/kernel/include/chmboxes.h new file mode 100644 index 000000000..85192e804 --- /dev/null +++ b/os/kernel/include/chmboxes.h @@ -0,0 +1,163 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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_USE_MAILBOXES || defined(__DOXYGEN__)
+
+/*
+ * Module dependencies check.
+ */
+#if !CH_USE_SEMAPHORES
+#error "CH_USE_MAILBOXES requires CH_USE_SEMAPHORES"
+#endif
+
+/**
+ * @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 mb_fullsem; /**< @brief Full counter
+ @p Semaphore. */
+ Semaphore mb_emptysem; /**< @brief Empty counter
+ @p Semaphore. */
+} Mailbox;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void chMBInit(Mailbox *mbp, msg_t *buf, cnt_t n);
+ void chMBReset(Mailbox *mbp);
+ msg_t chMBPost(Mailbox *mbp, msg_t msg, systime_t timeout);
+ msg_t chMBPostS(Mailbox *mbp, msg_t msg, systime_t timeout);
+ msg_t chMBPostI(Mailbox *mbp, msg_t msg);
+ msg_t chMBPostAhead(Mailbox *mbp, msg_t msg, systime_t timeout);
+ msg_t chMBPostAheadS(Mailbox *mbp, msg_t msg, systime_t timeout);
+ msg_t chMBPostAheadI(Mailbox *mbp, msg_t msg);
+ msg_t chMBFetch(Mailbox *mbp, msg_t *msgp, systime_t timeout);
+ msg_t chMBFetchS(Mailbox *mbp, msg_t *msgp, systime_t timeout);
+ msg_t chMBFetchI(Mailbox *mbp, msg_t *msgp);
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @name Macro Functions
+ * @{
+ */
+/**
+ * @brief Returns the mailbox buffer size.
+ *
+ * @param[in] mbp the pointer to an initialized Mailbox object
+ *
+ * @iclass
+ */
+#define chMBSizeI(mbp) \
+ ((mbp)->mb_top - (mbp)->mb_buffer)
+
+/**
+ * @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 object
+ * @return The number of empty message slots.
+ *
+ * @iclass
+ */
+#define chMBGetFreeCountI(mbp) 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 object
+ * @return The number of queued messages.
+ *
+ * @iclass
+ */
+#define chMBGetUsedCountI(mbp) 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.
+ *
+ * @iclass
+ */
+#define chMBPeekI(mbp) (*(mbp)->mb_rdptr)
+/** @} */
+
+/**
+ * @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 name = _MAILBOX_DATA(name, buffer, size)
+
+#endif /* CH_USE_MAILBOXES */
+
+#endif /* _CHMBOXES_H_ */
+
+/** @} */
diff --git a/os/kernel/include/chmemcore.h b/os/kernel/include/chmemcore.h new file mode 100644 index 000000000..4f75bd043 --- /dev/null +++ b/os/kernel/include/chmemcore.h @@ -0,0 +1,86 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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.h
+ * @brief Core memory manager macros and structures.
+ *
+ * @addtogroup memcore
+ * @{
+ */
+
+#ifndef _CHMEMCORE_H_
+#define _CHMEMCORE_H_
+
+/**
+ * @brief Memory get function.
+ * @note This type must be assignment compatible with the @p chMemAlloc()
+ * function.
+ */
+typedef void *(*memgetfunc_t)(size_t size);
+
+/**
+ * @name Alignment support macros
+ */
+/**
+ * @brief Alignment size constant.
+ */
+#define MEM_ALIGN_SIZE sizeof(stkalign_t)
+
+/**
+ * @brief Alignment mask constant.
+ */
+#define MEM_ALIGN_MASK (MEM_ALIGN_SIZE - 1)
+
+/**
+ * @brief Alignment helper macro.
+ */
+#define MEM_ALIGN_PREV(p) ((size_t)(p) & ~MEM_ALIGN_MASK)
+
+/**
+ * @brief Alignment helper macro.
+ */
+#define MEM_ALIGN_NEXT(p) MEM_ALIGN_PREV((size_t)(p) + MEM_ALIGN_MASK)
+
+/**
+ * @brief Returns whatever a pointer or memory size is aligned to
+ * the type @p align_t.
+ */
+#define MEM_IS_ALIGNED(p) (((size_t)(p) & MEM_ALIGN_MASK) == 0)
+/** @} */
+
+#if CH_USE_MEMCORE || defined(__DOXYGEN__)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void _core_init(void);
+ void *chCoreAlloc(size_t size);
+ void *chCoreAllocI(size_t size);
+ size_t chCoreStatus(void);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CH_USE_MEMCORE */
+
+#endif /* _CHMEMCORE_H_ */
+
+/** @} */
diff --git a/os/kernel/include/chmempools.h b/os/kernel/include/chmempools.h new file mode 100644 index 000000000..80d6eeaf2 --- /dev/null +++ b/os/kernel/include/chmempools.h @@ -0,0 +1,134 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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_USE_MEMPOOLS || defined(__DOXYGEN__)
+
+/**
+ * @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. */
+} MemoryPool;
+
+/**
+ * @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) \
+ MemoryPool name = _MEMORYPOOL_DATA(name, size, provider)
+
+/**
+ * @name Macro 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 MemoryPool structure
+ * @param[in] objp the pointer to the object to be added
+ *
+ * @api
+ */
+#define chPoolAdd(mp, 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 MemoryPool structure
+ * @param[in] objp the pointer to the object to be added
+ *
+ * @iclass
+ */
+#define chPoolAddI(mp, objp) chPoolFreeI(mp, objp)
+/** @} */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void chPoolInit(MemoryPool *mp, size_t size, memgetfunc_t provider);
+ void chPoolLoadArray(MemoryPool *mp, void *p, size_t n);
+ void *chPoolAllocI(MemoryPool *mp);
+ void *chPoolAlloc(MemoryPool *mp);
+ void chPoolFreeI(MemoryPool *mp, void *objp);
+ void chPoolFree(MemoryPool *mp, void *objp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CH_USE_MEMPOOLS */
+
+#endif /* _CHMEMPOOLS_H_ */
+
+/** @} */
diff --git a/os/kernel/include/chmsg.h b/os/kernel/include/chmsg.h new file mode 100644 index 000000000..e613a6aad --- /dev/null +++ b/os/kernel/include/chmsg.h @@ -0,0 +1,85 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 chmsg.h
+ * @brief Messages macros and structures.
+ *
+ * @addtogroup messages
+ * @{
+ */
+
+#ifndef _CHMSG_H_
+#define _CHMSG_H_
+
+#if CH_USE_MESSAGES || defined(__DOXYGEN__)
+
+/**
+ * @name Macro Functions
+ * @{
+ */
+/**
+ * @brief Evaluates to TRUE if the thread has pending messages.
+ *
+ * @iclass
+ */
+#define chMsgIsPendingI(tp) \
+ ((tp)->p_msgqueue.p_next != (Thread *)&(tp)->p_msgqueue)
+
+/**
+ * @brief Returns the message carried by the specified thread.
+ * @pre This function must be invoked immediately after exiting a call
+ * to @p chMsgWait().
+ *
+ * @param[in] tp pointer to the thread
+ * @return The message carried by the sender.
+ *
+ * @api
+ */
+#define chMsgGet(tp) ((tp)->p_msg)
+
+/**
+ * @brief Releases the thread waiting on top of the messages queue.
+ * @pre Invoke this function only after a message has been received
+ * using @p chMsgWait().
+ *
+ * @param[in] tp pointer to the thread
+ * @param[in] msg message to be returned to the sender
+ *
+ * @sclass
+ */
+#define chMsgReleaseS(tp, msg) chSchWakeupS(tp, msg)
+/** @} */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ msg_t chMsgSend(Thread *tp, msg_t msg);
+ Thread * chMsgWait(void);
+ void chMsgRelease(Thread *tp, msg_t msg);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CH_USE_MESSAGES */
+
+#endif /* _CHMSG_H_ */
+
+/** @} */
diff --git a/os/kernel/include/chmtx.h b/os/kernel/include/chmtx.h new file mode 100644 index 000000000..124127a88 --- /dev/null +++ b/os/kernel/include/chmtx.h @@ -0,0 +1,96 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 chmtx.h
+ * @brief Mutexes macros and structures.
+ *
+ * @addtogroup mutexes
+ * @{
+ */
+
+#ifndef _CHMTX_H_
+#define _CHMTX_H_
+
+#if CH_USE_MUTEXES || defined(__DOXYGEN__)
+
+/**
+ * @brief Mutex structure.
+ */
+typedef struct Mutex {
+ ThreadsQueue m_queue; /**< @brief Queue of the threads sleeping
+ on this Mutex. */
+ Thread *m_owner; /**< @brief Owner @p Thread pointer or
+ @p NULL. */
+ struct Mutex *m_next; /**< @brief Next @p Mutex into an
+ owner-list or @p NULL. */
+} Mutex;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void chMtxInit(Mutex *mp);
+ void chMtxLock(Mutex *mp);
+ void chMtxLockS(Mutex *mp);
+ bool_t chMtxTryLock(Mutex *mp);
+ bool_t chMtxTryLockS(Mutex *mp);
+ Mutex *chMtxUnlock(void);
+ Mutex *chMtxUnlockS(void);
+ void chMtxUnlockAll(void);
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @brief Data part of a static mutex initializer.
+ * @details This macro should be used when statically initializing a mutex
+ * that is part of a bigger structure.
+ *
+ * @param[in] name the name of the mutex variable
+ */
+#define _MUTEX_DATA(name) {_THREADSQUEUE_DATA(name.m_queue), NULL, NULL}
+
+/**
+ * @brief Static mutex initializer.
+ * @details Statically initialized mutexes require no explicit initialization
+ * using @p chMtxInit().
+ *
+ * @param[in] name the name of the mutex variable
+ */
+#define MUTEX_DECL(name) Mutex name = _MUTEX_DATA(name)
+
+/**
+ * @name Macro Functions
+ * @{
+ */
+/**
+ * @brief Returns @p TRUE if the mutex queue contains at least a waiting
+ * thread.
+ *
+ * @sclass
+ */
+#define chMtxQueueNotEmptyS(mp) notempty(&(mp)->m_queue)
+/** @} */
+
+#endif /* CH_USE_MUTEXES */
+
+#endif /* _CHMTX_H_ */
+
+/** @} */
diff --git a/os/kernel/include/chqueues.h b/os/kernel/include/chqueues.h new file mode 100644 index 000000000..507f020d1 --- /dev/null +++ b/os/kernel/include/chqueues.h @@ -0,0 +1,369 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 chqueues.h
+ * @brief I/O Queues macros and structures.
+ *
+ * @addtogroup io_queues
+ * @{
+ */
+
+#ifndef _CHQUEUES_H_
+#define _CHQUEUES_H_
+
+#if CH_USE_QUEUES || defined(__DOXYGEN__)
+
+/**
+ * @name Queue functions returned status value
+ * @{
+ */
+#define Q_OK RDY_OK /**< @brief Operation successful. */
+#define Q_TIMEOUT RDY_TIMEOUT /**< @brief Timeout condition. */
+#define Q_RESET RDY_RESET /**< @brief Queue has been reset. */
+#define Q_EMPTY -3 /**< @brief Queue empty. */
+#define Q_FULL -4 /**< @brief Queue full, */
+/** @} */
+
+/**
+ * @brief Type of a generic I/O queue structure.
+ */
+typedef struct GenericQueue GenericQueue;
+
+/** @brief Queue notification callback type.*/
+typedef void (*qnotify_t)(GenericQueue *qp);
+
+/**
+ * @brief Generic I/O queue structure.
+ * @details This structure represents a generic Input or Output asymmetrical
+ * queue. The queue is asymmetrical because one end is meant to be
+ * accessed from a thread context, and thus can be blocking, the other
+ * end is accessible from interrupt handlers or from within a kernel
+ * lock zone (see <b>I-Locked</b> and <b>S-Locked</b> states in
+ * @ref system_states) and is non-blocking.
+ */
+struct GenericQueue {
+ ThreadsQueue q_waiting; /**< @brief Queue of waiting threads. */
+ size_t q_counter; /**< @brief Resources counter. */
+ uint8_t *q_buffer; /**< @brief Pointer to the queue buffer.*/
+ uint8_t *q_top; /**< @brief Pointer to the first location
+ after the buffer. */
+ uint8_t *q_wrptr; /**< @brief Write pointer. */
+ uint8_t *q_rdptr; /**< @brief Read pointer. */
+ qnotify_t q_notify; /**< @brief Data notification callback. */
+ void *q_link; /**< @brief Application defined field. */
+};
+
+/**
+ * @name Macro Functions
+ * @{
+ */
+/**
+ * @brief Returns the queue's buffer size.
+ *
+ * @param[in] qp pointer to a @p GenericQueue structure.
+ * @return The buffer size.
+ *
+ * @iclass
+ */
+#define chQSizeI(qp) ((size_t)((qp)->q_top - (qp)->q_buffer))
+
+/**
+ * @brief Queue space.
+ * @details Returns the used space if used on an input queue or the empty
+ * space if used on an output queue.
+ *
+ * @param[in] qp pointer to a @p GenericQueue structure.
+ * @return The buffer space.
+ *
+ * @iclass
+ */
+#define chQSpaceI(qp) ((qp)->q_counter)
+
+/**
+ * @brief Returns the queue application-defined link.
+ * @note This function can be called in any context.
+ *
+ * @param[in] qp pointer to a @p GenericQueue structure.
+ * @return The application-defined link.
+ *
+ * @special
+ */
+#define chQGetLink(qp) ((qp)->q_link)
+/** @} */
+
+/**
+ * @extends GenericQueue
+ *
+ * @brief Type of an input queue structure.
+ * @details This structure represents a generic asymmetrical input queue.
+ * Writing to the queue is non-blocking and can be performed from
+ * interrupt handlers or from within a kernel lock zone (see
+ * <b>I-Locked</b> and <b>S-Locked</b> states in @ref system_states).
+ * Reading the queue can be a blocking operation and is supposed to
+ * be performed by a system thread.
+ */
+typedef GenericQueue InputQueue;
+
+/**
+ * @name Macro Functions
+ * @{
+ */
+/**
+ * @brief Returns the filled space into an input queue.
+ *
+ * @param[in] iqp pointer to an @p InputQueue structure
+ * @return The number of full bytes in the queue.
+ * @retval 0 if the queue is empty.
+ *
+ * @iclass
+ */
+#define chIQGetFullI(iqp) chQSpaceI(iqp)
+
+/**
+ * @brief Returns the empty space into an input queue.
+ *
+ * @param[in] iqp pointer to an @p InputQueue structure
+ * @return The number of empty bytes in the queue.
+ * @retval 0 if the queue is full.
+ *
+ * @iclass
+ */
+#define chIQGetEmptyI(iqp) (chQSizeI(iqp) - chQSpaceI(iqp))
+
+/**
+ * @brief Evaluates to @p TRUE if the specified input queue is empty.
+ *
+ * @param[in] iqp pointer to an @p InputQueue structure.
+ * @return The queue status.
+ * @retval FALSE if the queue is not empty.
+ * @retval TRUE if the queue is empty.
+ *
+ * @iclass
+ */
+#define chIQIsEmptyI(iqp) ((bool_t)(chQSpaceI(iqp) <= 0))
+
+/**
+ * @brief Evaluates to @p TRUE if the specified input queue is full.
+ *
+ * @param[in] iqp pointer to an @p InputQueue structure.
+ * @return The queue status.
+ * @retval FALSE if the queue is not full.
+ * @retval TRUE if the queue is full.
+ *
+ * @iclass
+ */
+#define chIQIsFullI(iqp) ((bool_t)(((iqp)->q_wrptr == (iqp)->q_rdptr) && \
+ ((iqp)->q_counter != 0)))
+
+/**
+ * @brief Input queue read.
+ * @details This function reads a byte value from an input queue. If the queue
+ * is empty then the calling thread is suspended until a byte arrives
+ * in the queue.
+ *
+ * @param[in] iqp pointer to an @p InputQueue structure
+ * @return A byte value from the queue.
+ * @retval Q_RESET if the queue has been reset.
+ *
+ * @api
+ */
+#define chIQGet(iqp) chIQGetTimeout(iqp, TIME_INFINITE)
+/** @} */
+
+/**
+ * @brief Data part of a static input queue initializer.
+ * @details This macro should be used when statically initializing an
+ * input queue that is part of a bigger structure.
+ *
+ * @param[in] name the name of the input queue variable
+ * @param[in] buffer pointer to the queue buffer area
+ * @param[in] size size of the queue buffer area
+ * @param[in] inotify input notification callback pointer
+ * @param[in] link application defined pointer
+ */
+#define _INPUTQUEUE_DATA(name, buffer, size, inotify, link) { \
+ _THREADSQUEUE_DATA(name), \
+ 0, \
+ (uint8_t *)(buffer), \
+ (uint8_t *)(buffer) + (size), \
+ (uint8_t *)(buffer), \
+ (uint8_t *)(buffer), \
+ (inotify), \
+ (link) \
+}
+
+/**
+ * @brief Static input queue initializer.
+ * @details Statically initialized input queues require no explicit
+ * initialization using @p chIQInit().
+ *
+ * @param[in] name the name of the input queue variable
+ * @param[in] buffer pointer to the queue buffer area
+ * @param[in] size size of the queue buffer area
+ * @param[in] inotify input notification callback pointer
+ * @param[in] link application defined pointer
+ */
+#define INPUTQUEUE_DECL(name, buffer, size, inotify, link) \
+ InputQueue name = _INPUTQUEUE_DATA(name, buffer, size, inotify, link)
+
+/**
+ * @extends GenericQueue
+ *
+ * @brief Type of an output queue structure.
+ * @details This structure represents a generic asymmetrical output queue.
+ * Reading from the queue is non-blocking and can be performed from
+ * interrupt handlers or from within a kernel lock zone (see
+ * <b>I-Locked</b> and <b>S-Locked</b> states in @ref system_states).
+ * Writing the queue can be a blocking operation and is supposed to
+ * be performed by a system thread.
+ */
+typedef GenericQueue OutputQueue;
+
+/**
+ * @name Macro Functions
+ * @{
+ */
+/**
+ * @brief Returns the filled space into an output queue.
+ *
+ * @param[in] oqp pointer to an @p OutputQueue structure
+ * @return The number of full bytes in the queue.
+ * @retval 0 if the queue is empty.
+ *
+ * @iclass
+ */
+#define chOQGetFullI(oqp) (chQSizeI(oqp) - chQSpaceI(oqp))
+
+/**
+ * @brief Returns the empty space into an output queue.
+ *
+ * @param[in] oqp pointer to an @p OutputQueue structure
+ * @return The number of empty bytes in the queue.
+ * @retval 0 if the queue is full.
+ *
+ * @iclass
+ */
+#define chOQGetEmptyI(oqp) chQSpaceI(oqp)
+
+/**
+ * @brief Evaluates to @p TRUE if the specified output queue is empty.
+ *
+ * @param[in] oqp pointer to an @p OutputQueue structure.
+ * @return The queue status.
+ * @retval FALSE if the queue is not empty.
+ * @retval TRUE if the queue is empty.
+ *
+ * @iclass
+ */
+#define chOQIsEmptyI(oqp) ((bool_t)(((oqp)->q_wrptr == (oqp)->q_rdptr) && \
+ ((oqp)->q_counter != 0)))
+
+/**
+ * @brief Evaluates to @p TRUE if the specified output queue is full.
+ *
+ * @param[in] oqp pointer to an @p OutputQueue structure.
+ * @return The queue status.
+ * @retval FALSE if the queue is not full.
+ * @retval TRUE if the queue is full.
+ *
+ * @iclass
+ */
+#define chOQIsFullI(oqp) ((bool_t)(chQSpaceI(oqp) <= 0))
+
+/**
+ * @brief Output queue write.
+ * @details This function writes a byte value to an output queue. If the queue
+ * is full then the calling thread is suspended until there is space
+ * in the queue.
+ *
+ * @param[in] oqp pointer to an @p OutputQueue structure
+ * @param[in] b the byte value to be written in the queue
+ * @return The operation status.
+ * @retval Q_OK if the operation succeeded.
+ * @retval Q_RESET if the queue has been reset.
+ *
+ * @api
+ */
+#define chOQPut(oqp, b) chOQPutTimeout(oqp, b, TIME_INFINITE)
+ /** @} */
+
+/**
+ * @brief Data part of a static output queue initializer.
+ * @details This macro should be used when statically initializing an
+ * output queue that is part of a bigger structure.
+ *
+ * @param[in] name the name of the output queue variable
+ * @param[in] buffer pointer to the queue buffer area
+ * @param[in] size size of the queue buffer area
+ * @param[in] onotify output notification callback pointer
+ * @param[in] link application defined pointer
+ */
+#define _OUTPUTQUEUE_DATA(name, buffer, size, onotify, link) { \
+ _THREADSQUEUE_DATA(name), \
+ (size), \
+ (uint8_t *)(buffer), \
+ (uint8_t *)(buffer) + (size), \
+ (uint8_t *)(buffer), \
+ (uint8_t *)(buffer), \
+ (onotify), \
+ (link) \
+}
+
+/**
+ * @brief Static output queue initializer.
+ * @details Statically initialized output queues require no explicit
+ * initialization using @p chOQInit().
+ *
+ * @param[in] name the name of the output queue variable
+ * @param[in] buffer pointer to the queue buffer area
+ * @param[in] size size of the queue buffer area
+ * @param[in] onotify output notification callback pointer
+ * @param[in] link application defined pointer
+ */
+#define OUTPUTQUEUE_DECL(name, buffer, size, onotify, link) \
+ OutputQueue name = _OUTPUTQUEUE_DATA(name, buffer, size, onotify, link)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void chIQInit(InputQueue *iqp, uint8_t *bp, size_t size, qnotify_t infy,
+ void *link);
+ void chIQResetI(InputQueue *iqp);
+ msg_t chIQPutI(InputQueue *iqp, uint8_t b);
+ msg_t chIQGetTimeout(InputQueue *iqp, systime_t time);
+ size_t chIQReadTimeout(InputQueue *iqp, uint8_t *bp,
+ size_t n, systime_t time);
+
+ void chOQInit(OutputQueue *oqp, uint8_t *bp, size_t size, qnotify_t onfy,
+ void *link);
+ void chOQResetI(OutputQueue *oqp);
+ msg_t chOQPutTimeout(OutputQueue *oqp, uint8_t b, systime_t time);
+ msg_t chOQGetI(OutputQueue *oqp);
+ size_t chOQWriteTimeout(OutputQueue *oqp, const uint8_t *bp,
+ size_t n, systime_t time);
+#ifdef __cplusplus
+}
+#endif
+#endif /* CH_USE_QUEUES */
+
+#endif /* _CHQUEUES_H_ */
+
+/** @} */
diff --git a/os/kernel/include/chregistry.h b/os/kernel/include/chregistry.h new file mode 100644 index 000000000..446de7aca --- /dev/null +++ b/os/kernel/include/chregistry.h @@ -0,0 +1,130 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 chregistry.h
+ * @brief Threads registry macros and structures.
+ *
+ * @addtogroup registry
+ * @{
+ */
+
+#ifndef _CHREGISTRY_H_
+#define _CHREGISTRY_H_
+
+#if CH_USE_REGISTRY || defined(__DOXYGEN__)
+
+/**
+ * @brief ChibiOS/RT memory signature record.
+ */
+typedef struct {
+ char ch_identifier[4]; /**< @brief Always set to "main". */
+ uint8_t ch_zero; /**< @brief Must be zero. */
+ uint8_t ch_size; /**< @brief Size of this structure. */
+ uint16_t ch_version; /**< @brief Encoded ChibiOS/RT version. */
+ uint8_t ch_ptrsize; /**< @brief Size of a pointer. */
+ uint8_t ch_timesize; /**< @brief Size of a @p systime_t. */
+ uint8_t ch_threadsize; /**< @brief Size of a @p Thread struct. */
+ uint8_t cf_off_prio; /**< @brief Offset of @p p_prio field. */
+ uint8_t cf_off_ctx; /**< @brief Offset of @p p_ctx field. */
+ uint8_t cf_off_newer; /**< @brief Offset of @p p_newer field. */
+ uint8_t cf_off_older; /**< @brief Offset of @p p_older field. */
+ uint8_t cf_off_name; /**< @brief Offset of @p p_name field. */
+ uint8_t cf_off_stklimit; /**< @brief Offset of @p p_stklimit
+ field. */
+ uint8_t cf_off_state; /**< @brief Offset of @p p_state field. */
+ uint8_t cf_off_flags; /**< @brief Offset of @p p_flags field. */
+ uint8_t cf_off_refs; /**< @brief Offset of @p p_refs field. */
+ uint8_t cf_off_preempt; /**< @brief Offset of @p p_preempt
+ field. */
+ uint8_t cf_off_time; /**< @brief Offset of @p p_time field. */
+} chdebug_t;
+
+/**
+ * @name Macro Functions
+ * @{
+ */
+/**
+ * @brief Sets the current thread name.
+ * @pre This function only stores the pointer to the name if the option
+ * @p CH_USE_REGISTRY is enabled else no action is performed.
+ *
+ * @param[in] p thread name as a zero terminated string
+ *
+ * @api
+ */
+#define chRegSetThreadName(p) (currp->p_name = (p))
+
+/**
+ * @brief Returns the name of the specified thread.
+ * @pre This function only returns the pointer to the name if the option
+ * @p CH_USE_REGISTRY is enabled else @p NULL is returned.
+ *
+ * @param[in] tp pointer to the thread
+ *
+ * @return Thread name as a zero terminated string.
+ * @retval NULL if the thread name has not been set.
+ */
+#define chRegGetThreadName(tp) ((tp)->p_name)
+/** @} */
+#else /* !CH_USE_REGISTRY */
+#define chRegSetThreadName(p)
+#define chRegGetThreadName(tp) NULL
+#endif /* !CH_USE_REGISTRY */
+
+#if CH_USE_REGISTRY || defined(__DOXYGEN__)
+/**
+ * @brief Removes a thread from the registry list.
+ * @note This macro is not meant for use in application code.
+ *
+ * @param[in] tp thread to remove from the registry
+ */
+#define REG_REMOVE(tp) { \
+ (tp)->p_older->p_newer = (tp)->p_newer; \
+ (tp)->p_newer->p_older = (tp)->p_older; \
+}
+
+/**
+ * @brief Adds a thread to the registry list.
+ * @note This macro is not meant for use in application code.
+ *
+ * @param[in] tp thread to add to the registry
+ */
+#define REG_INSERT(tp) { \
+ (tp)->p_newer = (Thread *)&rlist; \
+ (tp)->p_older = rlist.r_older; \
+ (tp)->p_older->p_newer = rlist.r_older = (tp); \
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ extern ROMCONST chdebug_t ch_debug;
+ Thread *chRegFirstThread(void);
+ Thread *chRegNextThread(Thread *tp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CH_USE_REGISTRY */
+
+#endif /* _CHREGISTRY_H_ */
+
+/** @} */
diff --git a/os/kernel/include/chschd.h b/os/kernel/include/chschd.h new file mode 100644 index 000000000..37e457c31 --- /dev/null +++ b/os/kernel/include/chschd.h @@ -0,0 +1,237 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 chschd.h
+ * @brief Scheduler macros and structures.
+ *
+ * @addtogroup scheduler
+ * @{
+ */
+
+#ifndef _CHSCHD_H_
+#define _CHSCHD_H_
+
+/**
+ * @name Wakeup status codes
+ * @{
+ */
+#define RDY_OK 0 /**< @brief Normal wakeup message. */
+#define RDY_TIMEOUT -1 /**< @brief Wakeup caused by a timeout
+ condition. */
+#define RDY_RESET -2 /**< @brief Wakeup caused by a reset
+ condition. */
+/** @} */
+
+/**
+ * @name Priority constants
+ * @{
+ */
+#define NOPRIO 0 /**< @brief Ready list header priority. */
+#define IDLEPRIO 1 /**< @brief Idle thread priority. */
+#define LOWPRIO 2 /**< @brief Lowest user priority. */
+#define NORMALPRIO 64 /**< @brief Normal user priority. */
+#define HIGHPRIO 127 /**< @brief Highest user priority. */
+#define ABSPRIO 255 /**< @brief Greatest possible priority. */
+/** @} */
+
+/**
+ * @name Special time constants
+ * @{
+ */
+/**
+ * @brief Zero time specification for some functions with a timeout
+ * specification.
+ * @note Not all functions accept @p TIME_IMMEDIATE as timeout parameter,
+ * see the specific function documentation.
+ */
+#define TIME_IMMEDIATE ((systime_t)0)
+
+/**
+ * @brief Infinite time specification for all functions with a timeout
+ * specification.
+ */
+#define TIME_INFINITE ((systime_t)-1)
+/** @} */
+
+/**
+ * @brief Returns the priority of the first thread on the given ready list.
+ *
+ * @notapi
+ */
+#define firstprio(rlp) ((rlp)->p_next->p_prio)
+
+/**
+ * @extends ThreadsQueue
+ *
+ * @brief Ready list header.
+ */
+#if !defined(PORT_OPTIMIZED_READYLIST_STRUCT) || defined(__DOXYGEN__)
+typedef struct {
+ ThreadsQueue r_queue; /**< @brief Threads queue. */
+ tprio_t r_prio; /**< @brief This field must be
+ initialized to zero. */
+ struct context r_ctx; /**< @brief Not used, present because
+ offsets. */
+#if CH_USE_REGISTRY || defined(__DOXYGEN__)
+ Thread *r_newer; /**< @brief Newer registry element. */
+ Thread *r_older; /**< @brief Older registry element. */
+#endif
+ /* End of the fields shared with the Thread structure.*/
+ Thread *r_current; /**< @brief The currently running
+ thread. */
+} ReadyList;
+#endif /* !defined(PORT_OPTIMIZED_READYLIST_STRUCT) */
+
+#if !defined(PORT_OPTIMIZED_RLIST_EXT) && !defined(__DOXYGEN__)
+extern ReadyList rlist;
+#endif /* !defined(PORT_OPTIMIZED_RLIST_EXT) */
+
+/**
+ * @brief Current thread pointer access macro.
+ * @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.
+ * @note It is forbidden to use this macro in order to change the pointer
+ * (currp = something), use @p setcurrp() instead.
+ */
+#if !defined(PORT_OPTIMIZED_CURRP) || defined(__DOXYGEN__)
+#define currp rlist.r_current
+#endif /* !defined(PORT_OPTIMIZED_CURRP) */
+
+/**
+ * @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
+ */
+#if !defined(PORT_OPTIMIZED_SETCURRP) || defined(__DOXYGEN__)
+#define setcurrp(tp) (currp = (tp))
+#endif /* !defined(PORT_OPTIMIZED_SETCURRP) */
+
+/*
+ * Scheduler APIs.
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void _scheduler_init(void);
+#if !defined(PORT_OPTIMIZED_READYI)
+ Thread *chSchReadyI(Thread *tp);
+#endif
+#if !defined(PORT_OPTIMIZED_GOSLEEPS)
+ void chSchGoSleepS(tstate_t newstate);
+#endif
+#if !defined(PORT_OPTIMIZED_GOSLEEPTIMEOUTS)
+ msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time);
+#endif
+#if !defined(PORT_OPTIMIZED_WAKEUPS)
+ void chSchWakeupS(Thread *tp, msg_t msg);
+#endif
+#if !defined(PORT_OPTIMIZED_RESCHEDULES)
+ void chSchRescheduleS(void);
+#endif
+#if !defined(PORT_OPTIMIZED_ISPREEMPTIONREQUIRED)
+ bool_t chSchIsPreemptionRequired(void);
+#endif
+#if !defined(PORT_OPTIMIZED_DORESCHEDULEBEHIND) || defined(__DOXYGEN__)
+ void chSchDoRescheduleBehind(void);
+#endif
+#if !defined(PORT_OPTIMIZED_DORESCHEDULEAHEAD) || defined(__DOXYGEN__)
+ void chSchDoRescheduleAhead(void);
+#endif
+#if !defined(PORT_OPTIMIZED_DORESCHEDULE)
+ void chSchDoReschedule(void);
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @name Macro Functions
+ * @{
+ */
+/**
+ * @brief Determines if the current thread must reschedule.
+ * @details This function returns @p TRUE if there is a ready thread with
+ * higher priority.
+ *
+ * @iclass
+ */
+#if !defined(PORT_OPTIMIZED_ISRESCHREQUIREDI) || defined(__DOXYGEN__)
+#define chSchIsRescRequiredI() (firstprio(&rlist.r_queue) > currp->p_prio)
+#endif /* !defined(PORT_OPTIMIZED_ISRESCHREQUIREDI) */
+
+/**
+ * @brief Determines if yielding is possible.
+ * @details This function returns @p TRUE if there is a ready thread with
+ * equal or higher priority.
+ *
+ * @sclass
+ */
+#if !defined(PORT_OPTIMIZED_CANYIELDS) || defined(__DOXYGEN__)
+#define chSchCanYieldS() (firstprio(&rlist.r_queue) >= currp->p_prio)
+#endif /* !defined(PORT_OPTIMIZED_CANYIELDS) */
+
+/**
+ * @brief Yields the time slot.
+ * @details Yields the CPU control to the next thread in the ready list with
+ * equal or higher priority, if any.
+ *
+ * @sclass
+ */
+#if !defined(PORT_OPTIMIZED_DOYIELDS) || defined(__DOXYGEN__)
+#define chSchDoYieldS() { \
+ if (chSchCanYieldS()) \
+ chSchDoRescheduleBehind(); \
+}
+#endif /* !defined(PORT_OPTIMIZED_DOYIELDS) */
+
+/**
+ * @brief Inline-able preemption code.
+ * @details This is the common preemption code, this function must be invoked
+ * exclusively from the port layer.
+ *
+ * @special
+ */
+#if (CH_TIME_QUANTUM > 0) || defined(__DOXYGEN__)
+#define chSchPreemption() { \
+ tprio_t p1 = firstprio(&rlist.r_queue); \
+ tprio_t p2 = currp->p_prio; \
+ if (currp->p_preempt) { \
+ if (p1 > p2) \
+ chSchDoRescheduleAhead(); \
+ } \
+ else { \
+ if (p1 >= p2) \
+ chSchDoRescheduleBehind(); \
+ } \
+}
+#else /* CH_TIME_QUANTUM == 0 */
+#define chSchPreemption() { \
+ if (p1 >= p2) \
+ chSchDoRescheduleAhead(); \
+}
+#endif /* CH_TIME_QUANTUM == 0 */
+/** @} */
+
+#endif /* _CHSCHD_H_ */
+
+/** @} */
diff --git a/os/kernel/include/chsem.h b/os/kernel/include/chsem.h new file mode 100644 index 000000000..b5036af7c --- /dev/null +++ b/os/kernel/include/chsem.h @@ -0,0 +1,118 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 chsem.h
+ * @brief Semaphores macros and structures.
+ *
+ * @addtogroup semaphores
+ * @{
+ */
+
+#ifndef _CHSEM_H_
+#define _CHSEM_H_
+
+#if CH_USE_SEMAPHORES || defined(__DOXYGEN__)
+
+/**
+ * @brief Semaphore structure.
+ */
+typedef struct Semaphore {
+ ThreadsQueue s_queue; /**< @brief Queue of the threads sleeping
+ on this semaphore. */
+ cnt_t s_cnt; /**< @brief The semaphore counter. */
+} Semaphore;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void chSemInit(Semaphore *sp, cnt_t n);
+ void chSemReset(Semaphore *sp, cnt_t n);
+ void chSemResetI(Semaphore *sp, cnt_t n);
+ msg_t chSemWait(Semaphore *sp);
+ msg_t chSemWaitS(Semaphore *sp);
+ msg_t chSemWaitTimeout(Semaphore *sp, systime_t time);
+ msg_t chSemWaitTimeoutS(Semaphore *sp, systime_t time);
+ void chSemSignal(Semaphore *sp);
+ void chSemSignalI(Semaphore *sp);
+ void chSemAddCounterI(Semaphore *sp, cnt_t n);
+#if CH_USE_SEMSW
+ msg_t chSemSignalWait(Semaphore *sps, Semaphore *spw);
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @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] n the counter initial value, this value must be
+ * non-negative
+ */
+#define _SEMAPHORE_DATA(name, n) {_THREADSQUEUE_DATA(name.s_queue), n}
+
+/**
+ * @brief Static semaphore initializer.
+ * @details Statically initialized semaphores require no explicit
+ * initialization using @p chSemInit().
+ *
+ * @param[in] name the name of the semaphore variable
+ * @param[in] n the counter initial value, this value must be
+ * non-negative
+ */
+#define SEMAPHORE_DECL(name, n) Semaphore name = _SEMAPHORE_DATA(name, n)
+
+/**
+ * @name Macro Functions
+ * @{
+ */
+/**
+ * @brief Decreases the semaphore counter.
+ * @details This macro can be used when the counter is known to be positive.
+ *
+ * @iclass
+ */
+#define chSemFastWaitI(sp) ((sp)->s_cnt--)
+
+/**
+ * @brief Increases the semaphore counter.
+ * @details This macro can be used when the counter is known to be not
+ * negative.
+ *
+ * @iclass
+ */
+#define chSemFastSignalI(sp) ((sp)->s_cnt++)
+
+/**
+ * @brief Returns the semaphore counter current value.
+ *
+ * @iclass
+ */
+#define chSemGetCounterI(sp) ((sp)->s_cnt)
+/** @} */
+
+#endif /* CH_USE_SEMAPHORES */
+
+#endif /* _CHSEM_H_ */
+
+/** @} */
diff --git a/os/kernel/include/chstreams.h b/os/kernel/include/chstreams.h new file mode 100644 index 000000000..b9c40cac2 --- /dev/null +++ b/os/kernel/include/chstreams.h @@ -0,0 +1,147 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 chstreams.h
+ * @brief Data streams.
+ * @details This header defines abstract interfaces useful to access generic
+ * data streams in a standardized way.
+ *
+ * @addtogroup data_streams
+ * @details This module define an abstract interface for generic data streams.
+ * Note that no code is present, just abstract interfaces-like
+ * structures, you should look at the system as to a set of
+ * abstract C++ classes (even if written in C). This system
+ * has then advantage to make the access to data streams
+ * independent from the implementation logic.<br>
+ * The stream interface can be used as base class for high level
+ * object types such as files, sockets, serial ports, pipes etc.
+ * @{
+ */
+
+#ifndef _CHSTREAMS_H_
+#define _CHSTREAMS_H_
+
+/**
+ * @brief BaseSequentialStream specific methods.
+ */
+#define _base_sequential_stream_methods \
+ /* Stream write buffer method.*/ \
+ size_t (*write)(void *instance, const uint8_t *bp, size_t n); \
+ /* Stream read buffer method.*/ \
+ size_t (*read)(void *instance, uint8_t *bp, size_t n); \
+ /* Channel put method, blocking.*/ \
+ msg_t (*put)(void *instance, uint8_t b); \
+ /* Channel get method, blocking.*/ \
+ msg_t (*get)(void *instance); \
+
+/**
+ * @brief @p BaseSequentialStream specific data.
+ * @note It is empty because @p BaseSequentialStream is only an interface
+ * without implementation.
+ */
+#define _base_sequential_stream_data
+
+/**
+ * @brief @p BaseSequentialStream virtual methods table.
+ */
+struct BaseSequentialStreamVMT {
+ _base_sequential_stream_methods
+};
+
+/**
+ * @brief Base stream class.
+ * @details This class represents a generic blocking unbuffered sequential
+ * data stream.
+ */
+typedef struct {
+ /** @brief Virtual Methods Table.*/
+ const struct BaseSequentialStreamVMT *vmt;
+ _base_sequential_stream_data
+} BaseSequentialStream;
+
+/**
+ * @name Macro Functions (BaseSequentialStream)
+ * @{
+ */
+/**
+ * @brief Sequential Stream write.
+ * @details The function writes data from a buffer to a stream.
+ *
+ * @param[in] ip pointer to a @p BaseSequentialStream or derived class
+ * @param[in] bp pointer to the data buffer
+ * @param[in] n the maximum amount of data to be transferred
+ * @return The number of bytes transferred. The return value can
+ * be less than the specified number of bytes if an
+ * end-of-file condition has been met.
+ *
+ * @api
+ */
+#define chSequentialStreamWrite(ip, bp, n) ((ip)->vmt->write(ip, bp, n))
+
+/**
+ * @brief Sequential Stream read.
+ * @details The function reads data from a stream into a buffer.
+ *
+ * @param[in] ip pointer to a @p BaseSequentialStream or derived class
+ * @param[out] bp pointer to the data buffer
+ * @param[in] n the maximum amount of data to be transferred
+ * @return The number of bytes transferred. The return value can
+ * be less than the specified number of bytes if an
+ * end-of-file condition has been met.
+ *
+ * @api
+ */
+#define chSequentialStreamRead(ip, bp, n) ((ip)->vmt->read(ip, bp, n))
+
+/**
+ * @brief Sequential Stream blocking byte write.
+ * @details This function writes a byte value to a channel. If the channel
+ * is not ready to accept data then the calling thread is suspended.
+ *
+ * @param[in] ip pointer to a @p BaseChannel or derived class
+ * @param[in] b the byte value to be written to the channel
+ *
+ * @return The operation status.
+ * @retval Q_OK if the operation succeeded.
+ * @retval Q_RESET if an end-of-file condition has been met.
+ *
+ * @api
+ */
+#define chSequentialStreamPut(ip, b) ((ip)->vmt->put(ip, b))
+
+/**
+ * @brief Sequential Stream blocking byte read.
+ * @details This function reads a byte value from a channel. If the data
+ * is not available then the calling thread is suspended.
+ *
+ * @param[in] ip pointer to a @p BaseChannel or derived class
+ *
+ * @return A byte value from the queue.
+ * @retval Q_RESET if an end-of-file condition has been met.
+ *
+ * @api
+ */
+#define chSequentialStreamGet(ip) ((ip)->vmt->get(ip))
+/** @} */
+
+#endif /* _CHSTREAMS_H_ */
+
+/** @} */
diff --git a/os/kernel/include/chsys.h b/os/kernel/include/chsys.h new file mode 100644 index 000000000..a1f59f38e --- /dev/null +++ b/os/kernel/include/chsys.h @@ -0,0 +1,247 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 chsys.h
+ * @brief System related macros and structures.
+ *
+ * @addtogroup system
+ * @{
+ */
+
+#ifndef _CHSYS_H_
+#define _CHSYS_H_
+
+/**
+ * @name Macro Functions
+ * @{
+ */
+#if !CH_NO_IDLE_THREAD || defined(__DOXYGEN__)
+/**
+ * @brief Returns a pointer to the idle thread.
+ * @pre In order to use this function the option @p CH_NO_IDLE_THREAD
+ * must be disabled.
+ * @note The reference counter of the idle thread is not incremented but
+ * it is not strictly required being the idle thread a static
+ * object.
+ *
+ * @return Pointer to the idle thread.
+ *
+ * @api
+ */
+#define chSysGetIdleThread() (rlist.r_queue.p_prev)
+#endif
+
+/**
+ * @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 Can be invoked from any system state.
+ *
+ * @special
+ */
+#if !defined(SYSTEM_HALT_HOOK) || defined(__DOXYGEN__)
+#define chSysHalt() port_halt()
+#else
+#define chSysHalt() { \
+ SYSTEM_HALT_HOOK(); \
+ port_halt(); \
+}
+#endif
+
+/**
+ * @brief Performs a context switch.
+ * @note Not a user function, it is meant to be invoked by the scheduler
+ * itself or from within the port layer.
+ *
+ * @param[in] ntp the thread to be switched in
+ * @param[in] otp the thread to be switched out
+ *
+ * @special
+ */
+#define chSysSwitch(ntp, otp) { \
+ dbg_trace(otp); \
+ THREAD_CONTEXT_SWITCH_HOOK(ntp, otp); \
+ port_switch(ntp, otp); \
+}
+
+/**
+ * @brief Raises the system interrupt priority mask to the maximum level.
+ * @details All the maskable interrupt sources are disabled regardless their
+ * hardware priority.
+ * @note Do not invoke this API from within a kernel lock.
+ *
+ * @special
+ */
+#define chSysDisable() { \
+ port_disable(); \
+ dbg_check_disable(); \
+}
+
+/**
+ * @brief Raises the system interrupt priority mask to system level.
+ * @details The interrupt sources that should not be able to preempt the kernel
+ * are disabled, interrupt sources with higher priority are still
+ * enabled.
+ * @note Do not invoke this API from within a kernel lock.
+ * @note This API is no replacement for @p chSysLock(), the @p chSysLock()
+ * could do more than just disable the interrupts.
+ *
+ * @special
+ */
+#define 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 mode.
+ *
+ * @special
+ */
+#define chSysLock() { \
+ port_lock(); \
+ dbg_check_lock(); \
+}
+
+/**
+ * @brief Leaves the kernel lock mode.
+ *
+ * @special
+ */
+#define chSysUnlock() { \
+ dbg_check_unlock(); \
+ port_unlock(); \
+}
+
+/**
+ * @brief Enters the kernel lock mode from within an interrupt handler.
+ * @note This API may do nothing on some architectures, it is required
+ * because on ports that support preemptable interrupt handlers
+ * it is required to raise the interrupt mask to the same level of
+ * the system mutual exclusion zone.<br>
+ * It is good practice to invoke this API before invoking any I-class
+ * syscall from an interrupt handler.
+ * @note This API must be invoked exclusively from interrupt handlers.
+ *
+ * @special
+ */
+#define chSysLockFromIsr() { \
+ port_lock_from_isr(); \
+ dbg_check_lock_from_isr(); \
+}
+
+/**
+ * @brief Leaves the kernel lock mode from within an interrupt handler.
+ *
+ * @note This API may do nothing on some architectures, it is required
+ * because on ports that support preemptable interrupt handlers
+ * it is required to raise the interrupt mask to the same level of
+ * the system mutual exclusion zone.<br>
+ * It is good practice to invoke this API after invoking any I-class
+ * syscall from an interrupt handler.
+ * @note This API must be invoked exclusively from interrupt handlers.
+ *
+ * @special
+ */
+#define chSysUnlockFromIsr() { \
+ dbg_check_unlock_from_isr(); \
+ port_unlock_from_isr(); \
+}
+/** @} */
+
+/**
+ * @name ISRs abstraction macros
+ */
+/**
+ * @brief IRQ handler enter code.
+ * @note Usually IRQ handlers functions are also declared naked.
+ * @note On some architectures this macro can be empty.
+ *
+ * @special
+ */
+#define CH_IRQ_PROLOGUE() \
+ PORT_IRQ_PROLOGUE(); \
+ dbg_check_enter_isr();
+
+/**
+ * @brief IRQ handler exit code.
+ * @note Usually IRQ handlers function are also declared naked.
+ * @note This macro usually performs the final reschedule by using
+ * @p chSchIsPreemptionRequired() and @p chSchDoReschedule().
+ *
+ * @special
+ */
+#define CH_IRQ_EPILOGUE() \
+ dbg_check_leave_isr(); \
+ PORT_IRQ_EPILOGUE();
+
+/**
+ * @brief Standard normal IRQ handler declaration.
+ * @note @p id can be a function name or a vector number depending on the
+ * port implementation.
+ *
+ * @special
+ */
+#define CH_IRQ_HANDLER(id) PORT_IRQ_HANDLER(id)
+/** @} */
+
+/**
+ * @name Fast ISRs abstraction macros
+ */
+/**
+ * @brief Standard fast IRQ handler declaration.
+ * @note @p id can be a function name or a vector number depending on the
+ * port implementation.
+ * @note Not all architectures support fast interrupts.
+ *
+ * @special
+ */
+#define CH_FAST_IRQ_HANDLER(id) PORT_FAST_IRQ_HANDLER(id)
+/** @} */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void chSysInit(void);
+ void chSysTimerHandlerI(void);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CHSYS_H_ */
+
+/** @} */
diff --git a/os/kernel/include/chthreads.h b/os/kernel/include/chthreads.h new file mode 100644 index 000000000..77f72caca --- /dev/null +++ b/os/kernel/include/chthreads.h @@ -0,0 +1,380 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 chthreads.h
+ * @brief Threads macros and structures.
+ *
+ * @addtogroup threads
+ * @{
+ */
+
+#ifndef _CHTHREADS_H_
+#define _CHTHREADS_H_
+
+/**
+ * @name Thread states
+ * @{
+ */
+#define THD_STATE_READY 0 /**< @brief Waiting on the ready list. */
+#define THD_STATE_CURRENT 1 /**< @brief Currently running. */
+#define THD_STATE_SUSPENDED 2 /**< @brief Created in suspended state. */
+#define THD_STATE_WTSEM 3 /**< @brief Waiting on a semaphore. */
+#define THD_STATE_WTMTX 4 /**< @brief Waiting on a mutex. */
+#define THD_STATE_WTCOND 5 /**< @brief Waiting on a condition
+ variable. */
+#define THD_STATE_SLEEPING 6 /**< @brief Waiting in @p chThdSleep()
+ or @p chThdSleepUntil(). */
+#define THD_STATE_WTEXIT 7 /**< @brief Waiting in @p chThdWait(). */
+#define THD_STATE_WTOREVT 8 /**< @brief Waiting for an event. */
+#define THD_STATE_WTANDEVT 9 /**< @brief Waiting for several events. */
+#define THD_STATE_SNDMSGQ 10 /**< @brief Sending a message, in queue.*/
+#define THD_STATE_SNDMSG 11 /**< @brief Sent a message, waiting
+ answer. */
+#define THD_STATE_WTMSG 12 /**< @brief Waiting for a message. */
+#define THD_STATE_WTQUEUE 13 /**< @brief Waiting on an I/O queue. */
+#define THD_STATE_FINAL 14 /**< @brief Thread terminated. */
+
+/**
+ * @brief Thread states as array of strings.
+ * @details Each element in an array initialized with this macro can be
+ * indexed using the numeric thread state values.
+ */
+#define THD_STATE_NAMES \
+ "READY", "CURRENT", "SUSPENDED", "WTSEM", "WTMTX", "WTCOND", "SLEEPING", \
+ "WTEXIT", "WTOREVT", "WTANDEVT", "SNDMSGQ", "SNDMSG", "WTMSG", "WTQUEUE", \
+ "FINAL"
+/** @} */
+
+/**
+ * @name Thread flags and attributes
+ * @{
+ */
+#define THD_MEM_MODE_MASK 3 /**< @brief Thread memory mode mask. */
+#define THD_MEM_MODE_STATIC 0 /**< @brief Static thread. */
+#define THD_MEM_MODE_HEAP 1 /**< @brief Thread allocated from a
+ Memory Heap. */
+#define THD_MEM_MODE_MEMPOOL 2 /**< @brief Thread allocated from a
+ Memory Pool. */
+#define THD_TERMINATE 4 /**< @brief Termination requested flag. */
+/** @} */
+
+/**
+ * @extends ThreadsQueue
+ *
+ * @brief Structure representing a thread.
+ * @note Not all the listed fields are always needed, by switching off some
+ * not needed ChibiOS/RT subsystems it is possible to save RAM space
+ * by shrinking the @p Thread structure.
+ */
+struct Thread {
+ Thread *p_next; /**< @brief Next in the list/queue. */
+ /* End of the fields shared with the ThreadsList structure. */
+ Thread *p_prev; /**< @brief Previous in the queue. */
+ /* End of the fields shared with the ThreadsQueue structure. */
+ tprio_t p_prio; /**< @brief Thread priority. */
+ struct context p_ctx; /**< @brief Processor context. */
+#if CH_USE_REGISTRY || defined(__DOXYGEN__)
+ Thread *p_newer; /**< @brief Newer registry element. */
+ Thread *p_older; /**< @brief Older registry element. */
+#endif
+ /* End of the fields shared with the ReadyList structure. */
+#if CH_USE_REGISTRY || defined(__DOXYGEN__)
+ /**
+ * @brief Thread name or @p NULL.
+ */
+ const char *p_name;
+#endif
+#if CH_DBG_ENABLE_STACK_CHECK || defined(__DOXYGEN__)
+ /**
+ * @brief Thread stack boundary.
+ */
+ stkalign_t *p_stklimit;
+#endif
+ /**
+ * @brief Current thread state.
+ */
+ tstate_t p_state;
+ /**
+ * @brief Various thread flags.
+ */
+ tmode_t p_flags;
+#if CH_USE_DYNAMIC || defined(__DOXYGEN__)
+ /**
+ * @brief References to this thread.
+ */
+ trefs_t p_refs;
+#endif
+ /**
+ * @brief Number of ticks remaining to this thread.
+ */
+#if (CH_TIME_QUANTUM > 0) || defined(__DOXYGEN__)
+ tslices_t p_preempt;
+#endif
+#if CH_DBG_THREADS_PROFILING || defined(__DOXYGEN__)
+ /**
+ * @brief Thread consumed time in ticks.
+ * @note This field can overflow.
+ */
+ volatile systime_t p_time;
+#endif
+ /**
+ * @brief State-specific fields.
+ * @note All the fields declared in this union are only valid in the
+ * specified state or condition and are thus volatile.
+ */
+ union {
+ /**
+ * @brief Thread wakeup code.
+ * @note This field contains the low level message sent to the thread
+ * by the waking thread or interrupt handler. The value is valid
+ * after exiting the @p chSchWakeupS() function.
+ */
+ msg_t rdymsg;
+ /**
+ * @brief Thread exit code.
+ * @note The thread termination code is stored in this field in order
+ * to be retrieved by the thread performing a @p chThdWait() on
+ * this thread.
+ */
+ msg_t exitcode;
+ /**
+ * @brief Pointer to a generic "wait" object.
+ * @note This field is used to get a generic pointer to a synchronization
+ * object and is valid when the thread is in one of the wait
+ * states.
+ */
+ void *wtobjp;
+#if CH_USE_EVENTS || defined(__DOXYGEN__)
+ /**
+ * @brief Enabled events mask.
+ * @note This field is only valid while the thread is in the
+ * @p THD_STATE_WTOREVT or @p THD_STATE_WTANDEVT states.
+ */
+ eventmask_t ewmask;
+#endif
+ } p_u;
+#if CH_USE_WAITEXIT || defined(__DOXYGEN__)
+ /**
+ * @brief Termination waiting list.
+ */
+ ThreadsList p_waiting;
+#endif
+#if CH_USE_MESSAGES || defined(__DOXYGEN__)
+ /**
+ * @brief Messages queue.
+ */
+ ThreadsQueue p_msgqueue;
+ /**
+ * @brief Thread message.
+ */
+ msg_t p_msg;
+#endif
+#if CH_USE_EVENTS || defined(__DOXYGEN__)
+ /**
+ * @brief Pending events mask.
+ */
+ eventmask_t p_epending;
+#endif
+#if CH_USE_MUTEXES || defined(__DOXYGEN__)
+ /**
+ * @brief List of the mutexes owned by this thread.
+ * @note The list is terminated by a @p NULL in this field.
+ */
+ Mutex *p_mtxlist;
+ /**
+ * @brief Thread's own, non-inherited, priority.
+ */
+ tprio_t p_realprio;
+#endif
+#if (CH_USE_DYNAMIC && CH_USE_MEMPOOLS) || defined(__DOXYGEN__)
+ /**
+ * @brief Memory Pool where the thread workspace is returned.
+ */
+ void *p_mpool;
+#endif
+#if defined(THREAD_EXT_FIELDS)
+ /* Extra fields defined in chconf.h.*/
+ THREAD_EXT_FIELDS
+#endif
+};
+
+/**
+ * @brief Thread function.
+ */
+typedef msg_t (*tfunc_t)(void *);
+
+/**
+ * @name Macro Functions
+ * @{
+ */
+/**
+ * @brief Returns a pointer to the current @p Thread.
+ * @note Can be invoked in any context.
+ *
+ * @special
+ */
+#define chThdSelf() currp
+
+/**
+ * @brief Returns the current thread priority.
+ * @note Can be invoked in any context.
+ *
+ * @special
+ */
+#define chThdGetPriority() (currp->p_prio)
+
+/**
+ * @brief Returns the number of ticks consumed by the specified thread.
+ * @note This function is only available when the
+ * @p CH_DBG_THREADS_PROFILING configuration option is enabled.
+ * @note Can be invoked in any context.
+ *
+ * @param[in] tp pointer to the thread
+ *
+ * @special
+ */
+#define chThdGetTicks(tp) ((tp)->p_time)
+
+/**
+ * @brief Returns the pointer to the @p Thread local storage area, if any.
+ * @note Can be invoked in any context.
+ *
+ * @special
+ */
+#define chThdLS() (void *)(currp + 1)
+
+/**
+ * @brief Verifies if the specified thread is in the @p THD_STATE_FINAL state.
+ * @note Can be invoked in any context.
+ *
+ * @param[in] tp pointer to the thread
+ * @retval TRUE thread terminated.
+ * @retval FALSE thread not terminated.
+ *
+ * @special
+ */
+#define chThdTerminated(tp) ((tp)->p_state == THD_STATE_FINAL)
+
+/**
+ * @brief Verifies if the current thread has a termination request pending.
+ * @note Can be invoked in any context.
+ *
+ * @retval TRUE termination request pending.
+ * @retval FALSE termination request not pending.
+ *
+ * @special
+ */
+#define chThdShouldTerminate() (currp->p_flags & THD_TERMINATE)
+
+/**
+ * @brief Resumes a thread created with @p chThdCreateI().
+ *
+ * @param[in] tp pointer to the thread
+ *
+ * @iclass
+ */
+#define chThdResumeI(tp) chSchReadyI(tp)
+
+/**
+ * @brief Suspends the invoking thread for the specified time.
+ *
+ * @param[in] time the delay in system ticks, the special values are
+ * handled as follow:
+ * - @a TIME_INFINITE the thread enters an infinite sleep
+ * state.
+ * - @a TIME_IMMEDIATE this value is not allowed.
+ * .
+ *
+ * @sclass
+ */
+#define chThdSleepS(time) chSchGoSleepTimeoutS(THD_STATE_SLEEPING, time)
+
+/**
+ * @brief Delays the invoking thread for the specified number of seconds.
+ * @note The specified time is rounded up to a value allowed by the real
+ * system tick clock.
+ * @note The maximum specifiable value is implementation dependent.
+ *
+ * @param[in] sec time in seconds, must be different from zero
+ *
+ * @api
+ */
+#define chThdSleepSeconds(sec) chThdSleep(S2ST(sec))
+
+/**
+ * @brief Delays the invoking thread for the specified number of
+ * milliseconds.
+ * @note The specified time is rounded up to a value allowed by the real
+ * system tick clock.
+ * @note The maximum specifiable value is implementation dependent.
+ *
+ * @param[in] msec time in milliseconds, must be different from zero
+ *
+ * @api
+ */
+#define chThdSleepMilliseconds(msec) chThdSleep(MS2ST(msec))
+
+/**
+ * @brief Delays the invoking thread for the specified number of
+ * microseconds.
+ * @note The specified time is rounded up to a value allowed by the real
+ * system tick clock.
+ * @note The maximum specifiable value is implementation dependent.
+ *
+ * @param[in] usec time in microseconds, must be different from zero
+ *
+ * @api
+ */
+#define chThdSleepMicroseconds(usec) chThdSleep(US2ST(usec))
+/** @} */
+
+/*
+ * Threads APIs.
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+ Thread *_thread_init(Thread *tp, tprio_t prio);
+#if CH_DBG_FILL_THREADS
+ void _thread_memfill(uint8_t *startp, uint8_t *endp, uint8_t v);
+#endif
+ Thread *chThdCreateI(void *wsp, size_t size,
+ tprio_t prio, tfunc_t pf, void *arg);
+ Thread *chThdCreateStatic(void *wsp, size_t size,
+ tprio_t prio, tfunc_t pf, void *arg);
+ tprio_t chThdSetPriority(tprio_t newprio);
+ Thread *chThdResume(Thread *tp);
+ void chThdTerminate(Thread *tp);
+ void chThdSleep(systime_t time);
+ void chThdSleepUntil(systime_t time);
+ void chThdYield(void);
+ void chThdExit(msg_t msg);
+ void chThdExitS(msg_t msg);
+#if CH_USE_WAITEXIT
+ msg_t chThdWait(Thread *tp);
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CHTHREADS_H_ */
+
+/** @} */
diff --git a/os/kernel/include/chvt.h b/os/kernel/include/chvt.h new file mode 100644 index 000000000..97a04d81e --- /dev/null +++ b/os/kernel/include/chvt.h @@ -0,0 +1,228 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 chvt.h
+ * @brief Time macros and structures.
+ *
+ * @addtogroup time
+ * @{
+ */
+
+#ifndef _CHVT_H_
+#define _CHVT_H_
+
+/**
+ * @name Time conversion utilities
+ * @{
+ */
+/**
+ * @brief Seconds to system ticks.
+ * @details Converts from seconds to system ticks number.
+ * @note The result is rounded upward to the next tick boundary.
+ *
+ * @param[in] sec number of seconds
+ * @return The number of ticks.
+ *
+ * @api
+ */
+#define S2ST(sec) \
+ ((systime_t)((sec) * CH_FREQUENCY))
+
+/**
+ * @brief Milliseconds to system ticks.
+ * @details Converts from milliseconds to system ticks number.
+ * @note The result is rounded upward to the next tick boundary.
+ *
+ * @param[in] msec number of milliseconds
+ * @return The number of ticks.
+ *
+ * @api
+ */
+#define MS2ST(msec) \
+ ((systime_t)((((msec) * CH_FREQUENCY - 1L) / 1000L) + 1L))
+
+/**
+ * @brief Microseconds to system ticks.
+ * @details Converts from microseconds to system ticks number.
+ * @note The result is rounded upward to the next tick boundary.
+ *
+ * @param[in] usec number of microseconds
+ * @return The number of ticks.
+ *
+ * @api
+ */
+#define US2ST(usec) \
+ ((systime_t)((((usec) * CH_FREQUENCY - 1L) / 1000000L) + 1L))
+/** @} */
+
+/**
+ * @brief Virtual Timer callback function.
+ */
+typedef void (*vtfunc_t)(void *);
+
+/**
+ * @brief Virtual Timer structure type.
+ */
+typedef struct VirtualTimer VirtualTimer;
+
+/**
+ * @extends VTList
+ *
+ * @brief Virtual Timer descriptor structure.
+ */
+struct VirtualTimer {
+ VirtualTimer *vt_next; /**< @brief Next timer in the delta
+ list. */
+ VirtualTimer *vt_prev; /**< @brief Previous timer in the delta
+ list. */
+ systime_t vt_time; /**< @brief Time delta before timeout. */
+ vtfunc_t vt_func; /**< @brief Timer callback function
+ pointer. */
+ void *vt_par; /**< @brief Timer callback function
+ parameter. */
+};
+
+/**
+ * @brief Virtual timers list header.
+ * @note The delta list is implemented as a double link bidirectional list
+ * in order to make the unlink time constant, the reset of a virtual
+ * timer is often used in the code.
+ */
+typedef struct {
+ VirtualTimer *vt_next; /**< @brief Next timer in the delta
+ list. */
+ VirtualTimer *vt_prev; /**< @brief Last timer in the delta
+ list. */
+ systime_t vt_time; /**< @brief Must be initialized to -1. */
+ volatile systime_t vt_systime; /**< @brief System Time counter. */
+} VTList;
+
+/**
+ * @name Macro Functions
+ * @{
+ */
+/**
+ * @brief Virtual timers ticker.
+ * @note The system lock is released before entering the callback and
+ * re-acquired immediately after. It is callback's responsibility
+ * to acquire the lock if needed. This is done in order to reduce
+ * interrupts jitter when many timers are in use.
+ *
+ * @iclass
+ */
+#define chVTDoTickI() { \
+ vtlist.vt_systime++; \
+ if (&vtlist != (VTList *)vtlist.vt_next) { \
+ VirtualTimer *vtp; \
+ \
+ --vtlist.vt_next->vt_time; \
+ while (!(vtp = vtlist.vt_next)->vt_time) { \
+ vtfunc_t fn = vtp->vt_func; \
+ vtp->vt_func = (vtfunc_t)NULL; \
+ vtp->vt_next->vt_prev = (void *)&vtlist; \
+ (&vtlist)->vt_next = vtp->vt_next; \
+ chSysUnlockFromIsr(); \
+ fn(vtp->vt_par); \
+ chSysLockFromIsr(); \
+ } \
+ } \
+}
+
+/**
+ * @brief Returns @p TRUE if the specified timer is armed.
+ *
+ * @iclass
+ */
+#define chVTIsArmedI(vtp) ((vtp)->vt_func != NULL)
+
+/**
+ * @brief Enables a virtual timer.
+ * @note The associated function is invoked from interrupt context.
+ *
+ * @param[out] vtp the @p VirtualTimer structure pointer
+ * @param[in] time the number of ticks before the operation timeouts, the
+ * special values are handled as follow:
+ * - @a TIME_INFINITE is allowed but interpreted as a
+ * normal time specification.
+ * - @a TIME_IMMEDIATE this value is not allowed.
+ * .
+ * @param[in] vtfunc the timer callback function. After invoking the
+ * callback the timer is disabled and the structure can
+ * be disposed or reused.
+ * @param[in] par a parameter that will be passed to the callback
+ * function
+ *
+ * @api
+ */
+#define chVTSet(vtp, time, vtfunc, par) { \
+ chSysLock(); \
+ chVTSetI(vtp, time, vtfunc, par); \
+ chSysUnlock(); \
+}
+
+/**
+ * @brief Disables a Virtual Timer.
+ * @note The timer is first checked and disabled only if armed.
+ *
+ * @param[in] vtp the @p VirtualTimer structure pointer
+ *
+ * @api
+ */
+#define chVTReset(vtp) { \
+ chSysLock(); \
+ if (chVTIsArmedI(vtp)) \
+ chVTResetI(vtp); \
+ chSysUnlock(); \
+}
+
+/**
+ * @brief Current system time.
+ * @details Returns the number of system ticks since the @p chSysInit()
+ * invocation.
+ * @note The counter can reach its maximum and then restart from zero.
+ * @note This function is designed to work with the @p chThdSleepUntil().
+ *
+ * @return The system time in ticks.
+ *
+ * @api
+ */
+#define chTimeNow() (vtlist.vt_systime)
+/** @} */
+
+extern VTList vtlist;
+
+/*
+ * Virtual Timers APIs.
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void _vt_init(void);
+ void chVTSetI(VirtualTimer *vtp, systime_t time, vtfunc_t vtfunc, void *par);
+ void chVTResetI(VirtualTimer *vtp);
+ bool_t chTimeIsWithin(systime_t start, systime_t end);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CHVT_H_ */
+
+/** @} */
diff --git a/os/kernel/kernel.dox b/os/kernel/kernel.dox new file mode 100644 index 000000000..05753a8f6 --- /dev/null +++ b/os/kernel/kernel.dox @@ -0,0 +1,173 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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/>.
+*/
+
+/**
+ * @defgroup kernel Kernel
+ * @details The kernel is the portable part of ChibiOS/RT, this section
+ * documents the various kernel subsystems.
+ */
+
+/**
+ * @defgroup kernel_info Version Numbers and Identification
+ * @ingroup kernel
+ */
+
+/**
+ * @defgroup config Configuration
+ * @ingroup kernel
+ */
+
+/**
+ * @defgroup types Types
+ * @details The system types are defined into the port layer, please refer to
+ * the core port implementation section.
+ * @ingroup kernel
+ */
+
+/**
+ * @defgroup base Base Kernel Services
+ * @details Base kernel services, the base subsystems are always included in
+ * the OS builds.
+ * @ingroup kernel
+ */
+
+/**
+ * @defgroup system System Management
+ * @ingroup base
+ */
+
+/**
+ * @defgroup scheduler Scheduler
+ * @ingroup base
+ */
+
+/**
+ * @defgroup threads Threads
+ * @ingroup base
+ */
+
+/**
+ * @defgroup time Time and Virtual Timers
+ * @ingroup base
+ */
+
+/**
+ * @defgroup synchronization Synchronization
+ * @details Synchronization services.
+ * @ingroup kernel
+ */
+
+/**
+ * @defgroup semaphores Counting Semaphores
+ * @ingroup synchronization
+ */
+
+/**
+ * @defgroup binary_semaphores Binary Semaphores
+ * @ingroup synchronization
+ */
+
+/**
+ * @defgroup mutexes Mutexes
+ * @ingroup synchronization
+ */
+
+/**
+ * @defgroup condvars Condition Variables
+ * @ingroup synchronization
+ */
+
+/**
+ * @defgroup events Event Flags
+ * @ingroup synchronization
+ */
+
+/**
+ * @defgroup messages Synchronous Messages
+ * @ingroup synchronization
+ */
+
+/**
+ * @defgroup mailboxes Mailboxes
+ * @ingroup synchronization
+ */
+
+/**
+ * @defgroup io_queues I/O Queues
+ * @ingroup synchronization
+ */
+
+/**
+ * @defgroup memory Memory Management
+ * @details Memory Management services.
+ * @ingroup kernel
+ */
+
+/**
+ * @defgroup memcore Core Memory Manager
+ * @ingroup memory
+ */
+
+/**
+ * @defgroup heaps Heaps
+ * @ingroup memory
+ */
+
+/**
+ * @defgroup pools Memory Pools
+ * @ingroup memory
+ */
+
+/**
+ * @defgroup dynamic_threads Dynamic Threads
+ * @ingroup memory
+ */
+
+ /**
+ * @defgroup streams Streams and Files
+ * @details Stream and Files interfaces.
+ * @ingroup kernel
+ */
+
+/**
+ * @defgroup data_streams Abstract Sequential Streams
+ * @ingroup streams
+ */
+
+/**
+ * @defgroup data_files Abstract File Streams
+ * @ingroup streams
+ */
+
+/**
+ * @defgroup registry Registry
+ * @ingroup kernel
+ */
+
+/**
+ * @defgroup debug Debug
+ * @ingroup kernel
+ */
+
+/**
+ * @defgroup internals Internals
+ * @ingroup kernel
+ */
+
diff --git a/os/kernel/kernel.mk b/os/kernel/kernel.mk new file mode 100644 index 000000000..3ebf2ed98 --- /dev/null +++ b/os/kernel/kernel.mk @@ -0,0 +1,23 @@ +# List of all the ChibiOS/RT kernel files, there is no need to remove the files
+# from this list, you can disable parts of the kernel by editing chconf.h.
+KERNSRC = ${CHIBIOS}/os/kernel/src/chsys.c \
+ ${CHIBIOS}/os/kernel/src/chdebug.c \
+ ${CHIBIOS}/os/kernel/src/chlists.c \
+ ${CHIBIOS}/os/kernel/src/chvt.c \
+ ${CHIBIOS}/os/kernel/src/chschd.c \
+ ${CHIBIOS}/os/kernel/src/chthreads.c \
+ ${CHIBIOS}/os/kernel/src/chdynamic.c \
+ ${CHIBIOS}/os/kernel/src/chregistry.c \
+ ${CHIBIOS}/os/kernel/src/chsem.c \
+ ${CHIBIOS}/os/kernel/src/chmtx.c \
+ ${CHIBIOS}/os/kernel/src/chcond.c \
+ ${CHIBIOS}/os/kernel/src/chevents.c \
+ ${CHIBIOS}/os/kernel/src/chmsg.c \
+ ${CHIBIOS}/os/kernel/src/chmboxes.c \
+ ${CHIBIOS}/os/kernel/src/chqueues.c \
+ ${CHIBIOS}/os/kernel/src/chmemcore.c \
+ ${CHIBIOS}/os/kernel/src/chheap.c \
+ ${CHIBIOS}/os/kernel/src/chmempools.c
+
+# Required include directories
+KERNINC = ${CHIBIOS}/os/kernel/include
diff --git a/os/kernel/src/chcond.c b/os/kernel/src/chcond.c new file mode 100644 index 000000000..c217bf6fd --- /dev/null +++ b/os/kernel/src/chcond.c @@ -0,0 +1,285 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 Leon Woestenberg.
+ */
+
+/**
+ * @file chcond.c
+ * @brief Condition Variables code.
+ *
+ * @addtogroup condvars Condition Variables
+ * @details This module implements the Condition Variables mechanism. Condition
+ * variables are an extensions to the Mutex subsystem and cannot
+ * work alone.
+ * <h2>Operation mode</h2>
+ * The condition variable is a synchronization object meant to be
+ * used inside a zone protected by a @p Mutex. Mutexes and CondVars
+ * together can implement a Monitor construct.
+ * @pre In order to use the condition variable APIs the @p CH_USE_CONDVARS
+ * option must be enabled in @p chconf.h.
+ * @{
+ */
+
+#include "ch.h"
+
+#if (CH_USE_CONDVARS && CH_USE_MUTEXES) || defined(__DOXYGEN__)
+
+/**
+ * @brief Initializes s @p CondVar structure.
+ *
+ * @param[out] cp pointer to a @p CondVar structure
+ *
+ * @init
+ */
+void chCondInit(CondVar *cp) {
+
+ chDbgCheck(cp != NULL, "chCondInit");
+
+ queue_init(&cp->c_queue);
+}
+
+/**
+ * @brief Signals one thread that is waiting on the condition variable.
+ *
+ * @param[in] cp pointer to the @p CondVar structure
+ *
+ * @api
+ */
+void chCondSignal(CondVar *cp) {
+
+ chDbgCheck(cp != NULL, "chCondSignal");
+
+ chSysLock();
+ if (notempty(&cp->c_queue))
+ chSchWakeupS(fifo_remove(&cp->c_queue), RDY_OK);
+ chSysUnlock();
+}
+
+/**
+ * @brief Signals one thread that is waiting on the condition variable.
+ * @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] cp pointer to the @p CondVar structure
+ *
+ * @iclass
+ */
+void chCondSignalI(CondVar *cp) {
+
+ chDbgCheckClassI();
+ chDbgCheck(cp != NULL, "chCondSignalI");
+
+ if (notempty(&cp->c_queue))
+ chSchReadyI(fifo_remove(&cp->c_queue))->p_u.rdymsg = RDY_OK;
+}
+
+/**
+ * @brief Signals all threads that are waiting on the condition variable.
+ *
+ * @param[in] cp pointer to the @p CondVar structure
+ *
+ * @api
+ */
+void chCondBroadcast(CondVar *cp) {
+
+ chSysLock();
+ chCondBroadcastI(cp);
+ chSchRescheduleS();
+ chSysUnlock();
+}
+
+/**
+ * @brief Signals all threads that are waiting on the condition variable.
+ * @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] cp pointer to the @p CondVar structure
+ *
+ * @iclass
+ */
+void chCondBroadcastI(CondVar *cp) {
+
+ chDbgCheckClassI();
+ chDbgCheck(cp != NULL, "chCondBroadcastI");
+
+ /* Empties the condition variable queue and inserts all the Threads into the
+ ready list in FIFO order. The wakeup message is set to @p RDY_RESET in
+ order to make a chCondBroadcast() detectable from a chCondSignal().*/
+ while (cp->c_queue.p_next != (void *)&cp->c_queue)
+ chSchReadyI(fifo_remove(&cp->c_queue))->p_u.rdymsg = RDY_RESET;
+}
+
+/**
+ * @brief Waits on the condition variable releasing the mutex lock.
+ * @details Releases the currently owned mutex, waits on the condition
+ * variable, and finally acquires the mutex again. All the sequence
+ * is performed atomically.
+ * @pre The invoking thread <b>must</b> have at least one owned mutex.
+ *
+ * @param[in] cp pointer to the @p CondVar structure
+ * @return A message specifying how the invoking thread has been
+ * released from the condition variable.
+ * @retval RDY_OK if the condvar has been signaled using
+ * @p chCondSignal().
+ * @retval RDY_RESET if the condvar has been signaled using
+ * @p chCondBroadcast().
+ *
+ * @api
+ */
+msg_t chCondWait(CondVar *cp) {
+ msg_t msg;
+
+ chSysLock();
+ msg = chCondWaitS(cp);
+ chSysUnlock();
+ return msg;
+}
+
+/**
+ * @brief Waits on the condition variable releasing the mutex lock.
+ * @details Releases the currently owned mutex, waits on the condition
+ * variable, and finally acquires the mutex again. All the sequence
+ * is performed atomically.
+ * @pre The invoking thread <b>must</b> have at least one owned mutex.
+ *
+ * @param[in] cp pointer to the @p CondVar structure
+ * @return A message specifying how the invoking thread has been
+ * released from the condition variable.
+ * @retval RDY_OK if the condvar has been signaled using
+ * @p chCondSignal().
+ * @retval RDY_RESET if the condvar has been signaled using
+ * @p chCondBroadcast().
+ *
+ * @sclass
+ */
+msg_t chCondWaitS(CondVar *cp) {
+ Thread *ctp = currp;
+ Mutex *mp;
+ msg_t msg;
+
+ chDbgCheckClassS();
+ chDbgCheck(cp != NULL, "chCondWaitS");
+ chDbgAssert(ctp->p_mtxlist != NULL,
+ "chCondWaitS(), #1",
+ "not owning a mutex");
+
+ mp = chMtxUnlockS();
+ ctp->p_u.wtobjp = cp;
+ prio_insert(ctp, &cp->c_queue);
+ chSchGoSleepS(THD_STATE_WTCOND);
+ msg = ctp->p_u.rdymsg;
+ chMtxLockS(mp);
+ return msg;
+}
+
+#if CH_USE_CONDVARS_TIMEOUT || defined(__DOXYGEN__)
+/**
+ * @brief Waits on the condition variable releasing the mutex lock.
+ * @details Releases the currently owned mutex, waits on the condition
+ * variable, and finally acquires the mutex again. All the sequence
+ * is performed atomically.
+ * @pre The invoking thread <b>must</b> have at least one owned mutex.
+ * @pre The configuration option @p CH_USE_CONDVARS_TIMEOUT must be enabled
+ * in order to use this function.
+ * @post Exiting the function because a timeout does not re-acquire the
+ * mutex, the mutex ownership is lost.
+ *
+ * @param[in] cp pointer to the @p CondVar structure
+ * @param[in] time the number of ticks before the operation timeouts, the
+ * special values are handled as follow:
+ * - @a TIME_INFINITE no timeout.
+ * - @a TIME_IMMEDIATE this value is not allowed.
+ * .
+ * @return A message specifying how the invoking thread has been
+ * released from the condition variable.
+ * @retval RDY_OK if the condvar has been signaled using
+ * @p chCondSignal().
+ * @retval RDY_RESET if the condvar has been signaled using
+ * @p chCondBroadcast().
+ * @retval RDY_TIMEOUT if the condvar has not been signaled within the
+ * specified timeout.
+ *
+ * @api
+ */
+msg_t chCondWaitTimeout(CondVar *cp, systime_t time) {
+ msg_t msg;
+
+ chSysLock();
+ msg = chCondWaitTimeoutS(cp, time);
+ chSysUnlock();
+ return msg;
+}
+
+/**
+ * @brief Waits on the condition variable releasing the mutex lock.
+ * @details Releases the currently owned mutex, waits on the condition
+ * variable, and finally acquires the mutex again. All the sequence
+ * is performed atomically.
+ * @pre The invoking thread <b>must</b> have at least one owned mutex.
+ * @pre The configuration option @p CH_USE_CONDVARS_TIMEOUT must be enabled
+ * in order to use this function.
+ * @post Exiting the function because a timeout does not re-acquire the
+ * mutex, the mutex ownership is lost.
+ *
+ * @param[in] cp pointer to the @p CondVar structure
+ * @param[in] time the number of ticks before the operation timeouts, the
+ * special values are handled as follow:
+ * - @a TIME_INFINITE no timeout.
+ * - @a TIME_IMMEDIATE this value is not allowed.
+ * .
+ * @return A message specifying how the invoking thread has been
+ * released from the condition variable.
+ * @retval RDY_OK if the condvar has been signaled using
+ * @p chCondSignal().
+ * @retval RDY_RESET if the condvar has been signaled using
+ * @p chCondBroadcast().
+ * @retval RDY_TIMEOUT if the condvar has not been signaled within the
+ * specified timeout.
+ *
+ * @sclass
+ */
+msg_t chCondWaitTimeoutS(CondVar *cp, systime_t time) {
+ Mutex *mp;
+ msg_t msg;
+
+ chDbgCheckClassS();
+ chDbgCheck((cp != NULL) && (time != TIME_IMMEDIATE), "chCondWaitTimeoutS");
+ chDbgAssert(currp->p_mtxlist != NULL,
+ "chCondWaitTimeoutS(), #1",
+ "not owning a mutex");
+
+ mp = chMtxUnlockS();
+ currp->p_u.wtobjp = cp;
+ prio_insert(currp, &cp->c_queue);
+ msg = chSchGoSleepTimeoutS(THD_STATE_WTCOND, time);
+ if (msg != RDY_TIMEOUT)
+ chMtxLockS(mp);
+ return msg;
+}
+#endif /* CH_USE_CONDVARS_TIMEOUT */
+
+#endif /* CH_USE_CONDVARS && CH_USE_MUTEXES */
+
+/** @} */
diff --git a/os/kernel/src/chdebug.c b/os/kernel/src/chdebug.c new file mode 100644 index 000000000..c69ce8f3f --- /dev/null +++ b/os/kernel/src/chdebug.c @@ -0,0 +1,271 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 chdebug.c
+ * @brief ChibiOS/RT Debug code.
+ *
+ * @addtogroup debug
+ * @details Debug APIs and services:
+ * - Runtime system state and call protocol check. The following
+ * panic messages can be generated:
+ * - SV#1, misplaced @p chSysDisable().
+ * - SV#2, misplaced @p chSysSuspend()
+ * - SV#3, misplaced @p chSysEnable().
+ * - SV#4, misplaced @p chSysLock().
+ * - SV#5, misplaced @p chSysUnlock().
+ * - SV#6, misplaced @p chSysLockFromIsr().
+ * - SV#7, misplaced @p chSysUnlockFromIsr().
+ * - SV#8, misplaced @p CH_IRQ_PROLOGUE().
+ * - SV#9, misplaced @p CH_IRQ_EPILOGUE().
+ * - SV#10, misplaced I-class function.
+ * - SV#11, misplaced S-class function.
+ * .
+ * - Trace buffer.
+ * - Parameters check.
+ * - Kernel assertions.
+ * - Kernel panics.
+ * .
+ * @note Stack checks are not implemented in this module but in the port
+ * layer in an architecture-dependent way.
+ * @{
+ */
+
+#include "ch.h"
+
+/*===========================================================================*/
+/* System state checker related code and variables. */
+/*===========================================================================*/
+
+#if CH_DBG_SYSTEM_STATE_CHECK || defined(__DOXYGEN__)
+
+/**
+ * @brief ISR nesting level.
+ */
+cnt_t dbg_isr_cnt;
+
+/**
+ * @brief Lock nesting level.
+ */
+cnt_t dbg_lock_cnt;
+
+/**
+ * @brief Guard code for @p chSysDisable().
+ *
+ * @notapi
+ */
+void dbg_check_disable(void) {
+
+ if ((dbg_isr_cnt != 0) || (dbg_lock_cnt != 0))
+ chDbgPanic("SV#1");
+}
+
+/**
+ * @brief Guard code for @p chSysSuspend().
+ *
+ * @notapi
+ */
+void dbg_check_suspend(void) {
+
+ if ((dbg_isr_cnt != 0) || (dbg_lock_cnt != 0))
+ chDbgPanic("SV#2");
+}
+
+/**
+ * @brief Guard code for @p chSysEnable().
+ *
+ * @notapi
+ */
+void dbg_check_enable(void) {
+
+ if ((dbg_isr_cnt != 0) || (dbg_lock_cnt != 0))
+ chDbgPanic("SV#3");
+}
+
+/**
+ * @brief Guard code for @p chSysLock().
+ *
+ * @notapi
+ */
+void dbg_check_lock(void) {
+
+ if ((dbg_isr_cnt != 0) || (dbg_lock_cnt != 0))
+ chDbgPanic("SV#4");
+ dbg_enter_lock();
+}
+
+/**
+ * @brief Guard code for @p chSysUnlock().
+ *
+ * @notapi
+ */
+void dbg_check_unlock(void) {
+
+ if ((dbg_isr_cnt != 0) || (dbg_lock_cnt <= 0))
+ chDbgPanic("SV#5");
+ dbg_leave_lock();
+}
+
+/**
+ * @brief Guard code for @p chSysLockFromIsr().
+ *
+ * @notapi
+ */
+void dbg_check_lock_from_isr(void) {
+
+ if ((dbg_isr_cnt <= 0) || (dbg_lock_cnt != 0))
+ chDbgPanic("SV#6");
+ dbg_enter_lock();
+}
+
+/**
+ * @brief Guard code for @p chSysUnlockFromIsr().
+ *
+ * @notapi
+ */
+void dbg_check_unlock_from_isr(void) {
+
+ if ((dbg_isr_cnt <= 0) || (dbg_lock_cnt <= 0))
+ chDbgPanic("SV#7");
+ dbg_leave_lock();
+}
+
+/**
+ * @brief Guard code for @p CH_IRQ_PROLOGUE().
+ *
+ * @notapi
+ */
+void dbg_check_enter_isr(void) {
+
+ port_lock_from_isr();
+ if ((dbg_isr_cnt < 0) || (dbg_lock_cnt != 0))
+ chDbgPanic("SV#8");
+ dbg_isr_cnt++;
+ port_unlock_from_isr();
+}
+
+/**
+ * @brief Guard code for @p CH_IRQ_EPILOGUE().
+ *
+ * @notapi
+ */
+void dbg_check_leave_isr(void) {
+
+ port_lock_from_isr();
+ if ((dbg_isr_cnt <= 0) || (dbg_lock_cnt != 0))
+ chDbgPanic("SV#9");
+ dbg_isr_cnt--;
+ port_unlock_from_isr();
+}
+
+/**
+ * @brief I-class functions context check.
+ * @details Verifies that the system is in an appropriate state for invoking
+ * an I-class API function. A panic is generated if the state is
+ * not compatible.
+ *
+ * @api
+ */
+void chDbgCheckClassI(void) {
+
+ if ((dbg_isr_cnt < 0) || (dbg_lock_cnt <= 0))
+ chDbgPanic("SV#10");
+}
+
+/**
+ * @brief S-class functions context check.
+ * @details Verifies that the system is in an appropriate state for invoking
+ * an S-class API function. A panic is generated if the state is
+ * not compatible.
+ *
+ * @api
+ */
+void chDbgCheckClassS(void) {
+
+ if ((dbg_isr_cnt != 0) || (dbg_lock_cnt <= 0))
+ chDbgPanic("SV#11");
+}
+
+#endif /* CH_DBG_SYSTEM_STATE_CHECK */
+
+/*===========================================================================*/
+/* Trace related code and variables. */
+/*===========================================================================*/
+
+#if CH_DBG_ENABLE_TRACE || defined(__DOXYGEN__)
+/**
+ * @brief Public trace buffer.
+ */
+ch_trace_buffer_t dbg_trace_buffer;
+
+/**
+ * @brief Trace circular buffer subsystem initialization.
+ * @note Internal use only.
+ */
+void _trace_init(void) {
+
+ dbg_trace_buffer.tb_size = CH_TRACE_BUFFER_SIZE;
+ dbg_trace_buffer.tb_ptr = &dbg_trace_buffer.tb_buffer[0];
+}
+
+/**
+ * @brief Inserts in the circular debug trace buffer a context switch record.
+ *
+ * @param[in] otp the thread being switched out
+ *
+ * @notapi
+ */
+void dbg_trace(Thread *otp) {
+
+ dbg_trace_buffer.tb_ptr->se_time = chTimeNow();
+ dbg_trace_buffer.tb_ptr->se_tp = currp;
+ dbg_trace_buffer.tb_ptr->se_wtobjp = otp->p_u.wtobjp;
+ dbg_trace_buffer.tb_ptr->se_state = (uint8_t)otp->p_state;
+ if (++dbg_trace_buffer.tb_ptr >=
+ &dbg_trace_buffer.tb_buffer[CH_TRACE_BUFFER_SIZE])
+ dbg_trace_buffer.tb_ptr = &dbg_trace_buffer.tb_buffer[0];
+}
+#endif /* CH_DBG_ENABLE_TRACE */
+
+/*===========================================================================*/
+/* Panic related code and variables. */
+/*===========================================================================*/
+
+#if CH_DBG_ENABLED || defined(__DOXYGEN__)
+/**
+ * @brief Pointer to the panic message.
+ * @details This pointer is meant to be accessed through the debugger, it is
+ * written once and then the system is halted.
+ */
+const char *dbg_panic_msg;
+
+/**
+ * @brief Prints a panic message on the console and then halts the system.
+ *
+ * @param[in] msg the pointer to the panic message string
+ */
+void chDbgPanic(const char *msg) {
+
+ dbg_panic_msg = msg;
+ chSysHalt();
+}
+#endif /* CH_DBG_ENABLED */
+
+/** @} */
diff --git a/os/kernel/src/chdynamic.c b/os/kernel/src/chdynamic.c new file mode 100644 index 000000000..632367ca1 --- /dev/null +++ b/os/kernel/src/chdynamic.c @@ -0,0 +1,204 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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_USE_DYNAMIC || defined(__DOXYGEN__)
+
+/**
+ * @brief Adds a reference to a thread object.
+ * @pre The configuration option @p CH_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 *chThdAddRef(Thread *tp) {
+
+ chSysLock();
+ chDbgAssert(tp->p_refs < 255, "chThdAddRef(), #1", "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 THD_STATE_FINAL state then the thread's memory is
+ * returned to the proper allocator.
+ * @pre The configuration option @p CH_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 *tp) {
+ trefs_t refs;
+
+ chSysLock();
+ chDbgAssert(tp->p_refs > 0, "chThdRelease(), #1", "not referenced");
+ refs = --tp->p_refs;
+ chSysUnlock();
+
+ /* If the references counter reaches zero 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 == 0) && (tp->p_state == THD_STATE_FINAL)) {
+ switch (tp->p_flags & THD_MEM_MODE_MASK) {
+#if CH_USE_HEAP
+ case THD_MEM_MODE_HEAP:
+#if CH_USE_REGISTRY
+ REG_REMOVE(tp);
+#endif
+ chHeapFree(tp);
+ break;
+#endif
+#if CH_USE_MEMPOOLS
+ case THD_MEM_MODE_MEMPOOL:
+#if CH_USE_REGISTRY
+ REG_REMOVE(tp);
+#endif
+ chPoolFree(tp->p_mpool, tp);
+ break;
+#endif
+ }
+ }
+}
+
+#if CH_USE_HEAP || defined(__DOXYGEN__)
+/**
+ * @brief Creates a new thread allocating the memory from the heap.
+ * @pre The configuration options @p CH_USE_DYNAMIC and @p CH_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 structure allocated for
+ * the thread into the working space area.
+ * @retval NULL if the memory cannot be allocated.
+ *
+ * @api
+ */
+Thread *chThdCreateFromHeap(MemoryHeap *heapp, size_t size,
+ tprio_t prio, tfunc_t pf, void *arg) {
+ void *wsp;
+ Thread *tp;
+
+ wsp = chHeapAlloc(heapp, size);
+ if (wsp == NULL)
+ return NULL;
+
+#if CH_DBG_FILL_THREADS
+ _thread_memfill((uint8_t *)wsp,
+ (uint8_t *)wsp + sizeof(Thread),
+ CH_THREAD_FILL_VALUE);
+ _thread_memfill((uint8_t *)wsp + sizeof(Thread),
+ (uint8_t *)wsp + size,
+ CH_STACK_FILL_VALUE);
+#endif
+
+ chSysLock();
+ tp = chThdCreateI(wsp, size, prio, pf, arg);
+ tp->p_flags = THD_MEM_MODE_HEAP;
+ chSchWakeupS(tp, RDY_OK);
+ chSysUnlock();
+ return tp;
+}
+#endif /* CH_USE_HEAP */
+
+#if CH_USE_MEMPOOLS || defined(__DOXYGEN__)
+/**
+ * @brief Creates a new thread allocating the memory from the specified
+ * memory pool.
+ * @pre The configuration options @p CH_USE_DYNAMIC and @p CH_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 structure allocated for
+ * the thread into the working space area.
+ * @retval NULL if the memory pool is empty.
+ *
+ * @api
+ */
+Thread *chThdCreateFromMemoryPool(MemoryPool *mp, tprio_t prio,
+ tfunc_t pf, void *arg) {
+ void *wsp;
+ Thread *tp;
+
+ chDbgCheck(mp != NULL, "chThdCreateFromMemoryPool");
+
+ wsp = chPoolAlloc(mp);
+ if (wsp == NULL)
+ return NULL;
+
+#if CH_DBG_FILL_THREADS
+ _thread_memfill((uint8_t *)wsp,
+ (uint8_t *)wsp + sizeof(Thread),
+ CH_THREAD_FILL_VALUE);
+ _thread_memfill((uint8_t *)wsp + sizeof(Thread),
+ (uint8_t *)wsp + mp->mp_object_size,
+ CH_STACK_FILL_VALUE);
+#endif
+
+ chSysLock();
+ tp = chThdCreateI(wsp, mp->mp_object_size, prio, pf, arg);
+ tp->p_flags = THD_MEM_MODE_MEMPOOL;
+ tp->p_mpool = mp;
+ chSchWakeupS(tp, RDY_OK);
+ chSysUnlock();
+ return tp;
+}
+#endif /* CH_USE_MEMPOOLS */
+
+#endif /* CH_USE_DYNAMIC */
+
+/** @} */
diff --git a/os/kernel/src/chevents.c b/os/kernel/src/chevents.c new file mode 100644 index 000000000..1a2285779 --- /dev/null +++ b/os/kernel/src/chevents.c @@ -0,0 +1,548 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 Scott (skute).
+ */
+
+/**
+ * @file chevents.c
+ * @brief Events code.
+ *
+ * @addtogroup events
+ * @details Event Flags, Event Sources and Event Listeners.
+ * <h2>Operation mode</h2>
+ * Each thread has a mask of pending event flags inside its @p Thread
+ * structure.
+ * Operations defined for event flags:
+ * - <b>Wait</b>, the invoking thread goes to sleep until a certain
+ * AND/OR combination of event flags becomes pending.
+ * - <b>Clear</b>, a mask of event flags is cleared from the pending
+ * events mask, the cleared event flags mask is returned (only the
+ * flags that were actually pending and then cleared).
+ * - <b>Signal</b>, an event mask is directly ORed to the mask of the
+ * signaled thread.
+ * - <b>Broadcast</b>, each thread registered on an Event Source is
+ * signaled with the event flags specified in its Event Listener.
+ * - <b>Dispatch</b>, an events mask is scanned and for each bit set
+ * to one an associated handler function is invoked. Bit masks are
+ * scanned from bit zero upward.
+ * .
+ * An Event Source is a special object that can be "broadcasted" by
+ * a thread or an interrupt service routine. Broadcasting an Event
+ * Source has the effect that all the threads registered on the
+ * Event Source will be signaled with an events mask.<br>
+ * An unlimited number of Event Sources can exists in a system and
+ * each thread can be listening on an unlimited number of
+ * them.
+ * @pre In order to use the Events APIs the @p CH_USE_EVENTS option must be
+ * enabled in @p chconf.h.
+ * @post Enabling events requires 1-4 (depending on the architecture)
+ * extra bytes in the @p Thread structure.
+ * @{
+ */
+
+#include "ch.h"
+
+#if CH_USE_EVENTS || defined(__DOXYGEN__)
+/**
+ * @brief Registers an Event Listener on an Event Source.
+ * @details Once a thread has registered as listener on an event source it
+ * will be notified of all events broadcasted there.
+ * @note Multiple Event Listeners can specify the same bits to be ORed to
+ * different threads.
+ *
+ * @param[in] esp pointer to the @p EventSource structure
+ * @param[in] elp pointer to the @p EventListener structure
+ * @param[in] mask the mask of event flags to be ORed to the thread when
+ * the event source is broadcasted
+ *
+ * @api
+ */
+void chEvtRegisterMask(EventSource *esp, EventListener *elp, eventmask_t mask) {
+
+ chDbgCheck((esp != NULL) && (elp != NULL), "chEvtRegisterMask");
+
+ chSysLock();
+ elp->el_next = esp->es_next;
+ esp->es_next = elp;
+ elp->el_listener = currp;
+ elp->el_mask = mask;
+ elp->el_flags = 0;
+ chSysUnlock();
+}
+
+/**
+ * @brief Unregisters an Event Listener from its Event Source.
+ * @note If the event listener is not registered on the specified event
+ * source then the function does nothing.
+ * @note For optimal performance it is better to perform the unregister
+ * operations in inverse order of the register operations (elements
+ * are found on top of the list).
+ *
+ * @param[in] esp pointer to the @p EventSource structure
+ * @param[in] elp pointer to the @p EventListener structure
+ *
+ * @api
+ */
+void chEvtUnregister(EventSource *esp, EventListener *elp) {
+ EventListener *p;
+
+ chDbgCheck((esp != NULL) && (elp != NULL), "chEvtUnregister");
+
+ p = (EventListener *)esp;
+ chSysLock();
+ while (p->el_next != (EventListener *)esp) {
+ if (p->el_next == elp) {
+ p->el_next = elp->el_next;
+ break;
+ }
+ p = p->el_next;
+ }
+ chSysUnlock();
+}
+
+/**
+ * @brief Clears the pending events specified in the mask.
+ *
+ * @param[in] mask the events to be cleared
+ * @return The pending events that were cleared.
+ *
+ * @api
+ */
+eventmask_t chEvtGetAndClearEvents(eventmask_t mask) {
+ eventmask_t m;
+
+ chSysLock();
+
+ m = currp->p_epending & mask;
+ currp->p_epending &= ~mask;
+
+ chSysUnlock();
+ return m;
+}
+
+/**
+ * @brief Adds (OR) a set of event flags on the current thread, this is
+ * @b much faster than using @p chEvtBroadcast() or @p chEvtSignal().
+ *
+ * @param[in] mask the event flags to be added
+ * @return The current pending events mask.
+ *
+ * @api
+ */
+eventmask_t chEvtAddEvents(eventmask_t mask) {
+
+ chSysLock();
+
+ mask = (currp->p_epending |= mask);
+
+ chSysUnlock();
+ return mask;
+}
+
+/**
+ * @brief Signals all the Event Listeners registered on the specified Event
+ * Source.
+ * @details This function variants ORs the specified event flags to all the
+ * threads registered on the @p EventSource in addition to the event
+ * flags specified by the threads themselves in the
+ * @p EventListener objects.
+ * @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] esp pointer to the @p EventSource structure
+ * @param[in] flags the flags set to be added to the listener flags mask
+ *
+ * @iclass
+ */
+void chEvtBroadcastFlagsI(EventSource *esp, flagsmask_t flags) {
+ EventListener *elp;
+
+ chDbgCheckClassI();
+ chDbgCheck(esp != NULL, "chEvtBroadcastMaskI");
+
+ elp = esp->es_next;
+ while (elp != (EventListener *)esp) {
+ elp->el_flags |= flags;
+ chEvtSignalI(elp->el_listener, elp->el_mask);
+ elp = elp->el_next;
+ }
+}
+
+/**
+ * @brief Returns the flags associated to an @p EventListener.
+ * @details The flags are returned and the @p EventListener flags mask is
+ * cleared.
+ *
+ * @param[in] elp pointer to the @p EventListener structure
+ * @return The flags added to the listener by the associated
+ * event source.
+ *
+ * @iclass
+ */
+flagsmask_t chEvtGetAndClearFlags(EventListener *elp) {
+ flagsmask_t flags;
+
+ chSysLock();
+
+ flags = elp->el_flags;
+ elp->el_flags = 0;
+
+ chSysUnlock();
+ return flags;
+}
+
+/**
+ * @brief Adds a set of event flags directly to specified @p Thread.
+ *
+ * @param[in] tp the thread to be signaled
+ * @param[in] mask the event flags set to be ORed
+ *
+ * @api
+ */
+void chEvtSignal(Thread *tp, eventmask_t mask) {
+
+ chDbgCheck(tp != NULL, "chEvtSignal");
+
+ chSysLock();
+ chEvtSignalI(tp, mask);
+ chSchRescheduleS();
+ chSysUnlock();
+}
+
+/**
+ * @brief Adds a set of event flags directly to specified @p Thread.
+ * @post This function does not reschedule so a call to a rescheduling
+ * function must be performed before unlocking the kernel. Note that
+ * interrupt handlers always reschedule on exit so an explicit
+ * reschedule must not be performed in ISRs.
+ *
+ * @param[in] tp the thread to be signaled
+ * @param[in] mask the event flags set to be ORed
+ *
+ * @iclass
+ */
+void chEvtSignalI(Thread *tp, eventmask_t mask) {
+
+ chDbgCheckClassI();
+ chDbgCheck(tp != NULL, "chEvtSignalI");
+
+ tp->p_epending |= mask;
+ /* Test on the AND/OR conditions wait states.*/
+ if (((tp->p_state == THD_STATE_WTOREVT) &&
+ ((tp->p_epending & tp->p_u.ewmask) != 0)) ||
+ ((tp->p_state == THD_STATE_WTANDEVT) &&
+ ((tp->p_epending & tp->p_u.ewmask) == tp->p_u.ewmask)))
+ chSchReadyI(tp)->p_u.rdymsg = RDY_OK;
+}
+
+/**
+ * @brief Signals all the Event Listeners registered on the specified Event
+ * Source.
+ * @details This function variants ORs the specified event flags to all the
+ * threads registered on the @p EventSource in addition to the event
+ * flags specified by the threads themselves in the
+ * @p EventListener objects.
+ *
+ * @param[in] esp pointer to the @p EventSource structure
+ * @param[in] flags the flags set to be added to the listener flags mask
+ *
+ * @api
+ */
+void chEvtBroadcastFlags(EventSource *esp, flagsmask_t flags) {
+
+ chSysLock();
+ chEvtBroadcastFlagsI(esp, flags);
+ chSchRescheduleS();
+ chSysUnlock();
+}
+
+/**
+ * @brief Returns the flags associated to an @p EventListener.
+ * @details The flags are returned and the @p EventListener flags mask is
+ * cleared.
+ *
+ * @param[in] elp pointer to the @p EventListener structure
+ * @return The flags added to the listener by the associated
+ * event source.
+ *
+ * @iclass
+ */
+flagsmask_t chEvtGetAndClearFlagsI(EventListener *elp) {
+ flagsmask_t flags;
+
+ flags = elp->el_flags;
+ elp->el_flags = 0;
+
+ return flags;
+}
+
+/**
+ * @brief Invokes the event handlers associated to an event flags mask.
+ *
+ * @param[in] mask mask of the event flags to be dispatched
+ * @param[in] handlers an array of @p evhandler_t. The array must have size
+ * equal to the number of bits in eventmask_t.
+ *
+ * @api
+ */
+void chEvtDispatch(const evhandler_t *handlers, eventmask_t mask) {
+ eventid_t eid;
+
+ chDbgCheck(handlers != NULL, "chEvtDispatch");
+
+ eid = 0;
+ while (mask) {
+ if (mask & EVENT_MASK(eid)) {
+ chDbgAssert(handlers[eid] != NULL,
+ "chEvtDispatch(), #1",
+ "null handler");
+ mask &= ~EVENT_MASK(eid);
+ handlers[eid](eid);
+ }
+ eid++;
+ }
+}
+
+#if CH_OPTIMIZE_SPEED || !CH_USE_EVENTS_TIMEOUT || defined(__DOXYGEN__)
+/**
+ * @brief Waits for exactly one of the specified events.
+ * @details The function waits for one event among those specified in
+ * @p mask to become pending then the event is cleared and returned.
+ * @note One and only one event is served in the function, the one with the
+ * lowest event id. The function is meant to be invoked into a loop in
+ * order to serve all the pending events.<br>
+ * This means that Event Listeners with a lower event identifier have
+ * an higher priority.
+ *
+ * @param[in] mask mask of the event flags that the function should wait
+ * for, @p ALL_EVENTS enables all the events
+ * @return The mask of the lowest id served and cleared event.
+ *
+ * @api
+ */
+eventmask_t chEvtWaitOne(eventmask_t mask) {
+ Thread *ctp = currp;
+ eventmask_t m;
+
+ chSysLock();
+
+ if ((m = (ctp->p_epending & mask)) == 0) {
+ ctp->p_u.ewmask = mask;
+ chSchGoSleepS(THD_STATE_WTOREVT);
+ m = ctp->p_epending & mask;
+ }
+ m &= -m;
+ ctp->p_epending &= ~m;
+
+ 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
+ * @return The mask of the served and cleared events.
+ *
+ * @api
+ */
+eventmask_t chEvtWaitAny(eventmask_t mask) {
+ Thread *ctp = currp;
+ eventmask_t m;
+
+ chSysLock();
+
+ if ((m = (ctp->p_epending & mask)) == 0) {
+ ctp->p_u.ewmask = mask;
+ chSchGoSleepS(THD_STATE_WTOREVT);
+ m = ctp->p_epending & mask;
+ }
+ ctp->p_epending &= ~m;
+
+ chSysUnlock();
+ return m;
+}
+
+/**
+ * @brief Waits for all the specified events.
+ * @details The function waits for all the events specified in @p mask to
+ * become pending then the events are cleared and returned.
+ *
+ * @param[in] mask mask of the event flags that the function should wait
+ * for, @p ALL_EVENTS requires all the events
+ * @return The mask of the served and cleared events.
+ *
+ * @api
+ */
+eventmask_t chEvtWaitAll(eventmask_t mask) {
+ Thread *ctp = currp;
+
+ chSysLock();
+
+ if ((ctp->p_epending & mask) != mask) {
+ ctp->p_u.ewmask = mask;
+ chSchGoSleepS(THD_STATE_WTANDEVT);
+ }
+ ctp->p_epending &= ~mask;
+
+ chSysUnlock();
+ return mask;
+}
+#endif /* CH_OPTIMIZE_SPEED || !CH_USE_EVENTS_TIMEOUT */
+
+#if CH_USE_EVENTS_TIMEOUT || defined(__DOXYGEN__)
+/**
+ * @brief Waits for exactly one of the specified events.
+ * @details The function waits for one event among those specified in
+ * @p mask to become pending then the event is cleared and returned.
+ * @note One and only one event is served in the function, the one with the
+ * lowest event id. The function is meant to be invoked into a loop in
+ * order to serve all the pending events.<br>
+ * This means that Event Listeners with a lower event identifier have
+ * an higher priority.
+ *
+ * @param[in] mask mask of the event flags that the function should wait
+ * for, @p ALL_EVENTS enables all the events
+ * @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 The mask of the lowest id served and cleared event.
+ * @retval 0 if the operation has timed out.
+ *
+ * @api
+ */
+eventmask_t chEvtWaitOneTimeout(eventmask_t mask, systime_t time) {
+ Thread *ctp = currp;
+ eventmask_t m;
+
+ chSysLock();
+
+ if ((m = (ctp->p_epending & mask)) == 0) {
+ if (TIME_IMMEDIATE == time) {
+ chSysUnlock();
+ return (eventmask_t)0;
+ }
+ ctp->p_u.ewmask = mask;
+ if (chSchGoSleepTimeoutS(THD_STATE_WTOREVT, time) < RDY_OK) {
+ chSysUnlock();
+ return (eventmask_t)0;
+ }
+ m = ctp->p_epending & mask;
+ }
+ m &= -m;
+ ctp->p_epending &= ~m;
+
+ 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] 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 The mask of the served and cleared events.
+ * @retval 0 if the operation has timed out.
+ *
+ * @api
+ */
+eventmask_t chEvtWaitAnyTimeout(eventmask_t mask, systime_t time) {
+ Thread *ctp = currp;
+ eventmask_t m;
+
+ chSysLock();
+
+ if ((m = (ctp->p_epending & mask)) == 0) {
+ if (TIME_IMMEDIATE == time) {
+ chSysUnlock();
+ return (eventmask_t)0;
+ }
+ ctp->p_u.ewmask = mask;
+ if (chSchGoSleepTimeoutS(THD_STATE_WTOREVT, time) < RDY_OK) {
+ chSysUnlock();
+ return (eventmask_t)0;
+ }
+ m = ctp->p_epending & mask;
+ }
+ ctp->p_epending &= ~m;
+
+ chSysUnlock();
+ return m;
+}
+
+/**
+ * @brief Waits for all the specified events.
+ * @details The function waits for all the events specified in @p mask to
+ * become pending then the events are cleared and returned.
+ *
+ * @param[in] mask mask of the event flags that the function should wait
+ * for, @p ALL_EVENTS requires all the events
+ * @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 The mask of the served and cleared events.
+ * @retval 0 if the operation has timed out.
+ *
+ * @api
+ */
+eventmask_t chEvtWaitAllTimeout(eventmask_t mask, systime_t time) {
+ Thread *ctp = currp;
+
+ chSysLock();
+
+ if ((ctp->p_epending & mask) != mask) {
+ if (TIME_IMMEDIATE == time) {
+ chSysUnlock();
+ return (eventmask_t)0;
+ }
+ ctp->p_u.ewmask = mask;
+ if (chSchGoSleepTimeoutS(THD_STATE_WTANDEVT, time) < RDY_OK) {
+ chSysUnlock();
+ return (eventmask_t)0;
+ }
+ }
+ ctp->p_epending &= ~mask;
+
+ chSysUnlock();
+ return mask;
+}
+#endif /* CH_USE_EVENTS_TIMEOUT */
+
+#endif /* CH_USE_EVENTS */
+
+/** @} */
diff --git a/os/kernel/src/chheap.c b/os/kernel/src/chheap.c new file mode 100644 index 000000000..23bcff6b4 --- /dev/null +++ b/os/kernel/src/chheap.c @@ -0,0 +1,318 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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>
+ * By enabling the @p CH_USE_MALLOC_HEAP option the heap manager
+ * will use the runtime-provided @p malloc() and @p free() as
+ * back end for the heap APIs instead of the system provided
+ * allocator.
+ * @pre In order to use the heap APIs the @p CH_USE_HEAP option must
+ * be enabled in @p chconf.h.
+ * @{
+ */
+
+#include "ch.h"
+
+#if CH_USE_HEAP || defined(__DOXYGEN__)
+
+#if !CH_USE_MALLOC_HEAP || defined(__DOXYGEN__)
+
+/*
+ * Defaults on the best synchronization mechanism available.
+ */
+#if CH_USE_MUTEXES || defined(__DOXYGEN__)
+#define H_LOCK(h) chMtxLock(&(h)->h_mtx)
+#define H_UNLOCK(h) chMtxUnlock()
+#else
+#define H_LOCK(h) chSemWait(&(h)->h_sem)
+#define H_UNLOCK(h) chSemSignal(&(h)->h_sem)
+#endif
+
+/**
+ * @brief Default heap descriptor.
+ */
+static MemoryHeap default_heap;
+
+/**
+ * @brief Initializes the default heap.
+ *
+ * @notapi
+ */
+void _heap_init(void) {
+ default_heap.h_provider = chCoreAlloc;
+ default_heap.h_free.h.u.next = (union heap_header *)NULL;
+ default_heap.h_free.h.size = 0;
+#if CH_USE_MUTEXES || defined(__DOXYGEN__)
+ chMtxInit(&default_heap.h_mtx);
+#else
+ chSemInit(&default_heap.h_sem, 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.
+ * @pre In order to use this function the option @p CH_USE_MALLOC_HEAP
+ * must be disabled.
+ *
+ * @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 chHeapInit(MemoryHeap *heapp, void *buf, size_t size) {
+ union heap_header *hp;
+
+ chDbgCheck(MEM_IS_ALIGNED(buf) && MEM_IS_ALIGNED(size), "chHeapInit");
+
+ heapp->h_provider = (memgetfunc_t)NULL;
+ heapp->h_free.h.u.next = hp = buf;
+ heapp->h_free.h.size = 0;
+ hp->h.u.next = NULL;
+ hp->h.size = size - sizeof(union heap_header);
+#if CH_USE_MUTEXES || defined(__DOXYGEN__)
+ chMtxInit(&heapp->h_mtx);
+#else
+ chSemInit(&heapp->h_sem, 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(MemoryHeap *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.*/
+ fp = (void *)((uint8_t *)(hp) + sizeof(union heap_header) + size);
+ 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);
+ return (void *)(hp + 1);
+ }
+ qp = hp;
+ }
+
+ H_UNLOCK(heapp);
+
+ /* More memory is required, tries to get it from the associated provider
+ else fails.*/
+ if (heapp->h_provider) {
+ hp = heapp->h_provider(size + sizeof(union heap_header));
+ if (hp != NULL) {
+ hp->h.u.heap = heapp;
+ hp->h.size = size;
+ hp++;
+ return (void *)hp;
+ }
+ }
+ return NULL;
+}
+
+#define LIMIT(p) (union heap_header *)((uint8_t *)(p) + \
+ sizeof(union heap_header) + \
+ (p)->h.size)
+
+/**
+ * @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;
+ MemoryHeap *heapp;
+
+ chDbgCheck(p != NULL, "chHeapFree");
+
+ hp = (union heap_header *)p - 1;
+ heapp = hp->h.u.heap;
+ qp = &heapp->h_free;
+ H_LOCK(heapp);
+
+ while (TRUE) {
+ chDbgAssert((hp < qp) || (hp >= LIMIT(qp)),
+ "chHeapFree(), #1",
+ "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.
+ * @note This function is not implemented when the @p CH_USE_MALLOC_HEAP
+ * configuration option is used (it always returns zero).
+ *
+ * @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(MemoryHeap *heapp, size_t *sizep) {
+ union heap_header *qp;
+ size_t n, sz;
+
+ if (heapp == NULL)
+ heapp = &default_heap;
+
+ H_LOCK(heapp);
+
+ sz = 0;
+ for (n = 0, qp = &heapp->h_free; qp->h.u.next; n++, qp = qp->h.u.next)
+ sz += qp->h.u.next->h.size;
+ if (sizep)
+ *sizep = sz;
+
+ H_UNLOCK(heapp);
+ return n;
+}
+
+#else /* CH_USE_MALLOC_HEAP */
+
+#include <stdlib.h>
+
+#if CH_USE_MUTEXES
+#define H_LOCK() chMtxLock(&hmtx)
+#define H_UNLOCK() chMtxUnlock()
+static Mutex hmtx;
+#elif CH_USE_SEMAPHORES
+#define H_LOCK() chSemWait(&hsem)
+#define H_UNLOCK() chSemSignal(&hsem)
+static Semaphore hsem;
+#endif
+
+void _heap_init(void) {
+
+#if CH_USE_MUTEXES
+ chMtxInit(&hmtx);
+#else
+ chSemInit(&hsem, 1);
+#endif
+}
+
+void *chHeapAlloc(MemoryHeap *heapp, size_t size) {
+ void *p;
+
+ chDbgCheck(heapp == NULL, "chHeapAlloc");
+
+ H_LOCK();
+ p = malloc(size);
+ H_UNLOCK();
+ return p;
+}
+
+void chHeapFree(void *p) {
+
+ chDbgCheck(p != NULL, "chHeapFree");
+
+ H_LOCK();
+ free(p);
+ H_UNLOCK();
+}
+
+size_t chHeapStatus(MemoryHeap *heapp, size_t *sizep) {
+
+ chDbgCheck(heapp == NULL, "chHeapStatus");
+
+ if (sizep)
+ *sizep = 0;
+ return 0;
+}
+
+#endif /* CH_USE_MALLOC_HEAP */
+
+#endif /* CH_USE_HEAP */
+
+/** @} */
diff --git a/os/kernel/src/chlists.c b/os/kernel/src/chlists.c new file mode 100644 index 000000000..8ee309200 --- /dev/null +++ b/os/kernel/src/chlists.c @@ -0,0 +1,156 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 chlists.c
+ * @brief Thread queues/lists code.
+ *
+ * @addtogroup internals
+ * @details All the functions present in this module, while public, are not
+ * OS APIs and should not be directly used in the user applications
+ * code.
+ * @{
+ */
+#include "ch.h"
+
+#if !CH_OPTIMIZE_SPEED || defined(__DOXYGEN__)
+/**
+ * @brief Inserts a thread into a priority ordered queue.
+ * @note The insertion is done by scanning the list from the highest
+ * priority toward the lowest.
+ *
+ * @param[in] tp the pointer to the thread to be inserted in the list
+ * @param[in] tqp the pointer to the threads list header
+ *
+ * @notapi
+ */
+void prio_insert(Thread *tp, ThreadsQueue *tqp) {
+
+ /* cp iterates over the queue.*/
+ Thread *cp = (Thread *)tqp;
+ do {
+ /* Iterate to next thread in queue.*/
+ cp = cp->p_next;
+ /* Not end of queue? and cp has equal or higher priority than tp?.*/
+ } while ((cp != (Thread *)tqp) && (cp->p_prio >= tp->p_prio));
+ /* Insertion on p_prev.*/
+ tp->p_next = cp;
+ tp->p_prev = cp->p_prev;
+ tp->p_prev->p_next = cp->p_prev = tp;
+}
+
+/**
+ * @brief Inserts a Thread into a queue.
+ *
+ * @param[in] tp the pointer to the thread to be inserted in the list
+ * @param[in] tqp the pointer to the threads list header
+ *
+ * @notapi
+ */
+void queue_insert(Thread *tp, ThreadsQueue *tqp) {
+
+ tp->p_next = (Thread *)tqp;
+ tp->p_prev = tqp->p_prev;
+ tp->p_prev->p_next = tqp->p_prev = tp;
+}
+
+/**
+ * @brief Removes the first-out Thread from a queue and returns it.
+ * @note If the queue is priority ordered then this function returns the
+ * thread with the highest priority.
+ *
+ * @param[in] tqp the pointer to the threads list header
+ * @return The removed thread pointer.
+ *
+ * @notapi
+ */
+Thread *fifo_remove(ThreadsQueue *tqp) {
+ Thread *tp = tqp->p_next;
+
+ (tqp->p_next = tp->p_next)->p_prev = (Thread *)tqp;
+ return tp;
+}
+
+/**
+ * @brief Removes the last-out Thread from a queue and returns it.
+ * @note If the queue is priority ordered then this function returns the
+ * thread with the lowest priority.
+ *
+ * @param[in] tqp the pointer to the threads list header
+ * @return The removed thread pointer.
+ *
+ * @notapi
+ */
+Thread *lifo_remove(ThreadsQueue *tqp) {
+ Thread *tp = tqp->p_prev;
+
+ (tqp->p_prev = tp->p_prev)->p_next = (Thread *)tqp;
+ return tp;
+}
+
+/**
+ * @brief Removes a Thread from a queue and returns it.
+ * @details The thread is removed from the queue regardless of its relative
+ * position and regardless the used insertion method.
+ *
+ * @param[in] tp the pointer to the thread to be removed from the queue
+ * @return The removed thread pointer.
+ *
+ * @notapi
+ */
+Thread *dequeue(Thread *tp) {
+
+ tp->p_prev->p_next = tp->p_next;
+ tp->p_next->p_prev = tp->p_prev;
+ return tp;
+}
+
+/**
+ * @brief Pushes a Thread on top of a stack list.
+ *
+ * @param[in] tp the pointer to the thread to be inserted in the list
+ * @param[in] tlp the pointer to the threads list header
+ *
+ * @notapi
+ */
+void list_insert(Thread *tp, ThreadsList *tlp) {
+
+ tp->p_next = tlp->p_next;
+ tlp->p_next = tp;
+}
+
+/**
+ * @brief Pops a Thread from the top of a stack list and returns it.
+ * @pre The list must be non-empty before calling this function.
+ *
+ * @param[in] tlp the pointer to the threads list header
+ * @return The removed thread pointer.
+ *
+ * @notapi
+ */
+Thread *list_remove(ThreadsList *tlp) {
+
+ Thread *tp = tlp->p_next;
+ tlp->p_next = tp->p_next;
+ return tp;
+}
+#endif /* CH_OPTIMIZE_SPEED */
+
+/** @} */
diff --git a/os/kernel/src/chmboxes.c b/os/kernel/src/chmboxes.c new file mode 100644 index 000000000..6f09a8d26 --- /dev/null +++ b/os/kernel/src/chmboxes.c @@ -0,0 +1,376 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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_USE_MAILBOXES option
+ * must be enabled in @p chconf.h.
+ * @{
+ */
+
+#include "ch.h"
+
+#if CH_USE_MAILBOXES || defined(__DOXYGEN__)
+/**
+ * @brief Initializes a Mailbox object.
+ *
+ * @param[out] mbp the pointer to the Mailbox 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 chMBInit(Mailbox *mbp, msg_t *buf, cnt_t n) {
+
+ chDbgCheck((mbp != NULL) && (buf != NULL) && (n > 0), "chMBInit");
+
+ mbp->mb_buffer = mbp->mb_wrptr = mbp->mb_rdptr = buf;
+ mbp->mb_top = &buf[n];
+ chSemInit(&mbp->mb_emptysem, n);
+ chSemInit(&mbp->mb_fullsem, 0);
+}
+
+/**
+ * @brief Resets a Mailbox object.
+ * @details All the waiting threads are resumed with status @p RDY_RESET and
+ * the queued messages are lost.
+ *
+ * @param[in] mbp the pointer to an initialized Mailbox object
+ *
+ * @api
+ */
+void chMBReset(Mailbox *mbp) {
+
+ chDbgCheck(mbp != NULL, "chMBReset");
+
+ chSysLock();
+ mbp->mb_wrptr = mbp->mb_rdptr = mbp->mb_buffer;
+ chSemResetI(&mbp->mb_emptysem, mbp->mb_top - mbp->mb_buffer);
+ chSemResetI(&mbp->mb_fullsem, 0);
+ chSchRescheduleS();
+ chSysUnlock();
+}
+
+/**
+ * @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 Mailbox object
+ * @param[in] msg the message to be posted on the mailbox
+ * @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 The operation status.
+ * @retval RDY_OK if a message has been correctly posted.
+ * @retval RDY_RESET if the mailbox has been reset while waiting.
+ * @retval RDY_TIMEOUT if the operation has timed out.
+ *
+ * @api
+ */
+msg_t chMBPost(Mailbox *mbp, msg_t msg, systime_t time) {
+ msg_t rdymsg;
+
+ chSysLock();
+ rdymsg = chMBPostS(mbp, msg, time);
+ 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 Mailbox object
+ * @param[in] msg the message to be posted on the mailbox
+ * @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 The operation status.
+ * @retval RDY_OK if a message has been correctly posted.
+ * @retval RDY_RESET if the mailbox has been reset while waiting.
+ * @retval RDY_TIMEOUT if the operation has timed out.
+ *
+ * @sclass
+ */
+msg_t chMBPostS(Mailbox *mbp, msg_t msg, systime_t time) {
+ msg_t rdymsg;
+
+ chDbgCheckClassS();
+ chDbgCheck(mbp != NULL, "chMBPostS");
+
+ rdymsg = chSemWaitTimeoutS(&mbp->mb_emptysem, time);
+ if (rdymsg == RDY_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 Mailbox object
+ * @param[in] msg the message to be posted on the mailbox
+ * @return The operation status.
+ * @retval RDY_OK if a message has been correctly posted.
+ * @retval RDY_TIMEOUT if the mailbox is full and the message cannot be
+ * posted.
+ *
+ * @iclass
+ */
+msg_t chMBPostI(Mailbox *mbp, msg_t msg) {
+
+ chDbgCheckClassI();
+ chDbgCheck(mbp != NULL, "chMBPostI");
+
+ if (chSemGetCounterI(&mbp->mb_emptysem) <= 0)
+ return RDY_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 RDY_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 Mailbox object
+ * @param[in] msg the message to be posted on the mailbox
+ * @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 The operation status.
+ * @retval RDY_OK if a message has been correctly posted.
+ * @retval RDY_RESET if the mailbox has been reset while waiting.
+ * @retval RDY_TIMEOUT if the operation has timed out.
+ *
+ * @api
+ */
+msg_t chMBPostAhead(Mailbox *mbp, msg_t msg, systime_t time) {
+ msg_t rdymsg;
+
+ chSysLock();
+ rdymsg = chMBPostAheadS(mbp, msg, time);
+ 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 Mailbox object
+ * @param[in] msg the message to be posted on the mailbox
+ * @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 The operation status.
+ * @retval RDY_OK if a message has been correctly posted.
+ * @retval RDY_RESET if the mailbox has been reset while waiting.
+ * @retval RDY_TIMEOUT if the operation has timed out.
+ *
+ * @sclass
+ */
+msg_t chMBPostAheadS(Mailbox *mbp, msg_t msg, systime_t time) {
+ msg_t rdymsg;
+
+ chDbgCheckClassS();
+ chDbgCheck(mbp != NULL, "chMBPostAheadS");
+
+ rdymsg = chSemWaitTimeoutS(&mbp->mb_emptysem, time);
+ if (rdymsg == RDY_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 Mailbox object
+ * @param[in] msg the message to be posted on the mailbox
+ * @return The operation status.
+ * @retval RDY_OK if a message has been correctly posted.
+ * @retval RDY_TIMEOUT if the mailbox is full and the message cannot be
+ * posted.
+ *
+ * @iclass
+ */
+msg_t chMBPostAheadI(Mailbox *mbp, msg_t msg) {
+
+ chDbgCheckClassI();
+ chDbgCheck(mbp != NULL, "chMBPostAheadI");
+
+ if (chSemGetCounterI(&mbp->mb_emptysem) <= 0)
+ return RDY_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 RDY_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 Mailbox object
+ * @param[out] msgp pointer to a message variable for the received message
+ * @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 The operation status.
+ * @retval RDY_OK if a message has been correctly fetched.
+ * @retval RDY_RESET if the mailbox has been reset while waiting.
+ * @retval RDY_TIMEOUT if the operation has timed out.
+ *
+ * @api
+ */
+msg_t chMBFetch(Mailbox *mbp, msg_t *msgp, systime_t time) {
+ msg_t rdymsg;
+
+ chSysLock();
+ rdymsg = chMBFetchS(mbp, msgp, time);
+ 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 Mailbox object
+ * @param[out] msgp pointer to a message variable for the received message
+ * @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 The operation status.
+ * @retval RDY_OK if a message has been correctly fetched.
+ * @retval RDY_RESET if the mailbox has been reset while waiting.
+ * @retval RDY_TIMEOUT if the operation has timed out.
+ *
+ * @sclass
+ */
+msg_t chMBFetchS(Mailbox *mbp, msg_t *msgp, systime_t time) {
+ msg_t rdymsg;
+
+ chDbgCheckClassS();
+ chDbgCheck((mbp != NULL) && (msgp != NULL), "chMBFetchS");
+
+ rdymsg = chSemWaitTimeoutS(&mbp->mb_fullsem, time);
+ if (rdymsg == RDY_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 Mailbox object
+ * @param[out] msgp pointer to a message variable for the received message
+ * @return The operation status.
+ * @retval RDY_OK if a message has been correctly fetched.
+ * @retval RDY_TIMEOUT if the mailbox is empty and a message cannot be
+ * fetched.
+ *
+ * @iclass
+ */
+msg_t chMBFetchI(Mailbox *mbp, msg_t *msgp) {
+
+ chDbgCheckClassI();
+ chDbgCheck((mbp != NULL) && (msgp != NULL), "chMBFetchI");
+
+ if (chSemGetCounterI(&mbp->mb_fullsem) <= 0)
+ return RDY_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 RDY_OK;
+}
+#endif /* CH_USE_MAILBOXES */
+
+/** @} */
diff --git a/os/kernel/src/chmemcore.c b/os/kernel/src/chmemcore.c new file mode 100644 index 000000000..0ff26bc76 --- /dev/null +++ b/os/kernel/src/chmemcore.c @@ -0,0 +1,131 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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_USE_MEMCORE
+ * option must be enabled in @p chconf.h.
+ * @{
+ */
+
+#include "ch.h"
+
+#if CH_USE_MEMCORE || defined(__DOXYGEN__)
+
+static uint8_t *nextmem;
+static uint8_t *endmem;
+
+/**
+ * @brief Low level memory manager initialization.
+ *
+ * @notapi
+ */
+void _core_init(void) {
+#if CH_MEMCORE_SIZE == 0
+ extern uint8_t __heap_base__[];
+ extern uint8_t __heap_end__[];
+ nextmem = (uint8_t *)MEM_ALIGN_NEXT(__heap_base__);
+ endmem = (uint8_t *)MEM_ALIGN_PREV(__heap_end__);
+#else
+ static stkalign_t buffer[MEM_ALIGN_NEXT(CH_MEMCORE_SIZE)/MEM_ALIGN_SIZE];
+ nextmem = (uint8_t *)&buffer[0];
+ endmem = (uint8_t *)&buffer[MEM_ALIGN_NEXT(CH_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);
+ if ((size_t)(endmem - nextmem) < size)
+ return NULL;
+ p = nextmem;
+ nextmem += size;
+ return p;
+}
+
+/**
+ * @brief Core memory status.
+ *
+ * @return The size, in bytes, of the free core memory.
+ *
+ * @api
+ */
+size_t chCoreStatus(void) {
+
+ return (size_t)(endmem - nextmem);
+}
+#endif /* CH_USE_MEMCORE */
+
+/** @} */
diff --git a/os/kernel/src/chmempools.c b/os/kernel/src/chmempools.c new file mode 100644 index 000000000..44faa057a --- /dev/null +++ b/os/kernel/src/chmempools.c @@ -0,0 +1,173 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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_USE_MEMPOOLS option
+ * must be enabled in @p chconf.h.
+ * @{
+ */
+
+#include "ch.h"
+
+#if CH_USE_MEMPOOLS || defined(__DOXYGEN__)
+/**
+ * @brief Initializes an empty memory pool.
+ *
+ * @param[out] mp pointer to a @p MemoryPool 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 chPoolInit(MemoryPool *mp, size_t size, memgetfunc_t provider) {
+
+ chDbgCheck((mp != NULL) && (size >= sizeof(void *)), "chPoolInit");
+
+ 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 MemoryPool structure
+ * @param[in] p pointer to the array first element
+ * @param[in] n number of elements in the array
+ *
+ * @api
+ */
+void chPoolLoadArray(MemoryPool *mp, void *p, size_t n) {
+
+ chDbgCheck((mp != NULL) && (n != 0), "chPoolLoadArray");
+
+ while (n) {
+ chPoolAdd(mp, p);
+ p = (void *)(((uint8_t *)p) + mp->mp_object_size);
+ 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 MemoryPool structure
+ * @return The pointer to the allocated object.
+ * @retval NULL if pool is empty.
+ *
+ * @iclass
+ */
+void *chPoolAllocI(MemoryPool *mp) {
+ void *objp;
+
+ chDbgCheckClassI();
+ chDbgCheck(mp != NULL, "chPoolAllocI");
+
+ if ((objp = mp->mp_next) != NULL)
+ mp->mp_next = mp->mp_next->ph_next;
+ else if (mp->mp_provider != NULL)
+ objp = mp->mp_provider(mp->mp_object_size);
+ 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 MemoryPool structure
+ * @return The pointer to the allocated object.
+ * @retval NULL if pool is empty.
+ *
+ * @api
+ */
+void *chPoolAlloc(MemoryPool *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 MemoryPool structure
+ * @param[in] objp the pointer to the object to be released
+ *
+ * @iclass
+ */
+void chPoolFreeI(MemoryPool *mp, void *objp) {
+ struct pool_header *php = objp;
+
+ chDbgCheckClassI();
+ chDbgCheck((mp != NULL) && (objp != NULL), "chPoolFreeI");
+
+ 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 MemoryPool structure
+ * @param[in] objp the pointer to the object to be released
+ *
+ * @api
+ */
+void chPoolFree(MemoryPool *mp, void *objp) {
+
+ chSysLock();
+ chPoolFreeI(mp, objp);
+ chSysUnlock();
+}
+
+#endif /* CH_USE_MEMPOOLS */
+
+/** @} */
diff --git a/os/kernel/src/chmsg.c b/os/kernel/src/chmsg.c new file mode 100644 index 000000000..ad97da79c --- /dev/null +++ b/os/kernel/src/chmsg.c @@ -0,0 +1,132 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 chmsg.c
+ * @brief Messages code.
+ *
+ * @addtogroup messages
+ * @details Synchronous inter-thread messages APIs and services.
+ * <h2>Operation Mode</h2>
+ * Synchronous messages are an easy to use and fast IPC mechanism,
+ * threads can both act as message servers and/or message clients,
+ * the mechanism allows data to be carried in both directions. Note
+ * that messages are not copied between the client and server threads
+ * but just a pointer passed so the exchange is very time
+ * efficient.<br>
+ * Messages are scalar data types of type @p msg_t that are guaranteed
+ * to be size compatible with data pointers. Note that on some
+ * architectures function pointers can be larger that @p msg_t.<br>
+ * Messages are usually processed in FIFO order but it is possible to
+ * process them in priority order by enabling the
+ * @p CH_USE_MESSAGES_PRIORITY option in @p chconf.h.<br>
+ * @pre In order to use the message APIs the @p CH_USE_MESSAGES option
+ * must be enabled in @p chconf.h.
+ * @post Enabling messages requires 6-12 (depending on the architecture)
+ * extra bytes in the @p Thread structure.
+ * @{
+ */
+
+#include "ch.h"
+
+#if CH_USE_MESSAGES || defined(__DOXYGEN__)
+
+#if CH_USE_MESSAGES_PRIORITY
+#define msg_insert(tp, qp) prio_insert(tp, qp)
+#else
+#define msg_insert(tp, qp) queue_insert(tp, qp)
+#endif
+
+/**
+ * @brief Sends a message to the specified thread.
+ * @details The sender is stopped until the receiver executes a
+ * @p chMsgRelease()after receiving the message.
+ *
+ * @param[in] tp the pointer to the thread
+ * @param[in] msg the message
+ * @return The answer message from @p chMsgRelease().
+ *
+ * @api
+ */
+msg_t chMsgSend(Thread *tp, msg_t msg) {
+ Thread *ctp = currp;
+
+ chDbgCheck(tp != NULL, "chMsgSend");
+
+ chSysLock();
+ ctp->p_msg = msg;
+ ctp->p_u.wtobjp = &tp->p_msgqueue;
+ msg_insert(ctp, &tp->p_msgqueue);
+ if (tp->p_state == THD_STATE_WTMSG)
+ chSchReadyI(tp);
+ chSchGoSleepS(THD_STATE_SNDMSGQ);
+ msg = ctp->p_u.rdymsg;
+ chSysUnlock();
+ return msg;
+}
+
+/**
+ * @brief Suspends the thread and waits for an incoming message.
+ * @post After receiving a message the function @p chMsgGet() must be
+ * called in order to retrieve the message and then @p chMsgRelease()
+ * must be invoked in order to acknowledge the reception and send
+ * the answer.
+ * @note If the message is a pointer then you can assume that the data
+ * pointed by the message is stable until you invoke @p chMsgRelease()
+ * because the sending thread is suspended until then.
+ *
+ * @return A reference to the thread carrying the message.
+ *
+ * @api
+ */
+Thread *chMsgWait(void) {
+ Thread *tp;
+
+ chSysLock();
+ if (!chMsgIsPendingI(currp))
+ chSchGoSleepS(THD_STATE_WTMSG);
+ tp = fifo_remove(&currp->p_msgqueue);
+ tp->p_state = THD_STATE_SNDMSG;
+ chSysUnlock();
+ return tp;
+}
+
+/**
+ * @brief Releases a sender thread specifying a response message.
+ * @pre Invoke this function only after a message has been received
+ * using @p chMsgWait().
+ *
+ * @param[in] tp pointer to the thread
+ * @param[in] msg message to be returned to the sender
+ *
+ * @api
+ */
+void chMsgRelease(Thread *tp, msg_t msg) {
+
+ chSysLock();
+ chDbgAssert(tp->p_state == THD_STATE_SNDMSG,
+ "chMsgRelease(), #1", "invalid state");
+ chMsgReleaseS(tp, msg);
+ chSysUnlock();
+}
+
+#endif /* CH_USE_MESSAGES */
+
+/** @} */
diff --git a/os/kernel/src/chmtx.c b/os/kernel/src/chmtx.c new file mode 100644 index 000000000..84d7e53a6 --- /dev/null +++ b/os/kernel/src/chmtx.c @@ -0,0 +1,393 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 chmtx.c
+ * @brief Mutexes code.
+ *
+ * @addtogroup mutexes
+ * @details Mutexes related APIs and services.
+ *
+ * <h2>Operation mode</h2>
+ * A mutex is a threads synchronization object that can be in two
+ * distinct states:
+ * - Not owned (unlocked).
+ * - Owned by a thread (locked).
+ * .
+ * Operations defined for mutexes:
+ * - <b>Lock</b>: The mutex is checked, if the mutex is not owned by
+ * some other thread then it is associated to the locking thread
+ * else the thread is queued on the mutex in a list ordered by
+ * priority.
+ * - <b>Unlock</b>: The mutex is released by the owner and the highest
+ * priority thread waiting in the queue, if any, is resumed and made
+ * owner of the mutex.
+ * .
+ * <h2>Constraints</h2>
+ * In ChibiOS/RT the Unlock operations are always performed in
+ * lock-reverse order. The unlock API does not even have a parameter,
+ * the mutex to unlock is selected from an internal, per-thread, stack
+ * of owned mutexes. This both improves the performance and is
+ * required for an efficient implementation of the priority
+ * inheritance mechanism.
+ *
+ * <h2>The priority inversion problem</h2>
+ * The mutexes in ChibiOS/RT implements the <b>full</b> priority
+ * inheritance mechanism in order handle the priority inversion
+ * problem.<br>
+ * When a thread is queued on a mutex, any thread, directly or
+ * indirectly, holding the mutex gains the same priority of the
+ * waiting thread (if their priority was not already equal or higher).
+ * The mechanism works with any number of nested mutexes and any
+ * number of involved threads. The algorithm complexity (worst case)
+ * is N with N equal to the number of nested mutexes.
+ * @pre In order to use the mutex APIs the @p CH_USE_MUTEXES option
+ * must be enabled in @p chconf.h.
+ * @post Enabling mutexes requires 5-12 (depending on the architecture)
+ * extra bytes in the @p Thread structure.
+ * @{
+ */
+
+#include "ch.h"
+
+#if CH_USE_MUTEXES || defined(__DOXYGEN__)
+
+/**
+ * @brief Initializes s @p Mutex structure.
+ *
+ * @param[out] mp pointer to a @p Mutex structure
+ *
+ * @init
+ */
+void chMtxInit(Mutex *mp) {
+
+ chDbgCheck(mp != NULL, "chMtxInit");
+
+ queue_init(&mp->m_queue);
+ mp->m_owner = NULL;
+}
+
+/**
+ * @brief Locks the specified mutex.
+ * @post The mutex is locked and inserted in the per-thread stack of owned
+ * mutexes.
+ *
+ * @param[in] mp pointer to the @p Mutex structure
+ *
+ * @api
+ */
+void chMtxLock(Mutex *mp) {
+
+ chSysLock();
+
+ chMtxLockS(mp);
+
+ chSysUnlock();
+}
+
+/**
+ * @brief Locks the specified mutex.
+ * @post The mutex is locked and inserted in the per-thread stack of owned
+ * mutexes.
+ *
+ * @param[in] mp pointer to the @p Mutex structure
+ *
+ * @sclass
+ */
+void chMtxLockS(Mutex *mp) {
+ Thread *ctp = currp;
+
+ chDbgCheckClassS();
+ chDbgCheck(mp != NULL, "chMtxLockS");
+
+ /* Is the mutex already locked? */
+ if (mp->m_owner != NULL) {
+ /* Priority inheritance protocol; explores the thread-mutex dependencies
+ boosting the priority of all the affected threads to equal the priority
+ of the running thread requesting the mutex.*/
+ Thread *tp = mp->m_owner;
+ /* Does the running thread have higher priority than the mutex
+ owning thread? */
+ while (tp->p_prio < ctp->p_prio) {
+ /* Make priority of thread tp match the running thread's priority.*/
+ tp->p_prio = ctp->p_prio;
+ /* The following states need priority queues reordering.*/
+ switch (tp->p_state) {
+ case THD_STATE_WTMTX:
+ /* Re-enqueues the mutex owner with its new priority.*/
+ prio_insert(dequeue(tp), (ThreadsQueue *)tp->p_u.wtobjp);
+ tp = ((Mutex *)tp->p_u.wtobjp)->m_owner;
+ continue;
+#if CH_USE_CONDVARS | \
+ (CH_USE_SEMAPHORES && CH_USE_SEMAPHORES_PRIORITY) | \
+ (CH_USE_MESSAGES && CH_USE_MESSAGES_PRIORITY)
+#if CH_USE_CONDVARS
+ case THD_STATE_WTCOND:
+#endif
+#if CH_USE_SEMAPHORES && CH_USE_SEMAPHORES_PRIORITY
+ case THD_STATE_WTSEM:
+#endif
+#if CH_USE_MESSAGES && CH_USE_MESSAGES_PRIORITY
+ case THD_STATE_SNDMSGQ:
+#endif
+ /* Re-enqueues tp with its new priority on the queue.*/
+ prio_insert(dequeue(tp), (ThreadsQueue *)tp->p_u.wtobjp);
+ break;
+#endif
+ case THD_STATE_READY:
+#if CH_DBG_ENABLE_ASSERTS
+ /* Prevents an assertion in chSchReadyI().*/
+ tp->p_state = THD_STATE_CURRENT;
+#endif
+ /* Re-enqueues tp with its new priority on the ready list.*/
+ chSchReadyI(dequeue(tp));
+ break;
+ }
+ break;
+ }
+ /* Sleep on the mutex.*/
+ prio_insert(ctp, &mp->m_queue);
+ ctp->p_u.wtobjp = mp;
+ chSchGoSleepS(THD_STATE_WTMTX);
+ /* It is assumed that the thread performing the unlock operation assigns
+ the mutex to this thread.*/
+ chDbgAssert(mp->m_owner == ctp, "chMtxLockS(), #1", "not owner");
+ chDbgAssert(ctp->p_mtxlist == mp, "chMtxLockS(), #2", "not owned");
+ }
+ else {
+ /* It was not owned, inserted in the owned mutexes list.*/
+ mp->m_owner = ctp;
+ mp->m_next = ctp->p_mtxlist;
+ ctp->p_mtxlist = mp;
+ }
+}
+
+/**
+ * @brief Tries to lock a mutex.
+ * @details This function attempts to lock a mutex, if the mutex is already
+ * locked by another thread then the function exits without waiting.
+ * @post The mutex is locked and inserted in the per-thread stack of owned
+ * mutexes.
+ * @note This function does not have any overhead related to the
+ * priority inheritance mechanism because it does not try to
+ * enter a sleep state.
+ *
+ * @param[in] mp pointer to the @p Mutex structure
+ * @return The operation status.
+ * @retval TRUE if the mutex has been successfully acquired
+ * @retval FALSE if the lock attempt failed.
+ *
+ * @api
+ */
+bool_t chMtxTryLock(Mutex *mp) {
+ bool_t b;
+
+ chSysLock();
+
+ b = chMtxTryLockS(mp);
+
+ chSysUnlock();
+ return b;
+}
+
+/**
+ * @brief Tries to lock a mutex.
+ * @details This function attempts to lock a mutex, if the mutex is already
+ * taken by another thread then the function exits without waiting.
+ * @post The mutex is locked and inserted in the per-thread stack of owned
+ * mutexes.
+ * @note This function does not have any overhead related to the
+ * priority inheritance mechanism because it does not try to
+ * enter a sleep state.
+ *
+ * @param[in] mp pointer to the @p Mutex structure
+ * @return The operation status.
+ * @retval TRUE if the mutex has been successfully acquired
+ * @retval FALSE if the lock attempt failed.
+ *
+ * @sclass
+ */
+bool_t chMtxTryLockS(Mutex *mp) {
+
+ chDbgCheckClassS();
+ chDbgCheck(mp != NULL, "chMtxTryLockS");
+
+ if (mp->m_owner != NULL)
+ return FALSE;
+ mp->m_owner = currp;
+ mp->m_next = currp->p_mtxlist;
+ currp->p_mtxlist = mp;
+ return TRUE;
+}
+
+/**
+ * @brief Unlocks the next owned mutex in reverse lock order.
+ * @pre The invoking thread <b>must</b> have at least one owned mutex.
+ * @post The mutex is unlocked and removed from the per-thread stack of
+ * owned mutexes.
+ *
+ * @return A pointer to the unlocked mutex.
+ *
+ * @api
+ */
+Mutex *chMtxUnlock(void) {
+ Thread *ctp = currp;
+ Mutex *ump, *mp;
+
+ chSysLock();
+ chDbgAssert(ctp->p_mtxlist != NULL,
+ "chMtxUnlock(), #1",
+ "owned mutexes list empty");
+ chDbgAssert(ctp->p_mtxlist->m_owner == ctp,
+ "chMtxUnlock(), #2",
+ "ownership failure");
+ /* Removes the top Mutex from the Thread's owned mutexes list and marks it
+ as not owned.*/
+ ump = ctp->p_mtxlist;
+ ctp->p_mtxlist = ump->m_next;
+ /* If a thread is waiting on the mutex then the fun part begins.*/
+ if (chMtxQueueNotEmptyS(ump)) {
+ Thread *tp;
+
+ /* Recalculates the optimal thread priority by scanning the owned
+ mutexes list.*/
+ tprio_t newprio = ctp->p_realprio;
+ mp = ctp->p_mtxlist;
+ while (mp != NULL) {
+ /* If the highest priority thread waiting in the mutexes list has a
+ greater priority than the current thread base priority then the final
+ priority will have at least that priority.*/
+ if (chMtxQueueNotEmptyS(mp) && (mp->m_queue.p_next->p_prio > newprio))
+ newprio = mp->m_queue.p_next->p_prio;
+ mp = mp->m_next;
+ }
+ /* Assigns to the current thread the highest priority among all the
+ waiting threads.*/
+ ctp->p_prio = newprio;
+ /* Awakens the highest priority thread waiting for the unlocked mutex and
+ assigns the mutex to it.*/
+ tp = fifo_remove(&ump->m_queue);
+ ump->m_owner = tp;
+ ump->m_next = tp->p_mtxlist;
+ tp->p_mtxlist = ump;
+ chSchWakeupS(tp, RDY_OK);
+ }
+ else
+ ump->m_owner = NULL;
+ chSysUnlock();
+ return ump;
+}
+
+/**
+ * @brief Unlocks the next owned mutex in reverse lock order.
+ * @pre The invoking thread <b>must</b> have at least one owned mutex.
+ * @post The mutex is unlocked and removed from the per-thread stack of
+ * owned mutexes.
+ * @post This function does not reschedule so a call to a rescheduling
+ * function must be performed before unlocking the kernel.
+ *
+ * @return A pointer to the unlocked mutex.
+ *
+ * @sclass
+ */
+Mutex *chMtxUnlockS(void) {
+ Thread *ctp = currp;
+ Mutex *ump, *mp;
+
+ chDbgCheckClassS();
+ chDbgAssert(ctp->p_mtxlist != NULL,
+ "chMtxUnlockS(), #1",
+ "owned mutexes list empty");
+ chDbgAssert(ctp->p_mtxlist->m_owner == ctp,
+ "chMtxUnlockS(), #2",
+ "ownership failure");
+
+ /* Removes the top Mutex from the owned mutexes list and marks it as not
+ owned.*/
+ ump = ctp->p_mtxlist;
+ ctp->p_mtxlist = ump->m_next;
+ /* If a thread is waiting on the mutex then the fun part begins.*/
+ if (chMtxQueueNotEmptyS(ump)) {
+ Thread *tp;
+
+ /* Recalculates the optimal thread priority by scanning the owned
+ mutexes list.*/
+ tprio_t newprio = ctp->p_realprio;
+ mp = ctp->p_mtxlist;
+ while (mp != NULL) {
+ /* If the highest priority thread waiting in the mutexes list has a
+ greater priority than the current thread base priority then the final
+ priority will have at least that priority.*/
+ if (chMtxQueueNotEmptyS(mp) && (mp->m_queue.p_next->p_prio > newprio))
+ newprio = mp->m_queue.p_next->p_prio;
+ mp = mp->m_next;
+ }
+ ctp->p_prio = newprio;
+ /* Awakens the highest priority thread waiting for the unlocked mutex and
+ assigns the mutex to it.*/
+ tp = fifo_remove(&ump->m_queue);
+ ump->m_owner = tp;
+ ump->m_next = tp->p_mtxlist;
+ tp->p_mtxlist = ump;
+ chSchReadyI(tp);
+ }
+ else
+ ump->m_owner = NULL;
+ return ump;
+}
+
+/**
+ * @brief Unlocks all the mutexes owned by the invoking thread.
+ * @post The stack of owned mutexes is emptied and all the found
+ * mutexes are unlocked.
+ * @note This function is <b>MUCH MORE</b> efficient than releasing the
+ * mutexes one by one and not just because the call overhead,
+ * this function does not have any overhead related to the priority
+ * inheritance mechanism.
+ *
+ * @api
+ */
+void chMtxUnlockAll(void) {
+ Thread *ctp = currp;
+
+ chSysLock();
+ if (ctp->p_mtxlist != NULL) {
+ do {
+ Mutex *ump = ctp->p_mtxlist;
+ ctp->p_mtxlist = ump->m_next;
+ if (chMtxQueueNotEmptyS(ump)) {
+ Thread *tp = fifo_remove(&ump->m_queue);
+ ump->m_owner = tp;
+ ump->m_next = tp->p_mtxlist;
+ tp->p_mtxlist = ump;
+ chSchReadyI(tp);
+ }
+ else
+ ump->m_owner = NULL;
+ } while (ctp->p_mtxlist != NULL);
+ ctp->p_prio = ctp->p_realprio;
+ chSchRescheduleS();
+ }
+ chSysUnlock();
+}
+
+#endif /* CH_USE_MUTEXES */
+
+/** @} */
diff --git a/os/kernel/src/chqueues.c b/os/kernel/src/chqueues.c new file mode 100644 index 000000000..871e499a0 --- /dev/null +++ b/os/kernel/src/chqueues.c @@ -0,0 +1,431 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 chqueues.c
+ * @brief I/O Queues code.
+ *
+ * @addtogroup io_queues
+ * @details ChibiOS/RT queues are mostly used in serial-like device drivers.
+ * The device drivers are usually designed to have a lower side
+ * (lower driver, it is usually an interrupt service routine) and an
+ * upper side (upper driver, accessed by the application threads).<br>
+ * There are several kind of queues:<br>
+ * - <b>Input queue</b>, unidirectional queue where the writer is the
+ * lower side and the reader is the upper side.
+ * - <b>Output queue</b>, unidirectional queue where the writer is the
+ * upper side and the reader is the lower side.
+ * - <b>Full duplex queue</b>, bidirectional queue. Full duplex queues
+ * are implemented by pairing an input queue and an output queue
+ * together.
+ * .
+ * @pre In order to use the I/O queues the @p CH_USE_QUEUES option must
+ * be enabled in @p chconf.h.
+ * @{
+ */
+
+#include "ch.h"
+
+#if CH_USE_QUEUES || defined(__DOXYGEN__)
+
+/**
+ * @brief Puts the invoking thread into the queue's threads queue.
+ *
+ * @param[out] qp pointer to an @p GenericQueue 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 threads queue.
+ * @retval Q_OK is the normal exit, thread signaled.
+ * @retval Q_RESET if the queue has been reset.
+ * @retval Q_TIMEOUT if the queue operation timed out.
+ */
+static msg_t qwait(GenericQueue *qp, systime_t time) {
+
+ if (TIME_IMMEDIATE == time)
+ return Q_TIMEOUT;
+ currp->p_u.wtobjp = qp;
+ queue_insert(currp, &qp->q_waiting);
+ return chSchGoSleepTimeoutS(THD_STATE_WTQUEUE, time);
+}
+
+/**
+ * @brief Initializes an input queue.
+ * @details A Semaphore is internally initialized and works as a counter of
+ * the bytes contained in the queue.
+ * @note The callback is invoked from within the S-Locked system state,
+ * see @ref system_states.
+ *
+ * @param[out] iqp pointer to an @p InputQueue structure
+ * @param[in] bp pointer to a memory area allocated as queue buffer
+ * @param[in] size size of the queue buffer
+ * @param[in] infy pointer to a callback function that is invoked when
+ * data is read from the queue. The value can be @p NULL.
+ * @param[in] link application defined pointer
+ *
+ * @init
+ */
+void chIQInit(InputQueue *iqp, uint8_t *bp, size_t size, qnotify_t infy,
+ void *link) {
+
+ queue_init(&iqp->q_waiting);
+ iqp->q_counter = 0;
+ iqp->q_buffer = iqp->q_rdptr = iqp->q_wrptr = bp;
+ iqp->q_top = bp + size;
+ iqp->q_notify = infy;
+ iqp->q_link = link;
+}
+
+/**
+ * @brief Resets an input queue.
+ * @details All the data in the input queue is erased and lost, any waiting
+ * thread is resumed with status @p Q_RESET.
+ * @note A reset operation can be used by a low level driver in order to
+ * obtain immediate attention from the high level layers.
+ *
+ * @param[in] iqp pointer to an @p InputQueue structure
+ *
+ * @iclass
+ */
+void chIQResetI(InputQueue *iqp) {
+
+ chDbgCheckClassI();
+
+ iqp->q_rdptr = iqp->q_wrptr = iqp->q_buffer;
+ iqp->q_counter = 0;
+ while (notempty(&iqp->q_waiting))
+ chSchReadyI(fifo_remove(&iqp->q_waiting))->p_u.rdymsg = Q_RESET;
+}
+
+/**
+ * @brief Input queue write.
+ * @details A byte value is written into the low end of an input queue.
+ *
+ * @param[in] iqp pointer to an @p InputQueue structure
+ * @param[in] b the byte value to be written in the queue
+ * @return The operation status.
+ * @retval Q_OK if the operation has been completed with success.
+ * @retval Q_FULL if the queue is full and the operation cannot be
+ * completed.
+ *
+ * @iclass
+ */
+msg_t chIQPutI(InputQueue *iqp, uint8_t b) {
+
+ chDbgCheckClassI();
+
+ if (chIQIsFullI(iqp))
+ return Q_FULL;
+
+ iqp->q_counter++;
+ *iqp->q_wrptr++ = b;
+ if (iqp->q_wrptr >= iqp->q_top)
+ iqp->q_wrptr = iqp->q_buffer;
+
+ if (notempty(&iqp->q_waiting))
+ chSchReadyI(fifo_remove(&iqp->q_waiting))->p_u.rdymsg = Q_OK;
+
+ return Q_OK;
+}
+
+/**
+ * @brief Input queue read with timeout.
+ * @details This function reads a byte value from an input queue. If the queue
+ * is empty then the calling thread is suspended until a byte arrives
+ * in the queue or a timeout occurs.
+ * @note The callback is invoked before reading the character from the
+ * buffer or before entering the state @p THD_STATE_WTQUEUE.
+ *
+ * @param[in] iqp pointer to an @p InputQueue 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 byte value from the queue.
+ * @retval Q_TIMEOUT if the specified time expired.
+ * @retval Q_RESET if the queue has been reset.
+ *
+ * @api
+ */
+msg_t chIQGetTimeout(InputQueue *iqp, systime_t time) {
+ uint8_t b;
+
+ chSysLock();
+ if (iqp->q_notify)
+ iqp->q_notify(iqp);
+
+ while (chIQIsEmptyI(iqp)) {
+ msg_t msg;
+ if ((msg = qwait((GenericQueue *)iqp, time)) < Q_OK) {
+ chSysUnlock();
+ return msg;
+ }
+ }
+
+ iqp->q_counter--;
+ b = *iqp->q_rdptr++;
+ if (iqp->q_rdptr >= iqp->q_top)
+ iqp->q_rdptr = iqp->q_buffer;
+
+ chSysUnlock();
+ return b;
+}
+
+/**
+ * @brief Input queue read with timeout.
+ * @details The function reads data from an input queue into a buffer. The
+ * operation completes when the specified amount of data has been
+ * transferred or after the specified timeout or if the queue has
+ * been reset.
+ * @note The function is not atomic, if you need atomicity it is suggested
+ * to use a semaphore or a mutex for mutual exclusion.
+ * @note The callback is invoked before reading each character from the
+ * buffer or before entering the state @p THD_STATE_WTQUEUE.
+ *
+ * @param[in] iqp pointer to an @p InputQueue structure
+ * @param[out] bp pointer to the data buffer
+ * @param[in] n the maximum amount of data to be transferred, the
+ * value 0 is reserved
+ * @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 The number of bytes effectively transferred.
+ *
+ * @api
+ */
+size_t chIQReadTimeout(InputQueue *iqp, uint8_t *bp,
+ size_t n, systime_t time) {
+ qnotify_t nfy = iqp->q_notify;
+ size_t r = 0;
+
+ chDbgCheck(n > 0, "chIQReadTimeout");
+
+ chSysLock();
+ while (TRUE) {
+ if (nfy)
+ nfy(iqp);
+
+ while (chIQIsEmptyI(iqp)) {
+ if (qwait((GenericQueue *)iqp, time) != Q_OK) {
+ chSysUnlock();
+ return r;
+ }
+ }
+
+ iqp->q_counter--;
+ *bp++ = *iqp->q_rdptr++;
+ if (iqp->q_rdptr >= iqp->q_top)
+ iqp->q_rdptr = iqp->q_buffer;
+
+ chSysUnlock(); /* Gives a preemption chance in a controlled point.*/
+ r++;
+ if (--n == 0)
+ return r;
+
+ chSysLock();
+ }
+}
+
+/**
+ * @brief Initializes an output queue.
+ * @details A Semaphore is internally initialized and works as a counter of
+ * the free bytes in the queue.
+ * @note The callback is invoked from within the S-Locked system state,
+ * see @ref system_states.
+ *
+ * @param[out] oqp pointer to an @p OutputQueue structure
+ * @param[in] bp pointer to a memory area allocated as queue buffer
+ * @param[in] size size of the queue buffer
+ * @param[in] onfy pointer to a callback function that is invoked when
+ * data is written to the queue. The value can be @p NULL.
+ * @param[in] link application defined pointer
+ *
+ * @init
+ */
+void chOQInit(OutputQueue *oqp, uint8_t *bp, size_t size, qnotify_t onfy,
+ void *link) {
+
+ queue_init(&oqp->q_waiting);
+ oqp->q_counter = size;
+ oqp->q_buffer = oqp->q_rdptr = oqp->q_wrptr = bp;
+ oqp->q_top = bp + size;
+ oqp->q_notify = onfy;
+ oqp->q_link = link;
+}
+
+/**
+ * @brief Resets an output queue.
+ * @details All the data in the output queue is erased and lost, any waiting
+ * thread is resumed with status @p Q_RESET.
+ * @note A reset operation can be used by a low level driver in order to
+ * obtain immediate attention from the high level layers.
+ *
+ * @param[in] oqp pointer to an @p OutputQueue structure
+ *
+ * @iclass
+ */
+void chOQResetI(OutputQueue *oqp) {
+
+ chDbgCheckClassI();
+
+ oqp->q_rdptr = oqp->q_wrptr = oqp->q_buffer;
+ oqp->q_counter = chQSizeI(oqp);
+ while (notempty(&oqp->q_waiting))
+ chSchReadyI(fifo_remove(&oqp->q_waiting))->p_u.rdymsg = Q_RESET;
+}
+
+/**
+ * @brief Output queue write with timeout.
+ * @details This function writes a byte value to an output queue. If the queue
+ * is full then the calling thread is suspended until there is space
+ * in the queue or a timeout occurs.
+ * @note The callback is invoked after writing the character into the
+ * buffer.
+ *
+ * @param[in] oqp pointer to an @p OutputQueue structure
+ * @param[in] b the byte value to be written in the queue
+ * @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 The operation status.
+ * @retval Q_OK if the operation succeeded.
+ * @retval Q_TIMEOUT if the specified time expired.
+ * @retval Q_RESET if the queue has been reset.
+ *
+ * @api
+ */
+msg_t chOQPutTimeout(OutputQueue *oqp, uint8_t b, systime_t time) {
+
+ chSysLock();
+ while (chOQIsFullI(oqp)) {
+ msg_t msg;
+
+ if ((msg = qwait((GenericQueue *)oqp, time)) < Q_OK) {
+ chSysUnlock();
+ return msg;
+ }
+ }
+
+ oqp->q_counter--;
+ *oqp->q_wrptr++ = b;
+ if (oqp->q_wrptr >= oqp->q_top)
+ oqp->q_wrptr = oqp->q_buffer;
+
+ if (oqp->q_notify)
+ oqp->q_notify(oqp);
+
+ chSysUnlock();
+ return Q_OK;
+}
+
+/**
+ * @brief Output queue read.
+ * @details A byte value is read from the low end of an output queue.
+ *
+ * @param[in] oqp pointer to an @p OutputQueue structure
+ * @return The byte value from the queue.
+ * @retval Q_EMPTY if the queue is empty.
+ *
+ * @iclass
+ */
+msg_t chOQGetI(OutputQueue *oqp) {
+ uint8_t b;
+
+ chDbgCheckClassI();
+
+ if (chOQIsEmptyI(oqp))
+ return Q_EMPTY;
+
+ oqp->q_counter++;
+ b = *oqp->q_rdptr++;
+ if (oqp->q_rdptr >= oqp->q_top)
+ oqp->q_rdptr = oqp->q_buffer;
+
+ if (notempty(&oqp->q_waiting))
+ chSchReadyI(fifo_remove(&oqp->q_waiting))->p_u.rdymsg = Q_OK;
+
+ return b;
+}
+
+/**
+ * @brief Output queue write with timeout.
+ * @details The function writes data from a buffer to an output queue. The
+ * operation completes when the specified amount of data has been
+ * transferred or after the specified timeout or if the queue has
+ * been reset.
+ * @note The function is not atomic, if you need atomicity it is suggested
+ * to use a semaphore or a mutex for mutual exclusion.
+ * @note The callback is invoked after writing each character into the
+ * buffer.
+ *
+ * @param[in] oqp pointer to an @p OutputQueue structure
+ * @param[out] bp pointer to the data buffer
+ * @param[in] n the maximum amount of data to be transferred, the
+ * value 0 is reserved
+ * @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 The number of bytes effectively transferred.
+ *
+ * @api
+ */
+size_t chOQWriteTimeout(OutputQueue *oqp, const uint8_t *bp,
+ size_t n, systime_t time) {
+ qnotify_t nfy = oqp->q_notify;
+ size_t w = 0;
+
+ chDbgCheck(n > 0, "chOQWriteTimeout");
+
+ chSysLock();
+ while (TRUE) {
+ while (chOQIsFullI(oqp)) {
+ if (qwait((GenericQueue *)oqp, time) != Q_OK) {
+ chSysUnlock();
+ return w;
+ }
+ }
+ oqp->q_counter--;
+ *oqp->q_wrptr++ = *bp++;
+ if (oqp->q_wrptr >= oqp->q_top)
+ oqp->q_wrptr = oqp->q_buffer;
+
+ if (nfy)
+ nfy(oqp);
+
+ chSysUnlock(); /* Gives a preemption chance in a controlled point.*/
+ w++;
+ if (--n == 0)
+ return w;
+ chSysLock();
+ }
+}
+#endif /* CH_USE_QUEUES */
+
+/** @} */
diff --git a/os/kernel/src/chregistry.c b/os/kernel/src/chregistry.c new file mode 100644 index 000000000..645172833 --- /dev/null +++ b/os/kernel/src/chregistry.c @@ -0,0 +1,156 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 chregistry.c
+ * @brief Threads registry code.
+ *
+ * @addtogroup registry
+ * @details Threads Registry related APIs and services.
+ *
+ * <h2>Operation mode</h2>
+ * The Threads Registry is a double linked list that holds all the
+ * active threads in the system.<br>
+ * Operations defined for the registry:
+ * - <b>First</b>, returns the first, in creation order, active thread
+ * in the system.
+ * - <b>Next</b>, returns the next, in creation order, active thread
+ * in the system.
+ * .
+ * The registry is meant to be mainly a debug feature, for example,
+ * using the registry a debugger can enumerate the active threads
+ * in any given moment or the shell can print the active threads
+ * and their state.<br>
+ * Another possible use is for centralized threads memory management,
+ * terminating threads can pulse an event source and an event handler
+ * can perform a scansion of the registry in order to recover the
+ * memory.
+ * @pre In order to use the threads registry the @p CH_USE_REGISTRY option
+ * must be enabled in @p chconf.h.
+ * @{
+ */
+#include "ch.h"
+
+#if CH_USE_REGISTRY || defined(__DOXYGEN__)
+
+#define _offsetof(st, m) \
+ ((size_t)((char *)&((st *)0)->m - (char *)0))
+
+/*
+ * OS signature in ROM plus debug-related information.
+ */
+ROMCONST chdebug_t ch_debug = {
+ "main",
+ (uint8_t)0,
+ (uint8_t)sizeof (chdebug_t),
+ (uint16_t)((CH_KERNEL_MAJOR << 11) |
+ (CH_KERNEL_MINOR << 6) |
+ (CH_KERNEL_PATCH) << 0),
+ (uint8_t)sizeof (void *),
+ (uint8_t)sizeof (systime_t),
+ (uint8_t)sizeof (Thread),
+ (uint8_t)_offsetof(Thread, p_prio),
+ (uint8_t)_offsetof(Thread, p_ctx),
+ (uint8_t)_offsetof(Thread, p_newer),
+ (uint8_t)_offsetof(Thread, p_older),
+ (uint8_t)_offsetof(Thread, p_name),
+#if CH_DBG_ENABLE_STACK_CHECK
+ (uint8_t)_offsetof(Thread, p_stklimit),
+#else
+ (uint8_t)0,
+#endif
+ (uint8_t)_offsetof(Thread, p_state),
+ (uint8_t)_offsetof(Thread, p_flags),
+#if CH_USE_DYNAMIC
+ (uint8_t)_offsetof(Thread, p_refs),
+#else
+ (uint8_t)0,
+#endif
+#if CH_TIME_QUANTUM > 0
+ (uint8_t)_offsetof(Thread, p_preempt),
+#else
+ (uint8_t)0,
+#endif
+#if CH_DBG_THREADS_PROFILING
+ (uint8_t)_offsetof(Thread, p_time)
+#else
+ (uint8_t)0
+#endif
+};
+
+/**
+ * @brief Returns the first thread in the system.
+ * @details Returns the most ancient thread in the system, usually this is
+ * the main thread unless it terminated. A reference is added to the
+ * returned thread in order to make sure its status is not lost.
+ * @note This function cannot return @p NULL because there is always at
+ * least one thread in the system.
+ *
+ * @return A reference to the most ancient thread.
+ *
+ * @api
+ */
+Thread *chRegFirstThread(void) {
+ Thread *tp;
+
+ chSysLock();
+ tp = rlist.r_newer;
+#if CH_USE_DYNAMIC
+ tp->p_refs++;
+#endif
+ chSysUnlock();
+ return tp;
+}
+
+/**
+ * @brief Returns the thread next to the specified one.
+ * @details The reference counter of the specified thread is decremented and
+ * the reference counter of the returned thread is incremented.
+ *
+ * @param[in] tp pointer to the thread
+ * @return A reference to the next thread.
+ * @retval NULL if there is no next thread.
+ *
+ * @api
+ */
+Thread *chRegNextThread(Thread *tp) {
+ Thread *ntp;
+
+ chSysLock();
+ ntp = tp->p_newer;
+ if (ntp == (Thread *)&rlist)
+ ntp = NULL;
+#if CH_USE_DYNAMIC
+ else {
+ chDbgAssert(ntp->p_refs < 255, "chRegNextThread(), #1",
+ "too many references");
+ ntp->p_refs++;
+ }
+#endif
+ chSysUnlock();
+#if CH_USE_DYNAMIC
+ chThdRelease(tp);
+#endif
+ return ntp;
+}
+
+#endif /* CH_USE_REGISTRY */
+
+/** @} */
diff --git a/os/kernel/src/chschd.c b/os/kernel/src/chschd.c new file mode 100644 index 000000000..1106cf03f --- /dev/null +++ b/os/kernel/src/chschd.c @@ -0,0 +1,378 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 chschd.c
+ * @brief Scheduler code.
+ *
+ * @addtogroup scheduler
+ * @details This module provides the default portable scheduler code,
+ * scheduler functions can be individually captured by the port
+ * layer in order to provide architecture optimized equivalents.
+ * When a function is captured its default code is not built into
+ * the OS image, the optimized version is included instead.
+ * @{
+ */
+
+#include "ch.h"
+
+/**
+ * @brief Ready list header.
+ */
+#if !defined(PORT_OPTIMIZED_RLIST_VAR) || defined(__DOXYGEN__)
+ReadyList rlist;
+#endif /* !defined(PORT_OPTIMIZED_RLIST_VAR) */
+
+/**
+ * @brief Scheduler initialization.
+ *
+ * @notapi
+ */
+void _scheduler_init(void) {
+
+ queue_init(&rlist.r_queue);
+ rlist.r_prio = NOPRIO;
+#if CH_USE_REGISTRY
+ rlist.r_newer = rlist.r_older = (Thread *)&rlist;
+#endif
+}
+
+/**
+ * @brief Inserts a thread in the Ready List.
+ * @details The thread is positioned behind all threads with higher or equal
+ * priority.
+ * @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.
+ * @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
+ */
+#if !defined(PORT_OPTIMIZED_READYI) || defined(__DOXYGEN__)
+Thread *chSchReadyI(Thread *tp) {
+ Thread *cp;
+
+ chDbgCheckClassI();
+
+ /* Integrity checks.*/
+ chDbgAssert((tp->p_state != THD_STATE_READY) &&
+ (tp->p_state != THD_STATE_FINAL),
+ "chSchReadyI(), #1",
+ "invalid state");
+
+ tp->p_state = THD_STATE_READY;
+ cp = (Thread *)&rlist.r_queue;
+ do {
+ cp = cp->p_next;
+ } while (cp->p_prio >= tp->p_prio);
+ /* Insertion on p_prev.*/
+ tp->p_next = cp;
+ tp->p_prev = cp->p_prev;
+ tp->p_prev->p_next = cp->p_prev = tp;
+ return tp;
+}
+#endif /* !defined(PORT_OPTIMIZED_READYI) */
+
+/**
+ * @brief Puts the current thread to sleep into the specified state.
+ * @details The thread goes into a sleeping state. The possible
+ * @ref thread_states are defined into @p threads.h.
+ *
+ * @param[in] newstate the new thread state
+ *
+ * @sclass
+ */
+#if !defined(PORT_OPTIMIZED_GOSLEEPS) || defined(__DOXYGEN__)
+void chSchGoSleepS(tstate_t newstate) {
+ Thread *otp;
+
+ chDbgCheckClassS();
+
+ (otp = currp)->p_state = newstate;
+#if CH_TIME_QUANTUM > 0
+ /* The thread is renouncing its remaining time slices so it will have a new
+ time quantum when it will wakeup.*/
+ otp->p_preempt = CH_TIME_QUANTUM;
+#endif
+ setcurrp(fifo_remove(&rlist.r_queue));
+ currp->p_state = THD_STATE_CURRENT;
+ chSysSwitch(currp, otp);
+}
+#endif /* !defined(PORT_OPTIMIZED_GOSLEEPS) */
+
+#if !defined(PORT_OPTIMIZED_GOSLEEPTIMEOUTS) || defined(__DOXYGEN__)
+/*
+ * Timeout wakeup callback.
+ */
+static void wakeup(void *p) {
+ Thread *tp = (Thread *)p;
+
+ chSysLockFromIsr();
+ switch (tp->p_state) {
+ case THD_STATE_READY:
+ /* Handling the special case where the thread has been made ready by
+ another thread with higher priority.*/
+ chSysUnlockFromIsr();
+ return;
+#if CH_USE_SEMAPHORES || CH_USE_QUEUES || \
+ (CH_USE_CONDVARS && CH_USE_CONDVARS_TIMEOUT)
+#if CH_USE_SEMAPHORES
+ case THD_STATE_WTSEM:
+ chSemFastSignalI((Semaphore *)tp->p_u.wtobjp);
+ /* Falls into, intentional. */
+#endif
+#if CH_USE_QUEUES
+ case THD_STATE_WTQUEUE:
+#endif
+#if CH_USE_CONDVARS && CH_USE_CONDVARS_TIMEOUT
+ case THD_STATE_WTCOND:
+#endif
+ /* States requiring dequeuing.*/
+ dequeue(tp);
+#endif
+ }
+ tp->p_u.rdymsg = RDY_TIMEOUT;
+ chSchReadyI(tp);
+ chSysUnlockFromIsr();
+}
+
+/**
+ * @brief Puts the current thread to sleep into the specified state with
+ * timeout specification.
+ * @details The thread goes into a sleeping state, if it is not awakened
+ * explicitly within the specified timeout then it is forcibly
+ * awakened with a @p RDY_TIMEOUT low level message. The possible
+ * @ref thread_states are defined into @p threads.h.
+ *
+ * @param[in] newstate the new thread state
+ * @param[in] time the number of ticks before the operation timeouts, the
+ * special values are handled as follow:
+ * - @a TIME_INFINITE the thread enters an infinite sleep
+ * state, this is equivalent to invoking
+ * @p chSchGoSleepS() but, of course, less efficient.
+ * - @a TIME_IMMEDIATE this value is not allowed.
+ * .
+ * @return The wakeup message.
+ * @retval RDY_TIMEOUT if a timeout occurs.
+ *
+ * @sclass
+ */
+msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time) {
+
+ chDbgCheckClassS();
+
+ if (TIME_INFINITE != time) {
+ VirtualTimer vt;
+
+ chVTSetI(&vt, time, wakeup, currp);
+ chSchGoSleepS(newstate);
+ if (chVTIsArmedI(&vt))
+ chVTResetI(&vt);
+ }
+ else
+ chSchGoSleepS(newstate);
+ return currp->p_u.rdymsg;
+}
+#endif /* !defined(PORT_OPTIMIZED_GOSLEEPTIMEOUTS) */
+
+/**
+ * @brief Wakes up a thread.
+ * @details The thread is inserted into the ready list or immediately made
+ * running depending on its relative priority compared to the current
+ * thread.
+ * @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.
+ * @note It is equivalent to a @p chSchReadyI() followed by a
+ * @p chSchRescheduleS() but much more efficient.
+ * @note The function assumes that the current thread has the highest
+ * priority.
+ *
+ * @param[in] ntp the Thread to be made ready
+ * @param[in] msg message to the awakened thread
+ *
+ * @sclass
+ */
+#if !defined(PORT_OPTIMIZED_WAKEUPS) || defined(__DOXYGEN__)
+void chSchWakeupS(Thread *ntp, msg_t msg) {
+
+ chDbgCheckClassS();
+
+ ntp->p_u.rdymsg = msg;
+ /* If the waken thread has a not-greater priority than the current
+ one then it is just inserted in the ready list else it made
+ running immediately and the invoking thread goes in the ready
+ list instead.*/
+ if (ntp->p_prio <= currp->p_prio)
+ chSchReadyI(ntp);
+ else {
+ Thread *otp = chSchReadyI(currp);
+ setcurrp(ntp);
+ ntp->p_state = THD_STATE_CURRENT;
+ chSysSwitch(ntp, otp);
+ }
+}
+#endif /* !defined(PORT_OPTIMIZED_WAKEUPS) */
+
+/**
+ * @brief Performs a reschedule if a higher priority thread is runnable.
+ * @details If a thread with a higher priority than the current thread is in
+ * the ready list then make the higher priority thread running.
+ *
+ * @sclass
+ */
+#if !defined(PORT_OPTIMIZED_RESCHEDULES) || defined(__DOXYGEN__)
+void chSchRescheduleS(void) {
+
+ chDbgCheckClassS();
+
+ if (chSchIsRescRequiredI())
+ chSchDoRescheduleAhead();
+}
+#endif /* !defined(PORT_OPTIMIZED_RESCHEDULES) */
+
+/**
+ * @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
+ */
+#if !defined(PORT_OPTIMIZED_ISPREEMPTIONREQUIRED) || defined(__DOXYGEN__)
+bool_t chSchIsPreemptionRequired(void) {
+ tprio_t p1 = firstprio(&rlist.r_queue);
+ tprio_t p2 = currp->p_prio;
+#if CH_TIME_QUANTUM > 0
+ /* If the running thread has not reached its time quantum, reschedule only
+ if the first thread on the ready queue has a higher priority.
+ 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.*/
+ return currp->p_preempt ? p1 > p2 : p1 >= p2;
+#else
+ /* If the round robin preemption feature is not enabled then performs a
+ simpler comparison.*/
+ return p1 > p2;
+#endif
+}
+#endif /* !defined(PORT_OPTIMIZED_ISPREEMPTIONREQUIRED) */
+
+/**
+ * @brief Switches to the first thread on the runnable queue.
+ * @details The current thread is positioned in the ready list behind all
+ * threads having the same priority. The thread regains its time
+ * quantum.
+ * @note Not a user function, it is meant to be invoked by the scheduler
+ * itself or from within the port layer.
+ *
+ * @special
+ */
+#if !defined(PORT_OPTIMIZED_DORESCHEDULEBEHIND) || defined(__DOXYGEN__)
+void chSchDoRescheduleBehind(void) {
+ Thread *otp;
+
+ otp = currp;
+ /* Picks the first thread from the ready queue and makes it current.*/
+ setcurrp(fifo_remove(&rlist.r_queue));
+ currp->p_state = THD_STATE_CURRENT;
+#if CH_TIME_QUANTUM > 0
+ otp->p_preempt = CH_TIME_QUANTUM;
+#endif
+ chSchReadyI(otp);
+ chSysSwitch(currp, otp);
+}
+#endif /* !defined(PORT_OPTIMIZED_DORESCHEDULEBEHIND) */
+
+/**
+ * @brief Switches to the first thread on the runnable queue.
+ * @details The current thread is positioned in the ready list ahead of all
+ * threads having the same priority.
+ * @note Not a user function, it is meant to be invoked by the scheduler
+ * itself or from within the port layer.
+ *
+ * @special
+ */
+#if !defined(PORT_OPTIMIZED_DORESCHEDULEAHEAD) || defined(__DOXYGEN__)
+void chSchDoRescheduleAhead(void) {
+ Thread *otp, *cp;
+
+ otp = currp;
+ /* Picks the first thread from the ready queue and makes it current.*/
+ setcurrp(fifo_remove(&rlist.r_queue));
+ currp->p_state = THD_STATE_CURRENT;
+
+ otp->p_state = THD_STATE_READY;
+ cp = (Thread *)&rlist.r_queue;
+ 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 = cp->p_prev = otp;
+
+ chSysSwitch(currp, otp);
+}
+#endif /* !defined(PORT_OPTIMIZED_DORESCHEDULEAHEAD) */
+
+/**
+ * @brief Switches to the first thread on the runnable queue.
+ * @details The current thread is positioned in the ready list behind or
+ * ahead of all threads having the same priority depending on
+ * if it used its whole time slice.
+ * @note Not a user function, it is meant to be invoked by the scheduler
+ * itself or from within the port layer.
+ *
+ * @special
+ */
+#if !defined(PORT_OPTIMIZED_DORESCHEDULE) || defined(__DOXYGEN__)
+void chSchDoReschedule(void) {
+
+#if CH_TIME_QUANTUM > 0
+ /* If CH_TIME_QUANTUM is enabled then there are two different scenarios to
+ handle on preemption: time quantum elapsed or not.*/
+ if (currp->p_preempt == 0) {
+ /* The thread consumed its time quantum so it is enqueued behind threads
+ with same priority level, however, it acquires a new time quantum.*/
+ chSchDoRescheduleBehind();
+ }
+ else {
+ /* 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.*/
+ chSchDoRescheduleAhead();
+ }
+#else /* !(CH_TIME_QUANTUM > 0) */
+ /* If the round-robin mechanism is disabled then the thread goes always
+ ahead of its peers.*/
+ chSchDoRescheduleAhead();
+#endif /* !(CH_TIME_QUANTUM > 0) */
+}
+#endif /* !defined(PORT_OPTIMIZED_DORESCHEDULE) */
+
+/** @} */
diff --git a/os/kernel/src/chsem.c b/os/kernel/src/chsem.c new file mode 100644 index 000000000..2dc7ee354 --- /dev/null +++ b/os/kernel/src/chsem.c @@ -0,0 +1,393 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 chsem.c
+ * @brief Semaphores code.
+ *
+ * @addtogroup semaphores
+ * @details Semaphores related APIs and services.
+ *
+ * <h2>Operation mode</h2>
+ * Semaphores are a flexible synchronization primitive, ChibiOS/RT
+ * implements semaphores in their "counting semaphores" variant as
+ * defined by Edsger Dijkstra plus several enhancements like:
+ * - Wait operation with timeout.
+ * - Reset operation.
+ * - Atomic wait+signal operation.
+ * - Return message from the wait operation (OK, RESET, TIMEOUT).
+ * .
+ * The binary semaphores variant can be easily implemented using
+ * counting semaphores.<br>
+ * Operations defined for semaphores:
+ * - <b>Signal</b>: The semaphore counter is increased and if the
+ * result is non-positive then a waiting thread is removed from
+ * the semaphore queue and made ready for execution.
+ * - <b>Wait</b>: The semaphore counter is decreased and if the result
+ * becomes negative the thread is queued in the semaphore and
+ * suspended.
+ * - <b>Reset</b>: The semaphore counter is reset to a non-negative
+ * value and all the threads in the queue are released.
+ * .
+ * Semaphores can be used as guards for mutual exclusion zones
+ * (note that mutexes are recommended for this kind of use) but
+ * also have other uses, queues guards and counters for example.<br>
+ * Semaphores usually use a FIFO queuing strategy but it is possible
+ * to make them order threads by priority by enabling
+ * @p CH_USE_SEMAPHORES_PRIORITY in @p chconf.h.
+ * @pre In order to use the semaphore APIs the @p CH_USE_SEMAPHORES
+ * option must be enabled in @p chconf.h.
+ * @{
+ */
+
+#include "ch.h"
+
+#if CH_USE_SEMAPHORES || defined(__DOXYGEN__)
+
+#if CH_USE_SEMAPHORES_PRIORITY
+#define sem_insert(tp, qp) prio_insert(tp, qp)
+#else
+#define sem_insert(tp, qp) queue_insert(tp, qp)
+#endif
+
+/**
+ * @brief Initializes a semaphore with the specified counter value.
+ *
+ * @param[out] sp pointer to a @p Semaphore structure
+ * @param[in] n initial value of the semaphore counter. Must be
+ * non-negative.
+ *
+ * @init
+ */
+void chSemInit(Semaphore *sp, cnt_t n) {
+
+ chDbgCheck((sp != NULL) && (n >= 0), "chSemInit");
+
+ queue_init(&sp->s_queue);
+ sp->s_cnt = n;
+}
+
+/**
+ * @brief Performs a reset operation on the semaphore.
+ * @post After invoking this function all the threads waiting on the
+ * semaphore, if any, are released and the semaphore counter is set
+ * to the specified, non negative, value.
+ * @note The released threads can recognize they were waked up by a reset
+ * rather than a signal because the @p chSemWait() will return
+ * @p RDY_RESET instead of @p RDY_OK.
+ *
+ * @param[in] sp pointer to a @p Semaphore structure
+ * @param[in] n the new value of the semaphore counter. The value must
+ * be non-negative.
+ *
+ * @api
+ */
+void chSemReset(Semaphore *sp, cnt_t n) {
+
+ chSysLock();
+ chSemResetI(sp, n);
+ chSchRescheduleS();
+ chSysUnlock();
+}
+
+/**
+ * @brief Performs a reset operation on the semaphore.
+ * @post After invoking this function all the threads waiting on the
+ * semaphore, if any, are released and the semaphore counter is set
+ * to the specified, non negative, value.
+ * @post This function does not reschedule so a call to a rescheduling
+ * function must be performed before unlocking the kernel. Note that
+ * interrupt handlers always reschedule on exit so an explicit
+ * reschedule must not be performed in ISRs.
+ * @note The released threads can recognize they were waked up by a reset
+ * rather than a signal because the @p chSemWait() will return
+ * @p RDY_RESET instead of @p RDY_OK.
+ *
+ * @param[in] sp pointer to a @p Semaphore structure
+ * @param[in] n the new value of the semaphore counter. The value must
+ * be non-negative.
+ *
+ * @iclass
+ */
+void chSemResetI(Semaphore *sp, cnt_t n) {
+ cnt_t cnt;
+
+ chDbgCheckClassI();
+ chDbgCheck((sp != NULL) && (n >= 0), "chSemResetI");
+ chDbgAssert(((sp->s_cnt >= 0) && isempty(&sp->s_queue)) ||
+ ((sp->s_cnt < 0) && notempty(&sp->s_queue)),
+ "chSemResetI(), #1",
+ "inconsistent semaphore");
+
+ cnt = sp->s_cnt;
+ sp->s_cnt = n;
+ while (++cnt <= 0)
+ chSchReadyI(lifo_remove(&sp->s_queue))->p_u.rdymsg = RDY_RESET;
+}
+
+/**
+ * @brief Performs a wait operation on a semaphore.
+ *
+ * @param[in] sp pointer to a @p Semaphore structure
+ * @return A message specifying how the invoking thread has been
+ * released from the semaphore.
+ * @retval RDY_OK if the thread has not stopped on the semaphore or the
+ * semaphore has been signaled.
+ * @retval RDY_RESET if the semaphore has been reset using @p chSemReset().
+ *
+ * @api
+ */
+msg_t chSemWait(Semaphore *sp) {
+ msg_t msg;
+
+ chSysLock();
+ msg = chSemWaitS(sp);
+ chSysUnlock();
+ return msg;
+}
+
+/**
+ * @brief Performs a wait operation on a semaphore.
+ *
+ * @param[in] sp pointer to a @p Semaphore structure
+ * @return A message specifying how the invoking thread has been
+ * released from the semaphore.
+ * @retval RDY_OK if the thread has not stopped on the semaphore or the
+ * semaphore has been signaled.
+ * @retval RDY_RESET if the semaphore has been reset using @p chSemReset().
+ *
+ * @sclass
+ */
+msg_t chSemWaitS(Semaphore *sp) {
+
+ chDbgCheckClassS();
+ chDbgCheck(sp != NULL, "chSemWaitS");
+ chDbgAssert(((sp->s_cnt >= 0) && isempty(&sp->s_queue)) ||
+ ((sp->s_cnt < 0) && notempty(&sp->s_queue)),
+ "chSemWaitS(), #1",
+ "inconsistent semaphore");
+
+ if (--sp->s_cnt < 0) {
+ currp->p_u.wtobjp = sp;
+ sem_insert(currp, &sp->s_queue);
+ chSchGoSleepS(THD_STATE_WTSEM);
+ return currp->p_u.rdymsg;
+ }
+ return RDY_OK;
+}
+
+/**
+ * @brief Performs a wait operation on a semaphore with timeout specification.
+ *
+ * @param[in] sp pointer to a @p Semaphore 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 RDY_OK if the thread has not stopped on the semaphore or the
+ * semaphore has been signaled.
+ * @retval RDY_RESET if the semaphore has been reset using @p chSemReset().
+ * @retval RDY_TIMEOUT if the semaphore has not been signaled or reset within
+ * the specified timeout.
+ *
+ * @api
+ */
+msg_t chSemWaitTimeout(Semaphore *sp, systime_t time) {
+ msg_t msg;
+
+ chSysLock();
+ msg = chSemWaitTimeoutS(sp, time);
+ chSysUnlock();
+ return msg;
+}
+
+/**
+ * @brief Performs a wait operation on a semaphore with timeout specification.
+ *
+ * @param[in] sp pointer to a @p Semaphore 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 RDY_OK if the thread has not stopped on the semaphore or the
+ * semaphore has been signaled.
+ * @retval RDY_RESET if the semaphore has been reset using @p chSemReset().
+ * @retval RDY_TIMEOUT if the semaphore has not been signaled or reset within
+ * the specified timeout.
+ *
+ * @sclass
+ */
+msg_t chSemWaitTimeoutS(Semaphore *sp, systime_t time) {
+
+ chDbgCheckClassS();
+ chDbgCheck(sp != NULL, "chSemWaitTimeoutS");
+ chDbgAssert(((sp->s_cnt >= 0) && isempty(&sp->s_queue)) ||
+ ((sp->s_cnt < 0) && notempty(&sp->s_queue)),
+ "chSemWaitTimeoutS(), #1",
+ "inconsistent semaphore");
+
+ if (--sp->s_cnt < 0) {
+ if (TIME_IMMEDIATE == time) {
+ sp->s_cnt++;
+ return RDY_TIMEOUT;
+ }
+ currp->p_u.wtobjp = sp;
+ sem_insert(currp, &sp->s_queue);
+ return chSchGoSleepTimeoutS(THD_STATE_WTSEM, time);
+ }
+ return RDY_OK;
+}
+
+/**
+ * @brief Performs a signal operation on a semaphore.
+ *
+ * @param[in] sp pointer to a @p Semaphore structure
+ *
+ * @api
+ */
+void chSemSignal(Semaphore *sp) {
+
+ chDbgCheck(sp != NULL, "chSemSignal");
+ chDbgAssert(((sp->s_cnt >= 0) && isempty(&sp->s_queue)) ||
+ ((sp->s_cnt < 0) && notempty(&sp->s_queue)),
+ "chSemSignal(), #1",
+ "inconsistent semaphore");
+
+ chSysLock();
+ if (++sp->s_cnt <= 0)
+ chSchWakeupS(fifo_remove(&sp->s_queue), RDY_OK);
+ chSysUnlock();
+}
+
+/**
+ * @brief Performs a signal operation on a semaphore.
+ * @post This function does not reschedule so a call to a rescheduling
+ * function must be performed before unlocking the kernel. Note that
+ * interrupt handlers always reschedule on exit so an explicit
+ * reschedule must not be performed in ISRs.
+ *
+ * @param[in] sp pointer to a @p Semaphore structure
+ *
+ * @iclass
+ */
+void chSemSignalI(Semaphore *sp) {
+
+ chDbgCheckClassI();
+ chDbgCheck(sp != NULL, "chSemSignalI");
+ chDbgAssert(((sp->s_cnt >= 0) && isempty(&sp->s_queue)) ||
+ ((sp->s_cnt < 0) && notempty(&sp->s_queue)),
+ "chSemSignalI(), #1",
+ "inconsistent semaphore");
+
+ if (++sp->s_cnt <= 0) {
+ /* Note, it is done this way in order to allow a tail call on
+ chSchReadyI().*/
+ Thread *tp = fifo_remove(&sp->s_queue);
+ tp->p_u.rdymsg = RDY_OK;
+ chSchReadyI(tp);
+ }
+}
+
+/**
+ * @brief Adds the specified value to the semaphore counter.
+ * @post This function does not reschedule so a call to a rescheduling
+ * function must be performed before unlocking the kernel. Note that
+ * interrupt handlers always reschedule on exit so an explicit
+ * reschedule must not be performed in ISRs.
+ *
+ * @param[in] sp pointer to a @p Semaphore structure
+ * @param[in] n value to be added to the semaphore counter. The value
+ * must be positive.
+ *
+ * @iclass
+ */
+void chSemAddCounterI(Semaphore *sp, cnt_t n) {
+
+ chDbgCheckClassI();
+ chDbgCheck((sp != NULL) && (n > 0), "chSemAddCounterI");
+ chDbgAssert(((sp->s_cnt >= 0) && isempty(&sp->s_queue)) ||
+ ((sp->s_cnt < 0) && notempty(&sp->s_queue)),
+ "chSemAddCounterI(), #1",
+ "inconsistent semaphore");
+
+ while (n > 0) {
+ if (++sp->s_cnt <= 0)
+ chSchReadyI(fifo_remove(&sp->s_queue))->p_u.rdymsg = RDY_OK;
+ n--;
+ }
+}
+
+#if CH_USE_SEMSW
+/**
+ * @brief Performs atomic signal and wait operations on two semaphores.
+ * @pre The configuration option @p CH_USE_SEMSW must be enabled in order
+ * to use this function.
+ *
+ * @param[in] sps pointer to a @p Semaphore structure to be signaled
+ * @param[in] spw pointer to a @p Semaphore structure to wait on
+ * @return A message specifying how the invoking thread has been
+ * released from the semaphore.
+ * @retval RDY_OK if the thread has not stopped on the semaphore or the
+ * semaphore has been signaled.
+ * @retval RDY_RESET if the semaphore has been reset using @p chSemReset().
+ *
+ * @api
+ */
+msg_t chSemSignalWait(Semaphore *sps, Semaphore *spw) {
+ msg_t msg;
+
+ chDbgCheck((sps != NULL) && (spw != NULL), "chSemSignalWait");
+ chDbgAssert(((sps->s_cnt >= 0) && isempty(&sps->s_queue)) ||
+ ((sps->s_cnt < 0) && notempty(&sps->s_queue)),
+ "chSemSignalWait(), #1",
+ "inconsistent semaphore");
+ chDbgAssert(((spw->s_cnt >= 0) && isempty(&spw->s_queue)) ||
+ ((spw->s_cnt < 0) && notempty(&spw->s_queue)),
+ "chSemSignalWait(), #2",
+ "inconsistent semaphore");
+
+ chSysLock();
+ if (++sps->s_cnt <= 0)
+ chSchReadyI(fifo_remove(&sps->s_queue))->p_u.rdymsg = RDY_OK;
+ if (--spw->s_cnt < 0) {
+ Thread *ctp = currp;
+ sem_insert(ctp, &spw->s_queue);
+ ctp->p_u.wtobjp = spw;
+ chSchGoSleepS(THD_STATE_WTSEM);
+ msg = ctp->p_u.rdymsg;
+ }
+ else {
+ chSchRescheduleS();
+ msg = RDY_OK;
+ }
+ chSysUnlock();
+ return msg;
+}
+#endif /* CH_USE_SEMSW */
+
+#endif /* CH_USE_SEMAPHORES */
+
+/** @} */
diff --git a/os/kernel/src/chsys.c b/os/kernel/src/chsys.c new file mode 100644 index 000000000..a6f1d15ba --- /dev/null +++ b/os/kernel/src/chsys.c @@ -0,0 +1,149 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 chsys.c
+ * @brief System related code.
+ *
+ * @addtogroup system
+ * @details System related APIs and services:
+ * - Initialization.
+ * - Locks.
+ * - Interrupt Handling.
+ * - Power Management.
+ * - Abnormal Termination.
+ * .
+ * @{
+ */
+
+#include "ch.h"
+
+#if !CH_NO_IDLE_THREAD || defined(__DOXYGEN__)
+/**
+ * @brief Idle thread working area.
+ */
+WORKING_AREA(_idle_thread_wa, PORT_IDLE_THREAD_STACK_SIZE);
+
+/**
+ * @brief This function implements the idle thread infinite loop.
+ * @details The function puts the processor in the lowest power mode capable
+ * to serve interrupts.<br>
+ * The priority is internally set to the minimum system value so
+ * that this thread is executed only if there are no other ready
+ * threads in the system.
+ *
+ * @param[in] p the thread parameter, unused in this scenario
+ */
+void _idle_thread(void *p) {
+
+ (void)p;
+ chRegSetThreadName("idle");
+ while (TRUE) {
+ port_wait_for_interrupt();
+ IDLE_LOOP_HOOK();
+ }
+}
+#endif /* CH_NO_IDLE_THREAD */
+
+/**
+ * @brief ChibiOS/RT initialization.
+ * @details After executing this function the current instructions stream
+ * becomes the main thread.
+ * @pre Interrupts must be still disabled when @p chSysInit() is invoked
+ * and are internally enabled.
+ * @post The main thread is created with priority @p NORMALPRIO.
+ * @note This function has special, architecture-dependent, requirements,
+ * see the notes into the various port reference manuals.
+ *
+ * @special
+ */
+void chSysInit(void) {
+ static Thread mainthread;
+#if CH_DBG_ENABLE_STACK_CHECK
+ extern stkalign_t __main_thread_stack_base__;
+#endif
+
+ port_init();
+ _scheduler_init();
+ _vt_init();
+#if CH_USE_MEMCORE
+ _core_init();
+#endif
+#if CH_USE_HEAP
+ _heap_init();
+#endif
+#if CH_DBG_ENABLE_TRACE
+ _trace_init();
+#endif
+
+ /* Now this instructions flow becomes the main thread.*/
+ setcurrp(_thread_init(&mainthread, NORMALPRIO));
+ currp->p_state = THD_STATE_CURRENT;
+#if CH_DBG_ENABLE_STACK_CHECK
+ /* This is a special case because the main thread Thread structure is not
+ adjacent to its stack area.*/
+ currp->p_stklimit = &__main_thread_stack_base__;
+#endif
+ chSysEnable();
+
+ /* Note, &ch_debug points to the string "main" if the registry is
+ active, else the parameter is ignored.*/
+ chRegSetThreadName((const char *)&ch_debug);
+
+#if !CH_NO_IDLE_THREAD
+ /* 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
+ mode compatible with the system status.*/
+ chThdCreateStatic(_idle_thread_wa, sizeof(_idle_thread_wa), IDLEPRIO,
+ (tfunc_t)_idle_thread, NULL);
+#endif
+}
+
+/**
+ * @brief Handles time ticks for round robin preemption and timer increments.
+ * @details Decrements the remaining time quantum of the running thread
+ * and preempts it when the quantum is used up. Increments system
+ * time and manages the timers.
+ * @note The frequency of the timer determines the system tick granularity
+ * and, together with the @p CH_TIME_QUANTUM macro, the round robin
+ * interval.
+ *
+ * @iclass
+ */
+void chSysTimerHandlerI(void) {
+
+ chDbgCheckClassI();
+
+#if CH_TIME_QUANTUM > 0
+ /* Running thread has not used up quantum yet? */
+ if (currp->p_preempt > 0)
+ /* Decrement remaining quantum.*/
+ currp->p_preempt--;
+#endif
+#if CH_DBG_THREADS_PROFILING
+ currp->p_time++;
+#endif
+ chVTDoTickI();
+#if defined(SYSTEM_TICK_EVENT_HOOK)
+ SYSTEM_TICK_EVENT_HOOK();
+#endif
+}
+
+/** @} */
diff --git a/os/kernel/src/chthreads.c b/os/kernel/src/chthreads.c new file mode 100644 index 000000000..9f6973c90 --- /dev/null +++ b/os/kernel/src/chthreads.c @@ -0,0 +1,436 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 chthreads.c
+ * @brief Threads code.
+ *
+ * @addtogroup threads
+ * @details Threads related APIs and services.
+ *
+ * <h2>Operation mode</h2>
+ * A thread is an abstraction of an independent instructions flow.
+ * In ChibiOS/RT a thread is represented by a "C" function owning
+ * a processor context, state informations and a dedicated stack
+ * area. In this scenario static variables are shared among all
+ * threads while automatic variables are local to the thread.<br>
+ * Operations defined for threads:
+ * - <b>Create</b>, a thread is started on the specified thread
+ * function. This operation is available in multiple variants,
+ * both static and dynamic.
+ * - <b>Exit</b>, a thread terminates by returning from its top
+ * level function or invoking a specific API, the thread can
+ * return a value that can be retrieved by other threads.
+ * - <b>Wait</b>, a thread waits for the termination of another
+ * thread and retrieves its return value.
+ * - <b>Resume</b>, a thread created in suspended state is started.
+ * - <b>Sleep</b>, the execution of a thread is suspended for the
+ * specified amount of time or the specified future absolute time
+ * is reached.
+ * - <b>SetPriority</b>, a thread changes its own priority level.
+ * - <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_USE_WAITEXIT and @p CH_USE_DYNAMIC configuration
+ * options.
+ * @{
+ */
+
+#include "ch.h"
+
+/**
+ * @brief Initializes a thread structure.
+ * @note This is an internal functions, do not use it in application code.
+ *
+ * @param[in] tp pointer to the thread
+ * @param[in] prio the priority level for the new thread
+ * @return The same thread pointer passed as parameter.
+ *
+ * @notapi
+ */
+Thread *_thread_init(Thread *tp, tprio_t prio) {
+
+ tp->p_prio = prio;
+ tp->p_state = THD_STATE_SUSPENDED;
+ tp->p_flags = THD_MEM_MODE_STATIC;
+#if CH_TIME_QUANTUM > 0
+ tp->p_preempt = CH_TIME_QUANTUM;
+#endif
+#if CH_USE_MUTEXES
+ tp->p_realprio = prio;
+ tp->p_mtxlist = NULL;
+#endif
+#if CH_USE_EVENTS
+ tp->p_epending = 0;
+#endif
+#if CH_DBG_THREADS_PROFILING
+ tp->p_time = 0;
+#endif
+#if CH_USE_DYNAMIC
+ tp->p_refs = 1;
+#endif
+#if CH_USE_REGISTRY
+ tp->p_name = NULL;
+ REG_INSERT(tp);
+#endif
+#if CH_USE_WAITEXIT
+ list_init(&tp->p_waiting);
+#endif
+#if CH_USE_MESSAGES
+ queue_init(&tp->p_msgqueue);
+#endif
+#if CH_DBG_ENABLE_STACK_CHECK
+ tp->p_stklimit = (stkalign_t *)(tp + 1);
+#endif
+#if defined(THREAD_EXT_INIT_HOOK)
+ THREAD_EXT_INIT_HOOK(tp);
+#endif
+ return tp;
+}
+
+#if CH_DBG_FILL_THREADS || defined(__DOXYGEN__)
+/**
+ * @brief Memory fill utility.
+ *
+ * @param[in] startp first address to fill
+ * @param[in] endp last address to fill +1
+ * @param[in] v filler value
+ *
+ * @notapi
+ */
+void _thread_memfill(uint8_t *startp, uint8_t *endp, uint8_t v) {
+
+ while (startp < endp)
+ *startp++ = v;
+}
+#endif /* CH_DBG_FILL_THREADS */
+
+/**
+ * @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 THD_STATE_SUSPENDED.
+ * @post The initialized thread can be subsequently started by invoking
+ * @p chThdResume(), @p chThdResumeI() 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] wsp pointer to a working area dedicated to the thread stack
+ * @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 structure allocated for
+ * the thread into the working space area.
+ *
+ * @iclass
+ */
+Thread *chThdCreateI(void *wsp, size_t size,
+ tprio_t prio, tfunc_t pf, void *arg) {
+ /* Thread structure is laid out in the lower part of the thread workspace.*/
+ Thread *tp = wsp;
+
+ chDbgCheckClassI();
+
+ chDbgCheck((wsp != NULL) && (size >= THD_WA_SIZE(0)) &&
+ (prio <= HIGHPRIO) && (pf != NULL),
+ "chThdCreateI");
+ SETUP_CONTEXT(wsp, size, pf, arg);
+ return _thread_init(tp, prio);
+}
+
+/**
+ * @brief Creates a new thread into a static memory area.
+ * @note A thread can terminate by calling @p chThdExit() or by simply
+ * returning from its main function.
+ *
+ * @param[out] wsp pointer to a working area dedicated to the thread stack
+ * @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 structure allocated for
+ * the thread into the working space area.
+ *
+ * @api
+ */
+Thread *chThdCreateStatic(void *wsp, size_t size,
+ tprio_t prio, tfunc_t pf, void *arg) {
+ Thread *tp;
+
+#if CH_DBG_FILL_THREADS
+ _thread_memfill((uint8_t *)wsp,
+ (uint8_t *)wsp + sizeof(Thread),
+ CH_THREAD_FILL_VALUE);
+ _thread_memfill((uint8_t *)wsp + sizeof(Thread),
+ (uint8_t *)wsp + size,
+ CH_STACK_FILL_VALUE);
+#endif
+ chSysLock();
+ chSchWakeupS(tp = chThdCreateI(wsp, size, prio, pf, arg), RDY_OK);
+ chSysUnlock();
+ return tp;
+}
+
+/**
+ * @brief Changes the running thread priority level then reschedules if
+ * necessary.
+ * @note The function returns the real thread priority regardless of the
+ * current priority that could be higher than the real priority
+ * because the priority inheritance mechanism.
+ *
+ * @param[in] newprio the new priority level of the running thread
+ * @return The old priority level.
+ *
+ * @api
+ */
+tprio_t chThdSetPriority(tprio_t newprio) {
+ tprio_t oldprio;
+
+ chDbgCheck(newprio <= HIGHPRIO, "chThdSetPriority");
+
+ chSysLock();
+#if CH_USE_MUTEXES
+ oldprio = currp->p_realprio;
+ if ((currp->p_prio == currp->p_realprio) || (newprio > currp->p_prio))
+ currp->p_prio = newprio;
+ currp->p_realprio = newprio;
+#else
+ oldprio = currp->p_prio;
+ currp->p_prio = newprio;
+#endif
+ chSchRescheduleS();
+ chSysUnlock();
+ return oldprio;
+}
+
+/**
+ * @brief Resumes a suspended thread.
+ * @pre The specified thread pointer must refer to an initialized thread
+ * in the @p THD_STATE_SUSPENDED state.
+ * @post The specified thread is immediately started or put in the ready
+ * list depending on the relative priority levels.
+ * @note Use this function to start threads created with @p chThdCreateI().
+ *
+ * @param[in] tp pointer to the thread
+ * @return The pointer to the thread.
+ *
+ * @api
+ */
+Thread *chThdResume(Thread *tp) {
+
+ chSysLock();
+ chDbgAssert(tp->p_state == THD_STATE_SUSPENDED,
+ "chThdResume(), #1",
+ "thread not in THD_STATE_SUSPENDED state");
+ chSchWakeupS(tp, RDY_OK);
+ chSysUnlock();
+ return tp;
+}
+
+/**
+ * @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 *tp) {
+
+ chSysLock();
+ tp->p_flags |= THD_TERMINATE;
+ chSysUnlock();
+}
+
+/**
+ * @brief Suspends the invoking thread for the specified time.
+ *
+ * @param[in] time the delay in system ticks, the special values are
+ * handled as follow:
+ * - @a TIME_INFINITE the thread enters an infinite sleep
+ * state.
+ * - @a TIME_IMMEDIATE this value is not allowed.
+ * .
+ *
+ * @api
+ */
+void chThdSleep(systime_t time) {
+
+ chDbgCheck(time != TIME_IMMEDIATE, "chThdSleep");
+
+ chSysLock();
+ chThdSleepS(time);
+ chSysUnlock();
+}
+
+/**
+ * @brief Suspends the invoking thread until the system time arrives to the
+ * specified value.
+ *
+ * @param[in] time absolute system time
+ *
+ * @api
+ */
+void chThdSleepUntil(systime_t time) {
+
+ chSysLock();
+ if ((time -= chTimeNow()) > 0)
+ chThdSleepS(time);
+ chSysUnlock();
+}
+
+/**
+ * @brief Yields the time slot.
+ * @details Yields the CPU control to the next thread in the ready list with
+ * equal priority, if any.
+ *
+ * @api
+ */
+void chThdYield(void) {
+
+ chSysLock();
+ chSchDoYieldS();
+ chSysUnlock();
+}
+
+/**
+ * @brief Terminates the current thread.
+ * @details The thread goes in the @p THD_STATE_FINAL state holding the
+ * specified exit status code, other threads can retrieve the
+ * exit status code by invoking the function @p chThdWait().
+ * @post Eventual code after this function will never be executed,
+ * this function never returns. The compiler has no way to
+ * know this so do not assume that the compiler would remove
+ * the dead code.
+ *
+ * @param[in] msg thread exit code
+ *
+ * @api
+ */
+void chThdExit(msg_t msg) {
+
+ chSysLock();
+ chThdExitS(msg);
+ /* The thread never returns here.*/
+}
+
+/**
+ * @brief Terminates the current thread.
+ * @details The thread goes in the @p THD_STATE_FINAL state holding the
+ * specified exit status code, other threads can retrieve the
+ * exit status code by invoking the function @p chThdWait().
+ * @post Eventual code after this function will never be executed,
+ * this function never returns. The compiler has no way to
+ * know this so do not assume that the compiler would remove
+ * the dead code.
+ *
+ * @param[in] msg thread exit code
+ *
+ * @sclass
+ */
+void chThdExitS(msg_t msg) {
+ Thread *tp = currp;
+
+ tp->p_u.exitcode = msg;
+#if defined(THREAD_EXT_EXIT_HOOK)
+ THREAD_EXT_EXIT_HOOK(tp);
+#endif
+#if CH_USE_WAITEXIT
+ while (notempty(&tp->p_waiting))
+ chSchReadyI(list_remove(&tp->p_waiting));
+#endif
+#if CH_USE_REGISTRY
+ /* Static threads are immediately removed from the registry because
+ there is no memory to recover.*/
+ if ((tp->p_flags & THD_MEM_MODE_MASK) == THD_MEM_MODE_STATIC)
+ REG_REMOVE(tp);
+#endif
+ chSchGoSleepS(THD_STATE_FINAL);
+ /* The thread never returns here.*/
+ chDbgAssert(FALSE, "chThdExitS(), #1", "zombies apocalypse");
+}
+
+#if CH_USE_WAITEXIT || defined(__DOXYGEN__)
+/**
+ * @brief Blocks the execution of the invoking thread until the specified
+ * thread terminates then the exit code is returned.
+ * @details This function waits 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_USE_WAITEXIT must be enabled in
+ * order to use this function.
+ * @post Enabling @p chThdWait() requires 2-4 (depending on the
+ * architecture) extra bytes in the @p Thread structure.
+ * @post After invoking @p chThdWait() the thread pointer becomes invalid
+ * and must not be used as parameter for further system calls.
+ * @note If @p CH_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
+ * @return The exit code from the terminated thread.
+ *
+ * @api
+ */
+msg_t chThdWait(Thread *tp) {
+ msg_t msg;
+
+ chDbgCheck(tp != NULL, "chThdWait");
+
+ chSysLock();
+ chDbgAssert(tp != currp, "chThdWait(), #1", "waiting self");
+#if CH_USE_DYNAMIC
+ chDbgAssert(tp->p_refs > 0, "chThdWait(), #2", "not referenced");
+#endif
+ if (tp->p_state != THD_STATE_FINAL) {
+ list_insert(currp, &tp->p_waiting);
+ chSchGoSleepS(THD_STATE_WTEXIT);
+ }
+ msg = tp->p_u.exitcode;
+ chSysUnlock();
+#if CH_USE_DYNAMIC
+ chThdRelease(tp);
+#endif
+ return msg;
+}
+#endif /* CH_USE_WAITEXIT */
+
+/** @} */
diff --git a/os/kernel/src/chvt.c b/os/kernel/src/chvt.c new file mode 100644 index 000000000..a8e3ce499 --- /dev/null +++ b/os/kernel/src/chvt.c @@ -0,0 +1,134 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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 chvt.c
+ * @brief Time and Virtual Timers related code.
+ *
+ * @addtogroup time
+ * @details Time and Virtual Timers related APIs and services.
+ * @{
+ */
+
+#include "ch.h"
+
+/**
+ * @brief Virtual timers delta list header.
+ */
+VTList vtlist;
+
+/**
+ * @brief Virtual Timers initialization.
+ * @note Internal use only.
+ *
+ * @notapi
+ */
+void _vt_init(void) {
+
+ vtlist.vt_next = vtlist.vt_prev = (void *)&vtlist;
+ vtlist.vt_time = (systime_t)-1;
+ vtlist.vt_systime = 0;
+}
+
+/**
+ * @brief Enables a virtual timer.
+ * @note The associated function is invoked from interrupt context.
+ *
+ * @param[out] vtp the @p VirtualTimer structure pointer
+ * @param[in] time the number of ticks before the operation timeouts, the
+ * special values are handled as follow:
+ * - @a TIME_INFINITE is allowed but interpreted as a
+ * normal time specification.
+ * - @a TIME_IMMEDIATE this value is not allowed.
+ * .
+ * @param[in] vtfunc the timer callback function. After invoking the
+ * callback the timer is disabled and the structure can
+ * be disposed or reused.
+ * @param[in] par a parameter that will be passed to the callback
+ * function
+ *
+ * @iclass
+ */
+void chVTSetI(VirtualTimer *vtp, systime_t time, vtfunc_t vtfunc, void *par) {
+ VirtualTimer *p;
+
+ chDbgCheckClassI();
+ chDbgCheck((vtp != NULL) && (vtfunc != NULL) && (time != TIME_IMMEDIATE),
+ "chVTSetI");
+
+ vtp->vt_par = par;
+ vtp->vt_func = vtfunc;
+ p = vtlist.vt_next;
+ while (p->vt_time < time) {
+ time -= p->vt_time;
+ p = p->vt_next;
+ }
+
+ vtp->vt_prev = (vtp->vt_next = p)->vt_prev;
+ vtp->vt_prev->vt_next = p->vt_prev = vtp;
+ vtp->vt_time = time;
+ if (p != (void *)&vtlist)
+ p->vt_time -= time;
+}
+
+/**
+ * @brief Disables a Virtual Timer.
+ * @note The timer MUST be active when this function is invoked.
+ *
+ * @param[in] vtp the @p VirtualTimer structure pointer
+ *
+ * @iclass
+ */
+void chVTResetI(VirtualTimer *vtp) {
+
+ chDbgCheckClassI();
+ chDbgCheck(vtp != NULL, "chVTResetI");
+ chDbgAssert(vtp->vt_func != NULL,
+ "chVTResetI(), #1",
+ "timer not set or already triggered");
+
+ if (vtp->vt_next != (void *)&vtlist)
+ vtp->vt_next->vt_time += vtp->vt_time;
+ vtp->vt_prev->vt_next = vtp->vt_next;
+ vtp->vt_next->vt_prev = vtp->vt_prev;
+ vtp->vt_func = (vtfunc_t)NULL;
+}
+
+/**
+ * @brief Checks if the current system time is within the specified time
+ * window.
+ * @note When start==end then the function returns always true because the
+ * whole time range is specified.
+ *
+ * @param[in] start the start of the time window (inclusive)
+ * @param[in] end the end of the time window (non inclusive)
+ * @retval TRUE current time within the specified time window.
+ * @retval FALSE current time not within the specified time window.
+ *
+ * @api
+ */
+bool_t chTimeIsWithin(systime_t start, systime_t end) {
+
+ systime_t time = chTimeNow();
+ return end > start ? (time >= start) && (time < end) :
+ (time >= start) || (time < end);
+}
+
+/** @} */
diff --git a/os/kernel/templates/chconf.h b/os/kernel/templates/chconf.h new file mode 100644 index 000000000..ae54d3edf --- /dev/null +++ b/os/kernel/templates/chconf.h @@ -0,0 +1,535 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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/chconf.h
+ * @brief Configuration file template.
+ * @details A copy of this file must be placed in each project directory, it
+ * contains the application specific kernel settings.
+ *
+ * @addtogroup config
+ * @details Kernel related settings and hooks.
+ * @{
+ */
+
+#ifndef _CHCONF_H_
+#define _CHCONF_H_
+
+/*===========================================================================*/
+/**
+ * @name Kernel parameters and options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief System tick frequency.
+ * @details Frequency of the system timer that drives the system ticks. This
+ * setting also defines the system tick time unit.
+ */
+#if !defined(CH_FREQUENCY) || defined(__DOXYGEN__)
+#define CH_FREQUENCY 1000
+#endif
+
+/**
+ * @brief Round robin interval.
+ * @details This constant is the number of system ticks allowed for the
+ * threads before preemption occurs. Setting this value to zero
+ * disables the preemption for threads with equal priority and the
+ * round robin becomes cooperative. Note that higher priority
+ * threads can still preempt, the kernel is always preemptive.
+ *
+ * @note Disabling the round robin preemption makes the kernel more compact
+ * and generally faster.
+ */
+#if !defined(CH_TIME_QUANTUM) || defined(__DOXYGEN__)
+#define CH_TIME_QUANTUM 20
+#endif
+
+/**
+ * @brief Managed RAM size.
+ * @details Size of the RAM area to be managed by the OS. If set to zero
+ * then the whole available RAM is used. The core memory is made
+ * available to the heap allocator and/or can be used directly through
+ * the simplified core memory allocator.
+ *
+ * @note In order to let the OS manage the whole RAM the linker script must
+ * provide the @p __heap_base__ and @p __heap_end__ symbols.
+ * @note Requires @p CH_USE_MEMCORE.
+ */
+#if !defined(CH_MEMCORE_SIZE) || defined(__DOXYGEN__)
+#define CH_MEMCORE_SIZE 0
+#endif
+
+/**
+ * @brief Idle thread automatic spawn suppression.
+ * @details When this option is activated the function @p chSysInit()
+ * does not spawn the idle thread automatically. The application has
+ * then the responsibility to do one of the following:
+ * - Spawn a custom idle thread at priority @p IDLEPRIO.
+ * - Change the main() thread priority to @p IDLEPRIO then enter
+ * an endless loop. In this scenario the @p main() thread acts as
+ * the idle thread.
+ * .
+ * @note Unless an idle thread is spawned the @p main() thread must not
+ * enter a sleep state.
+ */
+#if !defined(CH_NO_IDLE_THREAD) || defined(__DOXYGEN__)
+#define CH_NO_IDLE_THREAD FALSE
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Performance options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief OS optimization.
+ * @details If enabled then time efficient rather than space efficient code
+ * is used when two possible implementations exist.
+ *
+ * @note This is not related to the compiler optimization options.
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_OPTIMIZE_SPEED) || defined(__DOXYGEN__)
+#define CH_OPTIMIZE_SPEED TRUE
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Subsystem options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief Threads registry APIs.
+ * @details If enabled then the registry APIs are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_USE_REGISTRY) || defined(__DOXYGEN__)
+#define CH_USE_REGISTRY TRUE
+#endif
+
+/**
+ * @brief Threads synchronization APIs.
+ * @details If enabled then the @p chThdWait() function is included in
+ * the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_USE_WAITEXIT) || defined(__DOXYGEN__)
+#define CH_USE_WAITEXIT TRUE
+#endif
+
+/**
+ * @brief Semaphores APIs.
+ * @details If enabled then the Semaphores APIs are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_USE_SEMAPHORES) || defined(__DOXYGEN__)
+#define CH_USE_SEMAPHORES TRUE
+#endif
+
+/**
+ * @brief Semaphores queuing mode.
+ * @details If enabled then the threads are enqueued on semaphores by
+ * priority rather than in FIFO order.
+ *
+ * @note The default is @p FALSE. Enable this if you have special requirements.
+ * @note Requires @p CH_USE_SEMAPHORES.
+ */
+#if !defined(CH_USE_SEMAPHORES_PRIORITY) || defined(__DOXYGEN__)
+#define CH_USE_SEMAPHORES_PRIORITY FALSE
+#endif
+
+/**
+ * @brief Atomic semaphore API.
+ * @details If enabled then the semaphores the @p chSemSignalWait() API
+ * is included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ * @note Requires @p CH_USE_SEMAPHORES.
+ */
+#if !defined(CH_USE_SEMSW) || defined(__DOXYGEN__)
+#define CH_USE_SEMSW TRUE
+#endif
+
+/**
+ * @brief Mutexes APIs.
+ * @details If enabled then the mutexes APIs are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_USE_MUTEXES) || defined(__DOXYGEN__)
+#define CH_USE_MUTEXES TRUE
+#endif
+
+/**
+ * @brief Conditional Variables APIs.
+ * @details If enabled then the conditional variables APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ * @note Requires @p CH_USE_MUTEXES.
+ */
+#if !defined(CH_USE_CONDVARS) || defined(__DOXYGEN__)
+#define CH_USE_CONDVARS TRUE
+#endif
+
+/**
+ * @brief Conditional Variables APIs with timeout.
+ * @details If enabled then the conditional variables APIs with timeout
+ * specification are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ * @note Requires @p CH_USE_CONDVARS.
+ */
+#if !defined(CH_USE_CONDVARS_TIMEOUT) || defined(__DOXYGEN__)
+#define CH_USE_CONDVARS_TIMEOUT TRUE
+#endif
+
+/**
+ * @brief Events Flags APIs.
+ * @details If enabled then the event flags APIs are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_USE_EVENTS) || defined(__DOXYGEN__)
+#define CH_USE_EVENTS TRUE
+#endif
+
+/**
+ * @brief Events Flags APIs with timeout.
+ * @details If enabled then the events APIs with timeout specification
+ * are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ * @note Requires @p CH_USE_EVENTS.
+ */
+#if !defined(CH_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__)
+#define CH_USE_EVENTS_TIMEOUT TRUE
+#endif
+
+/**
+ * @brief Synchronous Messages APIs.
+ * @details If enabled then the synchronous messages APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_USE_MESSAGES) || defined(__DOXYGEN__)
+#define CH_USE_MESSAGES TRUE
+#endif
+
+/**
+ * @brief Synchronous Messages queuing mode.
+ * @details If enabled then messages are served by priority rather than in
+ * FIFO order.
+ *
+ * @note The default is @p FALSE. Enable this if you have special requirements.
+ * @note Requires @p CH_USE_MESSAGES.
+ */
+#if !defined(CH_USE_MESSAGES_PRIORITY) || defined(__DOXYGEN__)
+#define CH_USE_MESSAGES_PRIORITY FALSE
+#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_USE_SEMAPHORES.
+ */
+#if !defined(CH_USE_MAILBOXES) || defined(__DOXYGEN__)
+#define CH_USE_MAILBOXES TRUE
+#endif
+
+/**
+ * @brief I/O Queues APIs.
+ * @details If enabled then the I/O queues APIs are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_USE_QUEUES) || defined(__DOXYGEN__)
+#define CH_USE_QUEUES 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_USE_MEMCORE) || defined(__DOXYGEN__)
+#define CH_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.
+ * @note Requires @p CH_USE_MEMCORE and either @p CH_USE_MUTEXES or
+ * @p CH_USE_SEMAPHORES.
+ * @note Mutexes are recommended.
+ */
+#if !defined(CH_USE_HEAP) || defined(__DOXYGEN__)
+#define CH_USE_HEAP TRUE
+#endif
+
+/**
+ * @brief C-runtime allocator.
+ * @details If enabled the the heap allocator APIs just wrap the C-runtime
+ * @p malloc() and @p free() functions.
+ *
+ * @note The default is @p FALSE.
+ * @note Requires @p CH_USE_HEAP.
+ * @note The C-runtime may or may not require @p CH_USE_MEMCORE, see the
+ * appropriate documentation.
+ */
+#if !defined(CH_USE_MALLOC_HEAP) || defined(__DOXYGEN__)
+#define CH_USE_MALLOC_HEAP FALSE
+#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_USE_MEMPOOLS) || defined(__DOXYGEN__)
+#define CH_USE_MEMPOOLS TRUE
+#endif
+
+/**
+ * @brief Dynamic Threads APIs.
+ * @details If enabled then the dynamic threads creation APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ * @note Requires @p CH_USE_WAITEXIT.
+ * @note Requires @p CH_USE_HEAP and/or @p CH_USE_MEMPOOLS.
+ */
+#if !defined(CH_USE_DYNAMIC) || defined(__DOXYGEN__)
+#define CH_USE_DYNAMIC TRUE
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Debug options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief Debug option, system state check.
+ * @details If enabled the correct call protocol for system APIs is checked
+ * at runtime.
+ *
+ * @note The default is @p FALSE.
+ */
+#if !defined(CH_DBG_SYSTEM_STATE_CHECK) || defined(__DOXYGEN__)
+#define CH_DBG_SYSTEM_STATE_CHECK FALSE
+#endif
+
+/**
+ * @brief Debug option, parameters checks.
+ * @details If enabled then the checks on the API functions input
+ * parameters are activated.
+ *
+ * @note The default is @p FALSE.
+ */
+#if !defined(CH_DBG_ENABLE_CHECKS) || defined(__DOXYGEN__)
+#define CH_DBG_ENABLE_CHECKS FALSE
+#endif
+
+/**
+ * @brief Debug option, consistency checks.
+ * @details If enabled then all the assertions in the kernel code are
+ * activated. This includes consistency checks inside the kernel,
+ * runtime anomalies and port-defined checks.
+ *
+ * @note The default is @p FALSE.
+ */
+#if !defined(CH_DBG_ENABLE_ASSERTS) || defined(__DOXYGEN__)
+#define CH_DBG_ENABLE_ASSERTS FALSE
+#endif
+
+/**
+ * @brief Debug option, trace buffer.
+ * @details If enabled then the context switch circular trace buffer is
+ * activated.
+ *
+ * @note The default is @p FALSE.
+ */
+#if !defined(CH_DBG_ENABLE_TRACE) || defined(__DOXYGEN__)
+#define CH_DBG_ENABLE_TRACE FALSE
+#endif
+
+/**
+ * @brief Debug option, stack checks.
+ * @details If enabled then a runtime stack check is performed.
+ *
+ * @note The default is @p FALSE.
+ * @note The stack check is performed in a architecture/port dependent way.
+ * It may not be implemented or some ports.
+ * @note The default failure mode is to halt the system with the global
+ * @p panic_msg variable set to @p NULL.
+ */
+#if !defined(CH_DBG_ENABLE_STACK_CHECK) || defined(__DOXYGEN__)
+#define CH_DBG_ENABLE_STACK_CHECK FALSE
+#endif
+
+/**
+ * @brief Debug option, stacks initialization.
+ * @details If enabled then the threads working area is filled with a byte
+ * value when a thread is created. This can be useful for the
+ * runtime measurement of the used stack.
+ *
+ * @note The default is @p FALSE.
+ */
+#if !defined(CH_DBG_FILL_THREADS) || defined(__DOXYGEN__)
+#define CH_DBG_FILL_THREADS FALSE
+#endif
+
+/**
+ * @brief Debug option, threads profiling.
+ * @details If enabled then a field is added to the @p Thread structure that
+ * counts the system ticks occurred while executing the thread.
+ *
+ * @note The default is @p TRUE.
+ * @note This debug option is defaulted to TRUE because it is required by
+ * some test cases into the test suite.
+ */
+#if !defined(CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__)
+#define CH_DBG_THREADS_PROFILING TRUE
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Kernel hooks
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief Threads descriptor structure extension.
+ * @details User fields added to the end of the @p Thread structure.
+ */
+#if !defined(THREAD_EXT_FIELDS) || defined(__DOXYGEN__)
+#define THREAD_EXT_FIELDS \
+ /* Add threads custom fields here.*/
+#endif
+
+/**
+ * @brief Threads initialization hook.
+ * @details User initialization code added to the @p chThdInit() API.
+ *
+ * @note It is invoked from within @p chThdInit() and implicitly from all
+ * the threads creation APIs.
+ */
+#if !defined(THREAD_EXT_INIT_HOOK) || defined(__DOXYGEN__)
+#define THREAD_EXT_INIT_HOOK(tp) { \
+ /* Add threads initialization code here.*/ \
+}
+#endif
+
+/**
+ * @brief Threads finalization hook.
+ * @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.
+ */
+#if !defined(THREAD_EXT_EXIT_HOOK) || defined(__DOXYGEN__)
+#define THREAD_EXT_EXIT_HOOK(tp) { \
+ /* Add threads finalization code here.*/ \
+}
+#endif
+
+/**
+ * @brief Context switch hook.
+ * @details This hook is invoked just before switching between threads.
+ */
+#if !defined(THREAD_CONTEXT_SWITCH_HOOK) || defined(__DOXYGEN__)
+#define THREAD_CONTEXT_SWITCH_HOOK(ntp, otp) { \
+ /* System halt code here.*/ \
+}
+#endif
+
+/**
+ * @brief Idle Loop hook.
+ * @details This hook is continuously invoked by the idle thread loop.
+ */
+#if !defined(IDLE_LOOP_HOOK) || defined(__DOXYGEN__)
+#define IDLE_LOOP_HOOK() { \
+ /* Idle loop code here.*/ \
+}
+#endif
+
+/**
+ * @brief System tick event hook.
+ * @details This hook is invoked in the system tick handler immediately
+ * after processing the virtual timers queue.
+ */
+#if !defined(SYSTEM_TICK_EVENT_HOOK) || defined(__DOXYGEN__)
+#define SYSTEM_TICK_EVENT_HOOK() { \
+ /* System tick event code here.*/ \
+}
+#endif
+
+/**
+ * @brief System halt hook.
+ * @details This hook is invoked in case to a system halting error before
+ * the system is halted.
+ */
+#if !defined(SYSTEM_HALT_HOOK) || defined(__DOXYGEN__)
+#define SYSTEM_HALT_HOOK() { \
+ /* System halt code here.*/ \
+}
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/* Port-specific settings (override port settings defaulted in chcore.h). */
+/*===========================================================================*/
+
+#endif /* _CHCONF_H_ */
+
+/** @} */
diff --git a/os/kernel/templates/chcore.c b/os/kernel/templates/chcore.c new file mode 100644 index 000000000..7639d9dd7 --- /dev/null +++ b/os/kernel/templates/chcore.c @@ -0,0 +1,134 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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"
+
+/**
+ * @brief Port-related initialization code.
+ * @note This function is usually empty.
+ */
+void port_init(void) {
+}
+
+/**
+ * @brief Kernel-lock action.
+ * @details Usually this function just disables interrupts but may perform more
+ * actions.
+ */
+void port_lock(void) {
+}
+
+/**
+ * @brief Kernel-unlock action.
+ * @details Usually this function just enables interrupts but may perform more
+ * actions.
+ */
+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.
+ */
+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.
+ */
+void port_unlock_from_isr(void) {
+}
+
+/**
+ * @brief Disables all the interrupt sources.
+ * @note Of course non-maskable interrupt sources are not included.
+ */
+void port_disable(void) {
+}
+
+/**
+ * @brief Disables the interrupt sources below kernel-level priority.
+ * @note Interrupt sources above kernel level remains enabled.
+ */
+void port_suspend(void) {
+}
+
+/**
+ * @brief Enables all the interrupt sources.
+ */
+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.
+ */
+void port_wait_for_interrupt(void) {
+}
+
+/**
+ * @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).
+ */
+void port_halt(void) {
+
+ port_disable();
+ while (TRUE) {
+ }
+}
+
+/**
+ * @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 *ntp, Thread *otp) {
+}
+
+/** @} */
diff --git a/os/kernel/templates/chcore.h b/os/kernel/templates/chcore.h new file mode 100644 index 000000000..f73b3b0c8 --- /dev/null +++ b/os/kernel/templates/chcore.h @@ -0,0 +1,213 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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_
+
+/*===========================================================================*/
+/* Port constants. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Port macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Port configurable parameters. */
+/*===========================================================================*/
+
+/**
+ * @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 0
+#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 intctx and
+ * @p extctx is known to be zero.
+ */
+#ifndef PORT_INT_REQUIRED_STACK
+#define PORT_INT_REQUIRED_STACK 0
+#endif
+
+/*===========================================================================*/
+/* Port derived parameters. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Port exported info. */
+/*===========================================================================*/
+
+/**
+ * @brief Unique macro for the implemented architecture.
+ */
+#define CH_ARCHITECTURE_XXX
+
+/**
+ * @brief Name of the implemented architecture.
+ */
+#define CH_ARCHITECTURE_NAME ""
+
+/**
+ * @brief Name of the architecture variant (optional).
+ */
+#define CH_ARCHITECTURE_VARIANT_NAME ""
+
+/**
+ * @brief Name of the compiler supported by this port.
+ */
+#define CH_COMPILER_NAME "GCC"
+
+/**
+ * @brief Port-specific information string.
+ */
+#define CH_PORT_INFO ""
+
+/*===========================================================================*/
+/* Port implementation part. */
+/*===========================================================================*/
+
+/**
+ * @brief Base type for stack and memory alignment.
+ */
+typedef uint8_t stkalign_t;
+
+/**
+ * @brief Interrupt saved context.
+ * @details This structure represents the stack frame saved during a
+ * preemption-capable interrupt handler.
+ */
+struct extctx {
+};
+
+/**
+ * @brief System saved context.
+ * @details This structure represents the inner stack frame during a context
+ * switching.
+ */
+struct intctx {
+};
+
+/**
+ * @brief Platform dependent part of the @p Thread structure.
+ * @details This structure usually contains just the saved stack pointer
+ * defined as a pointer to a @p intctx structure.
+ */
+struct context {
+ struct intctx *sp;
+};
+
+/**
+ * @brief Platform dependent part of the @p chThdCreateI() API.
+ * @details This code usually setup the context switching frame represented
+ * by an @p intctx structure.
+ */
+#define SETUP_CONTEXT(workspace, wsize, pf, arg) { \
+}
+
+/**
+ * @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 THD_WA_SIZE(n) STACK_ALIGN(sizeof(Thread) + \
+ sizeof(struct intctx) + \
+ sizeof(struct extctx) + \
+ (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[THD_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.
+ */
+#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.
+ * @note Not all architectures support fast interrupts, in this case this
+ * macro must be omitted.
+ */
+#define PORT_FAST_IRQ_HANDLER(id) void id(void)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void port_init(void);
+ void port_lock(void);
+ void port_unlock(void);
+ void port_lock_from_isr(void);
+ void port_unlock_from_isr(void);
+ void port_disable(void);
+ void port_suspend(void);
+ void port_enable(void);
+ void port_wait_for_interrupt(void);
+ void port_halt(void);
+ void port_switch(Thread *ntp, Thread *otp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CHCORE_H_ */
+
+/** @} */
diff --git a/os/kernel/templates/chtypes.h b/os/kernel/templates/chtypes.h new file mode 100644 index 000000000..52efee447 --- /dev/null +++ b/os/kernel/templates/chtypes.h @@ -0,0 +1,130 @@ +/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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/RT 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
+ * @details System types and macros.
+ * @{
+ */
+
+#ifndef _CHTYPES_H_
+#define _CHTYPES_H_
+
+#define __need_NULL
+#define __need_size_t
+#include <stddef.h>
+
+#if !defined(_STDINT_H) && !defined(__STDINT_H_)
+#include <stdint.h>
+#endif
+
+/**
+ * @brief Boolean, recommended the fastest signed.
+ */
+typedef int32_t bool_t;
+
+/**
+ * @brief Thread mode flags, uint8_t is ok.
+ */
+typedef uint8_t tmode_t;
+
+/**
+ * @brief Thread state, uint8_t is ok.
+ */
+typedef uint8_t tstate_t;
+
+/**
+ * @brief Thread references counter, uint8_t is ok.
+ */
+typedef uint8_t trefs_t;
+
+/**
+ * @brief Priority, use the fastest unsigned type.
+ */
+typedef uint32_t tprio_t;
+
+/**
+ * @brief Message, use signed pointer equivalent.
+ */
+typedef int32_t msg_t;
+
+/**
+ * @brief Event Id, use fastest signed.
+ */
+typedef int32_t eventid_t;
+
+/**
+ * @brief Event Mask, recommended fastest unsigned.
+ */
+typedef uint32_t eventmask_t;
+
+/**
+ * @brief System Time, recommended fastest unsigned.
+ */
+typedef uint32_t systime_t;
+
+/**
+ * @brief Counter, recommended fastest signed.
+ */
+typedef int32_t cnt_t;
+
+/**
+ * @brief Inline function modifier.
+ */
+#define INLINE inline
+
+/**
+ * @brief ROM constant modifier.
+ * @note This is required because some compilers require a custom keyword,
+ * usually this macro is just set to "const" for the GCC compiler.
+ * @note This macro is not used to place constants in different address
+ * spaces (like AVR requires for example) because it is assumed that
+ * a pointer to a ROMCONST constant is compatible with a pointer
+ * to a normal variable. It is just like the "const" keyword but
+ * requires that the constant is placed in ROM if the architecture
+ * supports it.
+ */
+#define ROMCONST const
+
+/**
+ * @brief Packed structure modifier (within).
+ */
+#define PACK_STRUCT_STRUCT __attribute__((packed))
+
+/**
+ * @brief Packed structure modifier (before).
+ */
+#define PACK_STRUCT_BEGIN
+
+/**
+ * @brief Packed structure modifier (after).
+ */
+#define PACK_STRUCT_END
+
+#endif /* _CHTYPES_H_ */
+
+/** @} */
|