Add software

This commit is contained in:
RocketGod
2022-09-22 09:26:57 -07:00
parent fee0ab05fd
commit 957ea3d712
4511 changed files with 1943182 additions and 0 deletions

View File

@ -0,0 +1,150 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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.6.8"
/**
* @name Kernel version
* @{
*/
/**
* @brief Kernel version major number.
*/
#define CH_KERNEL_MAJOR 2
/**
* @brief Kernel version minor number.
*/
#define CH_KERNEL_MINOR 6
/**
* @brief Kernel version patch number.
*/
#define CH_KERNEL_PATCH 8
/** @} */
/**
* @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_ */
/** @} */

View File

@ -0,0 +1,258 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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 chBSemInit().
*
* @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_ */
/** @} */

View File

@ -0,0 +1,98 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/*
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_ */
/** @} */

View File

@ -0,0 +1,254 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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_ */
/** @} */

View File

@ -0,0 +1,75 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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_ */
/** @} */

View File

@ -0,0 +1,212 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/*
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 eventmask_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[out] 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_ */
/** @} */

View File

@ -0,0 +1,172 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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_ */
/** @} */

View File

@ -0,0 +1,100 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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_ */
/** @} */

View File

@ -0,0 +1,94 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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_ */

View File

@ -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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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_ */
/** @} */

View File

@ -0,0 +1,170 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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_ */
/** @} */

View File

@ -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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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_ */
/** @} */

View File

@ -0,0 +1,141 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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_ */
/** @} */

View File

@ -0,0 +1,92 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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_ */
/** @} */

View File

@ -0,0 +1,103 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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_ */
/** @} */

View File

@ -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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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_ */
/** @} */

View File

@ -0,0 +1,137 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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_ */
/** @} */

View File

@ -0,0 +1,244 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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_ */
/** @} */

View File

@ -0,0 +1,125 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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_ */
/** @} */

View File

@ -0,0 +1,154 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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 BaseSequentialStream 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 BaseSequentialStream 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_ */
/** @} */

View File

@ -0,0 +1,254 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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_ */
/** @} */

View File

@ -0,0 +1,387 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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 0 termination request not pending.
* @retval !0 termination request 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_ */
/** @} */

View File

@ -0,0 +1,262 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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)(((((uint32_t)(msec)) * ((uint32_t)CH_FREQUENCY) - 1UL) / \
1000UL) + 1UL))
/**
* @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)(((((uint32_t)(usec)) * ((uint32_t)CH_FREQUENCY) - 1UL) / \
1000000UL) + 1UL))
/** @} */
/**
* @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)
/**
* @brief Returns the elapsed time since the specified start time.
*
* @param[in] start start time
* @return The elapsed time.
*
* @api
*/
#define chTimeElapsedSince(start) (chTimeNow() - (start))
/**
* @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
*/
#define chTimeIsWithin(start, end) \
(chTimeElapsedSince(start) < ((end) - (start)))
/** @} */
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);
#ifdef __cplusplus
}
#endif
#endif /* _CHVT_H_ */
/** @} */

View File

@ -0,0 +1,27 @@
# 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.
set(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
set(KERNINC
${CHIBIOS}/os/kernel/include
)

View File

@ -0,0 +1,185 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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
*/
/**
* @defgroup core Port
* @ingroup kernel
*/

View File

@ -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

View File

@ -0,0 +1,292 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/*
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 */
/** @} */

View File

@ -0,0 +1,278 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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 */
/** @} */

View File

@ -0,0 +1,211 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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 */
/** @} */

View File

@ -0,0 +1,555 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/*
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[out] 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.
*
* @api
*/
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 & (m - 1);
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 & (m - 1);
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 */
/** @} */

View File

@ -0,0 +1,325 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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 */
/** @} */

View File

@ -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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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 */
/** @} */

View File

@ -0,0 +1,383 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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 */
/** @} */

View File

@ -0,0 +1,138 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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 */
/** @} */

View File

@ -0,0 +1,180 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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 */
/** @} */

View File

@ -0,0 +1,139 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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 */
/** @} */

View File

@ -0,0 +1,400 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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 */
/** @} */

View File

@ -0,0 +1,438 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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[in] 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 */
/** @} */

View File

@ -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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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 */
/** @} */

View File

@ -0,0 +1,386 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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);
__attribute__ ((fallthrough));
/* 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) */
/** @} */

View File

@ -0,0 +1,400 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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 || defined(__DOXYGEN__)
/**
* @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 */
/** @} */

View File

@ -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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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,
(void *)_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
}
/** @} */

View File

@ -0,0 +1,443 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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 */
/** @} */

View File

@ -0,0 +1,121 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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;
}
/** @} */

View File

@ -0,0 +1,542 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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) { \
/* Context switch 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_ */
/** @} */

View File

@ -0,0 +1,141 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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) {
}
/** @} */

View File

@ -0,0 +1,220 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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_ */
/** @} */

View File

@ -0,0 +1,137 @@
/*
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @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_ */
/** @} */