aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2008-07-22 09:55:51 +0000
committergdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2008-07-22 09:55:51 +0000
commit49c3629538ee20a1df4ee5bbe664464e4904db5d (patch)
tree5c3379181ca4b45af5c1e8b2dde0e596e2220fcf
parent71a1820c4a0be292590ed63c284539a68cd22fbb (diff)
downloadChibiOS-49c3629538ee20a1df4ee5bbe664464e4904db5d.tar.gz
ChibiOS-49c3629538ee20a1df4ee5bbe664464e4904db5d.tar.bz2
ChibiOS-49c3629538ee20a1df4ee5bbe664464e4904db5d.zip
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@346 35acf78f-673a-0410-8e92-d51de3d6d3f4
-rw-r--r--ports/ARMCM3-STM32F103/stm32_serial.c398
-rw-r--r--ports/ARMCM3/chcore.c319
-rw-r--r--ports/ARMCM3/chcore.h246
-rw-r--r--ports/ARMCM3/crt0.s187
-rw-r--r--readme.txt6
-rw-r--r--src/chinit.c167
-rw-r--r--src/chmtx.c503
-rw-r--r--src/chschd.c408
-rw-r--r--src/chthreads.c569
-rw-r--r--src/include/queues.h368
-rw-r--r--src/include/scheduler.h162
-rw-r--r--src/include/threads.h483
12 files changed, 1949 insertions, 1867 deletions
diff --git a/ports/ARMCM3-STM32F103/stm32_serial.c b/ports/ARMCM3-STM32F103/stm32_serial.c
index 148453b48..fbb1775c9 100644
--- a/ports/ARMCM3-STM32F103/stm32_serial.c
+++ b/ports/ARMCM3-STM32F103/stm32_serial.c
@@ -1,198 +1,200 @@
-/*
- ChibiOS/RT - Copyright (C) 2006-2007 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/>.
-*/
-
-#include <ch.h>
-
-#include "board.h"
-#include "nvic.h"
-#include "stm32_serial.h"
-#include "stm32lib/stm32f10x_nvic.h"
-
-#ifdef USE_USART1
-FullDuplexDriver COM1;
-static uint8_t ib1[SERIAL_BUFFERS_SIZE];
-static uint8_t ob1[SERIAL_BUFFERS_SIZE];
-#endif
-
-#ifdef USE_USART2
-FullDuplexDriver COM2;
-static uint8_t ib2[SERIAL_BUFFERS_SIZE];
-static uint8_t ob2[SERIAL_BUFFERS_SIZE];
-#endif
-
-#ifdef USE_USART3
-FullDuplexDriver COM3;
-static uint8_t ib3[SERIAL_BUFFERS_SIZE];
-static uint8_t ob3[SERIAL_BUFFERS_SIZE];
-#endif
-
-static void SetError(uint16_t sr, FullDuplexDriver *com) {
- dflags_t sts = 0;
-
- if (sr & SR_ORE)
- sts |= SD_OVERRUN_ERROR;
- if (sr & SR_PE)
- sts |= SD_PARITY_ERROR;
- if (sr & SR_FE)
- sts |= SD_FRAMING_ERROR;
- if (sr & SR_LBD)
- sts |= SD_BREAK_DETECTED;
- chSysLock();
- chFDDAddFlagsI(com, sts);
- chSysUnlock();
-}
-
-static void ServeInterrupt(USART_TypeDef *u, FullDuplexDriver *com) {
- uint16_t sr = u->SR;
-
- if (sr & (SR_ORE | SR_FE | SR_PE | SR_LBD))
- SetError(sr, com);
- if (sr & SR_RXNE) {
- chSysLock();
- chFDDIncomingDataI(com, u->DR);
- chSysUnlock();
- }
- if (sr & SR_TXE) {
- chSysLock();
- msg_t b = chFDDRequestDataI(com);
- chSysUnlock();
- if (b < Q_OK)
- u->CR1 &= ~CR1_TXEIE;
- else
- u->DR = b;
- }
-}
-
-#ifdef USE_USART1
-/*
- * USART1 IRQ service routine.
- */
-void VectorD4(void) {
-
- chSysIRQEnterI();
- ServeInterrupt(USART1, &COM1);
- chSysIRQExitI();
-}
-
-/*
- * Invoked by the high driver when one or more bytes are inserted in the
- * output queue.
- */
-static void OutNotify1(void) {
-
- USART1->CR1 |= CR1_TXEIE;
-}
-#endif
-
-#ifdef USE_USART2
-/*
- * USART2 IRQ service routine.
- */
-void VectorD8(void) {
-
- chSysIRQEnterI();
- ServeInterrupt(USART2, &COM2);
- chSysIRQExitI();
-}
-
-/*
- * Invoked by the high driver when one or more bytes are inserted in the
- * output queue.
- */
-static void OutNotify2(void) {
-
- USART2->CR1 |= CR1_TXEIE;
-}
-#endif
-
-#ifdef USE_USART3
-/*
- * USART3 IRQ service routine.
- */
-void VectorDC(void) {
-
- chSysIRQEnterI();
- ServeInterrupt(USART3, &COM3);
- chSysIRQExitI();
-}
-
-/*
- * Invoked by the high driver when one or more bytes are inserted in the
- * output queue.
- */
-static void OutNotify3(void) {
-
- USART3->CR1 |= CR1_TXEIE;
-}
-#endif
-
-/*
- * USART setup, must be invoked with interrupts disabled.
- * NOTE: Does not reset I/O queues.
- */
-void SetUSARTI(USART_TypeDef *u, uint32_t speed, uint16_t cr1,
- uint16_t cr2, uint16_t cr3) {
-
- /*
- * Baud rate setting.
- */
- if (u == USART1)
- u->BRR = APB2CLK / speed;
- else
- u->BRR = APB1CLK / speed;
-
- /*
- * Note that some bits are enforced.
- */
- u->CR1 = cr1 | CR1_UE | CR1_PEIE | CR1_RXNEIE | CR1_TE | CR1_RE;
- u->CR2 = cr2;
- u->CR3 = cr3 | CR3_EIE;
-}
-
-/*
- * Serial subsystem initialization.
- * NOTE: Handshake pins are not switched to their function because they may have
- * another use. Enable them externally if needed.
- */
-void InitSerial(uint32_t prio1, uint32_t prio2, uint32_t prio3) {
-
-#ifdef USE_USART1
- chFDDInit(&COM1, ib1, sizeof ib1, NULL, ob1, sizeof ob1, OutNotify1);
- RCC->APB2ENR |= 0x00004000;
- SetUSARTI(USART1, 38400, 0, CR2_STOP1_BITS | CR2_LINEN, 0);
- GPIOA->CRH = (GPIOA->CRH & 0xFFFFF00F) | 0x000004B0;
- NVICEnableVector(USART1_IRQChannel, prio1);
-#endif
-
-#ifdef USE_USART2
- chFDDInit(&COM2, ib2, sizeof ib2, NULL, ob2, sizeof ob2, OutNotify2);
- RCC->APB1ENR |= 0x00020000;
- SetUSARTI(USART2, 38400, 0, CR2_STOP1_BITS | CR2_LINEN, 0);
- GPIOA->CRL = (GPIOA->CRL & 0xFFFF00FF) | 0x00004B00;
- NVICEnableVector(USART2_IRQChannel, prio2);
-#endif
-
-#ifdef USE_USART3
- chFDDInit(&COM3, ib3, sizeof ib3, NULL, ob3, sizeof ob3, OutNotify3);
- RCC->APB1ENR |= 0x00040000;
- SetUSARTI(USART3, 38400, 0, CR2_STOP1_BITS | CR2_LINEN, 0);
- GPIOB->CRH = (GPIOB->CRH & 0xFFFF00FF) | 0x00004B00;
- NVICEnableVector(USART3_IRQChannel, prio3);
-#endif
-}
+/*
+ ChibiOS/RT - Copyright (C) 2006-2007 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/>.
+*/
+
+#include <ch.h>
+
+#include "board.h"
+#include "nvic.h"
+#include "stm32_serial.h"
+#include "stm32lib/stm32f10x_nvic.h"
+
+#define USART_BITRATE (38400)
+
+#ifdef USE_USART1
+FullDuplexDriver COM1;
+static uint8_t ib1[SERIAL_BUFFERS_SIZE];
+static uint8_t ob1[SERIAL_BUFFERS_SIZE];
+#endif
+
+#ifdef USE_USART2
+FullDuplexDriver COM2;
+static uint8_t ib2[SERIAL_BUFFERS_SIZE];
+static uint8_t ob2[SERIAL_BUFFERS_SIZE];
+#endif
+
+#ifdef USE_USART3
+FullDuplexDriver COM3;
+static uint8_t ib3[SERIAL_BUFFERS_SIZE];
+static uint8_t ob3[SERIAL_BUFFERS_SIZE];
+#endif
+
+static void SetError(uint16_t sr, FullDuplexDriver *com) {
+ dflags_t sts = 0;
+
+ if (sr & SR_ORE)
+ sts |= SD_OVERRUN_ERROR;
+ if (sr & SR_PE)
+ sts |= SD_PARITY_ERROR;
+ if (sr & SR_FE)
+ sts |= SD_FRAMING_ERROR;
+ if (sr & SR_LBD)
+ sts |= SD_BREAK_DETECTED;
+ chSysLock();
+ chFDDAddFlagsI(com, sts);
+ chSysUnlock();
+}
+
+static void ServeInterrupt(USART_TypeDef *u, FullDuplexDriver *com) {
+ uint16_t sr = u->SR;
+
+ if (sr & (SR_ORE | SR_FE | SR_PE | SR_LBD))
+ SetError(sr, com);
+ if (sr & SR_RXNE) {
+ chSysLock();
+ chFDDIncomingDataI(com, u->DR);
+ chSysUnlock();
+ }
+ if (sr & SR_TXE) {
+ chSysLock();
+ msg_t b = chFDDRequestDataI(com);
+ chSysUnlock();
+ if (b < Q_OK)
+ u->CR1 &= ~CR1_TXEIE;
+ else
+ u->DR = b;
+ }
+}
+
+#ifdef USE_USART1
+/*
+ * USART1 IRQ service routine.
+ */
+void VectorD4(void) {
+
+ chSysIRQEnterI();
+ ServeInterrupt(USART1, &COM1);
+ chSysIRQExitI();
+}
+
+/*
+ * Invoked by the high driver when one or more bytes are inserted in the
+ * output queue.
+ */
+static void OutNotify1(void) {
+
+ USART1->CR1 |= CR1_TXEIE;
+}
+#endif
+
+#ifdef USE_USART2
+/*
+ * USART2 IRQ service routine.
+ */
+void VectorD8(void) {
+
+ chSysIRQEnterI();
+ ServeInterrupt(USART2, &COM2);
+ chSysIRQExitI();
+}
+
+/*
+ * Invoked by the high driver when one or more bytes are inserted in the
+ * output queue.
+ */
+static void OutNotify2(void) {
+
+ USART2->CR1 |= CR1_TXEIE;
+}
+#endif
+
+#ifdef USE_USART3
+/*
+ * USART3 IRQ service routine.
+ */
+void VectorDC(void) {
+
+ chSysIRQEnterI();
+ ServeInterrupt(USART3, &COM3);
+ chSysIRQExitI();
+}
+
+/*
+ * Invoked by the high driver when one or more bytes are inserted in the
+ * output queue.
+ */
+static void OutNotify3(void) {
+
+ USART3->CR1 |= CR1_TXEIE;
+}
+#endif
+
+/*
+ * USART setup, must be invoked with interrupts disabled.
+ * NOTE: Does not reset I/O queues.
+ */
+void SetUSARTI(USART_TypeDef *u, uint32_t speed, uint16_t cr1,
+ uint16_t cr2, uint16_t cr3) {
+
+ /*
+ * Baud rate setting.
+ */
+ if (u == USART1)
+ u->BRR = APB2CLK / speed;
+ else
+ u->BRR = APB1CLK / speed;
+
+ /*
+ * Note that some bits are enforced.
+ */
+ u->CR1 = cr1 | CR1_UE | CR1_PEIE | CR1_RXNEIE | CR1_TE | CR1_RE;
+ u->CR2 = cr2;
+ u->CR3 = cr3 | CR3_EIE;
+}
+
+/*
+ * Serial subsystem initialization.
+ * NOTE: Handshake pins are not switched to their function because they may have
+ * another use. Enable them externally if needed.
+ */
+void InitSerial(uint32_t prio1, uint32_t prio2, uint32_t prio3) {
+
+#ifdef USE_USART1
+ chFDDInit(&COM1, ib1, sizeof ib1, NULL, ob1, sizeof ob1, OutNotify1);
+ RCC->APB2ENR |= 0x00004000;
+ SetUSARTI(USART1, USART_BITRATE, 0, CR2_STOP1_BITS | CR2_LINEN, 0);
+ GPIOA->CRH = (GPIOA->CRH & 0xFFFFF00F) | 0x000004B0;
+ NVICEnableVector(USART1_IRQChannel, prio1);
+#endif
+
+#ifdef USE_USART2
+ chFDDInit(&COM2, ib2, sizeof ib2, NULL, ob2, sizeof ob2, OutNotify2);
+ RCC->APB1ENR |= 0x00020000;
+ SetUSARTI(USART2, USART_BITRATE, 0, CR2_STOP1_BITS | CR2_LINEN, 0);
+ GPIOA->CRL = (GPIOA->CRL & 0xFFFF00FF) | 0x00004B00;
+ NVICEnableVector(USART2_IRQChannel, prio2);
+#endif
+
+#ifdef USE_USART3
+ chFDDInit(&COM3, ib3, sizeof ib3, NULL, ob3, sizeof ob3, OutNotify3);
+ RCC->APB1ENR |= 0x00040000;
+ SetUSARTI(USART3, USART_BITRATE, 0, CR2_STOP1_BITS | CR2_LINEN, 0);
+ GPIOB->CRH = (GPIOB->CRH & 0xFFFF00FF) | 0x00004B00;
+ NVICEnableVector(USART3_IRQChannel, prio3);
+#endif
+}
diff --git a/ports/ARMCM3/chcore.c b/ports/ARMCM3/chcore.c
index 8c4c74315..aac58f9e6 100644
--- a/ports/ARMCM3/chcore.c
+++ b/ports/ARMCM3/chcore.c
@@ -1,152 +1,167 @@
-/*
- ChibiOS/RT - Copyright (C) 2006-2007 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/>.
-*/
-
-#include <ch.h>
-#include <nvic.h>
-
-/*
- * System idle thread loop.
- */
-__attribute__((weak))
-void _IdleThread(void *p) {
-
- while (TRUE) {
-// asm volatile ("wfi");
- }
-}
-
-/*
- * System console message (not implemented).
- */
-__attribute__((weak))
-void chSysPuts(char *msg) {
-}
-
-/*
- * System halt.
- */
-__attribute__((naked, weak))
-void chSysHalt(void) {
-
- asm volatile ("cpsid i");
- while (TRUE) {
- }
-}
-
-__attribute__((naked, weak))
-void threadstart(void) {
-
- asm volatile ( \
- "blx r1 \n\t" \
- "bl chThdExit \n\t" \
- "bl chSysHalt \n\t" \
- );
-}
-
-/*
- * System Timer vector.
- */
-void SysTickVector(void) {
-
- chSysIRQEnterI();
- chSysLock();
-
- chSysTimerHandlerI();
-
- chSysUnlock();
- chSysIRQExitI();
-}
-
-void *retaddr;
-
-/*
- * System invoked context switch.
- */
-__attribute__((naked))
-void SVCallVector(Thread *otp, Thread *ntp) {
-
-#ifdef CH_CURRP_REGISTER_CACHE
- asm volatile ("mrs r3, BASEPRI \n\t" \
- "mrs r12, PSP \n\t" \
- "stmdb r12!, {r3-r6,r8-r11, lr} \n\t" \
- "str r12, [r0, #16] \n\t" \
- "ldr r12, [r1, #16] \n\t" \
- "ldmia r12!, {r3-r6,r8-r11, lr} \n\t" \
- "msr PSP, r12 \n\t" \
- "msr BASEPRI, r3 \n\t" \
- "bx lr ");
-#else
- asm volatile ("mrs r3, BASEPRI \n\t" \
- "mrs r12, PSP \n\t" \
- "stmdb r12!, {r3-r11, lr} \n\t" \
- "str r12, [r0, #16] \n\t" \
- "ldr r12, [r1, #16] \n\t" \
- "ldmia r12!, {r3-r11, lr} \n\t" \
- "msr PSP, r12 \n\t" \
- "msr BASEPRI, r3 \n\t" \
- "bx lr ");
-#endif
-}
-
-/*
- * Preemption invoked context switch.
- */
-__attribute__((naked))
-void PendSVVector(void) {
- Thread *otp;
- register struct intctx *sp_thd asm("r12");
-
- chSysLock();
- asm volatile ("push {lr}");
- if (!chSchRescRequiredI()) {
- chSysUnlock();
- asm volatile ("pop {pc}");
- }
-
- asm volatile ("pop {lr} \n\t" \
- "movs r3, #0 \n\t" \
- "mrs %0, PSP" : "=r" (sp_thd) : );
-#ifdef CH_CURRP_REGISTER_CACHE
- asm volatile ("stmdb %0!, {r3-r6,r8-r11, lr}" :
- "=r" (sp_thd) :
- "r" (sp_thd));
-#else
- asm volatile ("stmdb %0!, {r3-r11,lr}" :
- "=r" (sp_thd) :
- "r" (sp_thd));
-#endif
-
- (otp = currp)->p_ctx.r13 = sp_thd;
- chSchReadyI(otp);
- (currp = fifo_remove(&rlist.r_queue))->p_state = PRCURR;
- rlist.r_preempt = CH_TIME_QUANTUM;
-#ifdef CH_USE_TRACE
- chDbgTrace(otp, currp);
-#endif
- sp_thd = currp->p_ctx.r13;
-
-#ifdef CH_CURRP_REGISTER_CACHE
- asm volatile ("ldmia %0!, {r3-r6,r8-r11, lr}" : : "r" (sp_thd));
-#else
- asm volatile ("ldmia %0!, {r3-r11, lr}" : : "r" (sp_thd));
-#endif
- asm volatile ("msr PSP, %0 \n\t" \
- "msr BASEPRI, r3 \n\t" \
- "bx lr" : : "r" (sp_thd));
-}
+/*
+ ChibiOS/RT - Copyright (C) 2006-2007 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/>.
+*/
+
+#include <ch.h>
+#include <nvic.h>
+
+/*
+ * System idle thread loop.
+ */
+__attribute__((weak))
+void _IdleThread(void *p) {
+
+ while (TRUE) {
+// asm volatile ("wfi");
+ }
+}
+
+/*
+ * System console message (not implemented).
+ */
+__attribute__((weak))
+void chSysPuts(char *msg) {
+}
+
+/*
+ * System halt.
+ */
+__attribute__((naked, weak))
+void chSysHalt(void) {
+
+ asm volatile ("cpsid i");
+ while (TRUE) {
+ }
+}
+
+/*
+ * Start a thread by invoking its work function.
+ *
+ * Start a thread by calling its work function. If the work function returns,
+ * call chThdExit and chSysHalt.
+ */
+__attribute__((naked, weak))
+void threadstart(void) {
+
+ asm volatile ( \
+ "blx r1 \n\t" \
+ "bl chThdExit \n\t" \
+ "bl chSysHalt \n\t" \
+ );
+}
+
+/*
+ * System Timer vector.
+ */
+void SysTickVector(void) {
+
+ chSysIRQEnterI();
+ chSysLock();
+
+ chSysTimerHandlerI();
+
+ chSysUnlock();
+ chSysIRQExitI();
+}
+
+void *retaddr;
+
+/*
+ * System invoked context switch.
+ */
+__attribute__((naked))
+void SVCallVector(Thread *otp, Thread *ntp) {
+ /* { r0 = otp, r1 = ntp } */
+ /* get the BASEPRI in r3 */
+ /* get the PSP in r12 */
+ /* push the registers on the PSP stack */
+ /* stores the modified PSP into the thread context */
+ /* fetches the PSP position from the new thread context */
+ /* pop the registers from the PSP stack */
+ /* set the PSP from r12 */
+ /* set the BASEPRI from R3 */
+#ifdef CH_CURRP_REGISTER_CACHE
+ asm volatile ("mrs r3, BASEPRI \n\t" \
+ "mrs r12, PSP \n\t" \
+ "stmdb r12!, {r3-r6,r8-r11, lr} \n\t" \
+ "str r12, [r0, #16] \n\t" \
+ "ldr r12, [r1, #16] \n\t" \
+ "ldmia r12!, {r3-r6,r8-r11, lr} \n\t" \
+ "msr PSP, r12 \n\t" \
+ "msr BASEPRI, r3 \n\t" \
+ "bx lr ");
+#else
+ asm volatile ("mrs r3, BASEPRI \n\t" \
+ "mrs r12, PSP \n\t" \
+ "stmdb r12!, {r3-r11, lr} \n\t" \
+ "str r12, [r0, #16] \n\t" \
+ "ldr r12, [r1, #16] \n\t" \
+ "ldmia r12!, {r3-r11, lr} \n\t" \
+ "msr PSP, r12 \n\t" \
+ "msr BASEPRI, r3 \n\t" \
+ "bx lr ");
+#endif
+}
+
+/*
+ * Preemption invoked context switch.
+ */
+__attribute__((naked))
+void PendSVVector(void) {
+ Thread *otp;
+ register struct intctx *sp_thd asm("r12");
+
+ chSysLock();
+ asm volatile ("push {lr}");
+ if (!chSchRescRequiredI()) {
+ chSysUnlock();
+ asm volatile ("pop {pc}");
+ }
+
+ asm volatile ("pop {lr} \n\t" \
+ "movs r3, #0 \n\t" \
+ "mrs %0, PSP" : "=r" (sp_thd) : );
+#ifdef CH_CURRP_REGISTER_CACHE
+ asm volatile ("stmdb %0!, {r3-r6,r8-r11, lr}" :
+ "=r" (sp_thd) :
+ "r" (sp_thd));
+#else
+ asm volatile ("stmdb %0!, {r3-r11,lr}" :
+ "=r" (sp_thd) :
+ "r" (sp_thd));
+#endif
+
+ (otp = currp)->p_ctx.r13 = sp_thd;
+ chSchReadyI(otp);
+ (currp = fifo_remove(&rlist.r_queue))->p_state = PRCURR;
+ /* set the round-robin time quantum */
+ rlist.r_preempt = CH_TIME_QUANTUM;
+#ifdef CH_USE_TRACE
+ chDbgTrace(otp, currp);
+#endif
+ sp_thd = currp->p_ctx.r13;
+
+#ifdef CH_CURRP_REGISTER_CACHE
+ asm volatile ("ldmia %0!, {r3-r6,r8-r11, lr}" : : "r" (sp_thd));
+#else
+ asm volatile ("ldmia %0!, {r3-r11, lr}" : : "r" (sp_thd));
+#endif
+ asm volatile ("msr PSP, %0 \n\t" \
+ "msr BASEPRI, r3 \n\t" \
+ "bx lr" : : "r" (sp_thd));
+}
diff --git a/ports/ARMCM3/chcore.h b/ports/ARMCM3/chcore.h
index 9a8f00bee..3136f0d36 100644
--- a/ports/ARMCM3/chcore.h
+++ b/ports/ARMCM3/chcore.h
@@ -1,120 +1,126 @@
-/*
- ChibiOS/RT - Copyright (C) 2006-2007 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/>.
-*/
-
-#ifndef _CHCORE_H_
-#define _CHCORE_H_
-
-#define CH_ARCHITECTURE_ARMCM3
-
-typedef void *regarm;
-
-/*
- * Interrupt saved context, empty in this architecture.
- */
-struct extctx {
-};
-
-/*
- * System saved context.
- */
-struct intctx {
- regarm basepri;
- regarm r4;
- regarm r5;
- regarm r6;
-#ifndef CH_CURRP_REGISTER_CACHE
- regarm r7;
-#endif
- regarm r8;
- regarm r9;
- regarm r10;
- regarm r11;
- regarm lr_exc;
- regarm r0;
- regarm r1;
- regarm r2;
- regarm r3;
- regarm r12;
- regarm lr_thd;
- regarm pc;
- regarm xpsr;
-};
-
-/*
- * Port dependent part of the Thread structure, you may add fields in
- * this structure.
- */
-typedef struct {
- struct intctx *r13;
-} Context;
-
-/*
- * Platform dependent part of the \p chThdCreate() API.
- */
-#define SETUP_CONTEXT(workspace, wsize, pf, arg) { \
- tp->p_ctx.r13 = (struct intctx *)((uint8_t *)workspace + \
- wsize - \
- sizeof(struct intctx)); \
- tp->p_ctx.r13->basepri = 0; \
- tp->p_ctx.r13->lr_exc = (regarm)0xFFFFFFFD; \
- tp->p_ctx.r13->r0 = arg; \
- tp->p_ctx.r13->r1 = pf; \
- tp->p_ctx.r13->pc = threadstart; \
- tp->p_ctx.r13->xpsr = (regarm)0x01000000; \
-}
-
-#define chSysLock() { \
- register uint32_t tmp asm ("r3"); \
- asm volatile ("movs %0, #0x10" : "=r" (tmp): ); \
- asm volatile ("msr BASEPRI, %0" : : "r" (tmp)); \
-}
-#define chSysUnlock() { \
- register uint32_t tmp asm ("r3"); \
- asm volatile ("movs %0, #0" : "=r" (tmp): ); \
- asm volatile ("msr BASEPRI, %0" : : "r" (tmp)); \
-}
-#define chSysSwitchI(otp, ntp) { \
- register Thread *_otp asm ("r0") = (otp); \
- register Thread *_ntp asm ("r1") = (ntp); \
- asm volatile ("svc #0" : : "r" (_otp), "r" (_ntp)); \
-}
-
-#define INT_REQUIRED_STACK 0
-#define StackAlign(n) ((((n) - 1) | 3) + 1)
-#define UserStackSize(n) StackAlign(sizeof(Thread) + \
- sizeof(struct intctx) + \
- sizeof(struct extctx) + \
- (n) + \
- INT_REQUIRED_STACK)
-#define WorkingArea(s, n) uint32_t s[UserStackSize(n) >> 2];
-
-#define chSysIRQEnterI()
-#define chSysIRQExitI() { \
- SCB_ICSR = ICSR_PENDSVSET; \
-}
-
-/* It should be 8.*/
-#define IDLE_THREAD_STACK_SIZE 0
-void _IdleThread(void *p) __attribute__((noreturn));
-
-void chSysHalt(void);
-void chSysPuts(char *msg);
-void threadstart(void);
-
-#endif /* _CHCORE_H_ */
+/*
+ ChibiOS/RT - Copyright (C) 2006-2007 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/>.
+*/
+
+#ifndef _CHCORE_H_
+#define _CHCORE_H_
+
+#define CH_ARCHITECTURE_ARMCM3
+
+typedef void *regarm;
+
+/*
+ * Interrupt saved context, empty in this architecture.
+ */
+struct extctx {
+};
+
+/*
+ * System saved context.
+ */
+struct intctx {
+ regarm basepri;
+ regarm r4;
+ regarm r5;
+ regarm r6;
+#ifndef CH_CURRP_REGISTER_CACHE
+ regarm r7;
+#endif
+ regarm r8;
+ regarm r9;
+ regarm r10;
+ regarm r11;
+ regarm lr_exc;
+ regarm r0;
+ regarm r1;
+ regarm r2;
+ regarm r3;
+ regarm r12;
+ regarm lr_thd;
+ regarm pc;
+ regarm xpsr;
+};
+
+/*
+ * Port dependent part of the Thread structure, you may add fields in
+ * this structure.
+ */
+typedef struct {
+ struct intctx *r13;
+} Context;
+
+/*
+ * Platform dependent part of the \p chThdCreate() API.
+ *
+ * The top of the workspace is used for the intctx datastructure.
+ *
+ */
+#define SETUP_CONTEXT(workspace, wsize, pf, arg) { \
+ tp->p_ctx.r13 = (struct intctx *)((uint8_t *)workspace + \
+ wsize - \
+ sizeof(struct intctx)); \
+ tp->p_ctx.r13->basepri = 0; \
+ tp->p_ctx.r13->lr_exc = (regarm)0xFFFFFFFD; \
+ tp->p_ctx.r13->r0 = arg; \
+ tp->p_ctx.r13->r1 = pf; \
+ tp->p_ctx.r13->pc = threadstart; \
+ tp->p_ctx.r13->xpsr = (regarm)0x01000000; \
+}
+
+#define chSysLock() { \
+ register uint32_t tmp asm ("r3"); \
+ asm volatile ("movs %0, #0x10" : "=r" (tmp): ); \
+ asm volatile ("msr BASEPRI, %0" : : "r" (tmp)); \
+}
+#define chSysUnlock() { \
+ register uint32_t tmp asm ("r3"); \
+ asm volatile ("movs %0, #0" : "=r" (tmp): ); \
+ asm volatile ("msr BASEPRI, %0" : : "r" (tmp)); \
+}
+#define chSysSwitchI(otp, ntp) { \
+ register Thread *_otp asm ("r0") = (otp); \
+ register Thread *_ntp asm ("r1") = (ntp); \
+ asm volatile ("svc #0" : : "r" (_otp), "r" (_ntp)); \
+}
+
+#define INT_REQUIRED_STACK 0
+#define StackAlign(n) ((((n) - 1) | 3) + 1)
+#define UserStackSize(n) StackAlign(sizeof(Thread) + \
+ sizeof(struct intctx) + \
+ sizeof(struct extctx) + \
+ (n) + \
+ INT_REQUIRED_STACK)
+#define WorkingArea(s, n) uint32_t s[UserStackSize(n) >> 2];
+
+/* called on each interrupt entry, currently nothing is done */
+#define chSysIRQEnterI()
+/* called on each interrupt exit, pends a supervisor handler for
+ * execution after all higher priority interrupts; PendSVVector() */
+#define chSysIRQExitI() { \
+ SCB_ICSR = ICSR_PENDSVSET; \
+}
+
+/* It should be 8.*/
+#define IDLE_THREAD_STACK_SIZE 0
+void _IdleThread(void *p) __attribute__((noreturn));
+
+void chSysHalt(void);
+void chSysPuts(char *msg);
+void threadstart(void);
+
+#endif /* _CHCORE_H_ */
diff --git a/ports/ARMCM3/crt0.s b/ports/ARMCM3/crt0.s
index 47a89c632..0f2f4667d 100644
--- a/ports/ARMCM3/crt0.s
+++ b/ports/ARMCM3/crt0.s
@@ -1,93 +1,94 @@
-/*
- ChibiOS/RT - Copyright (C) 2006-2007 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/>.
-*/
-
-/*
- * Generic ARM-CortexM3 startup file for ChibiOS/RT.
- */
-
-.set CONTROL_MODE_PRIVILEGED, 0
-.set CONTROL_MODE_UNPRIVILEGED, 1
-.set CONTROL_USE_MSP, 0
-.set CONTROL_USE_PSP, 2
-
-.text
-.balign 2
-.syntax unified
-.thumb
-
-/*
- * Reset handler.
- */
-.thumb_func
-.global ResetHandler
-ResetHandler:
- /*
- * Stack pointers initialization.
- */
- ldr r0, =__ram_end__
- ldr r1, =__main_stack_size__
- sub r0, r0, r1
- msr PSP, r0
-// ldr r1, =__process_stack_size__
-// sub r0, r0, r1
- /*
- * Data initialization.
- * NOTE: It assumes that the DATA size is a multiple of 4.
- */
- ldr r1, =_textdata
- ldr r2, =_data
- ldr r3, =_edata
-dloop:
- cmp r2, r3
- ittt lo
- ldrlo r0, [r1], #4
- strlo r0, [r2], #4
- blo dloop
- /*
- * BSS initialization.
- * NOTE: It assumes that the BSS size is a multiple of 4.
- */
- movs r0, #0
- ldr r1, =_bss_start
- ldr r2, =_bss_end
-bloop:
- cmp r1, r2
- itt lo
- strlo r0, [r1], #4
- blo bloop
- /*
- * Switches to the Process Stack and disables the interrupts globally.
- */
- movs r0, #CONTROL_MODE_PRIVILEGED | CONTROL_USE_PSP
- msr CONTROL, r0
- isb
- movs r0, #0x10
- msr BASEPRI, r0
- cpsie i
- /*
- * Application-provided HW initialization routine.
- */
- bl hwinit
- /*
- * main(0, NULL).
- */
- movs r0, #0
- mov r1, r0
- bl main
- bl chSysHalt
+/*
+ ChibiOS/RT - Copyright (C) 2006-2007 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/>.
+*/
+
+/*
+ * Generic ARM-CortexM3 startup file for ChibiOS/RT.
+ */
+
+.set CONTROL_MODE_PRIVILEGED, 0
+.set CONTROL_MODE_UNPRIVILEGED, 1
+.set CONTROL_USE_MSP, 0
+.set CONTROL_USE_PSP, 2
+
+.text
+.balign 2
+.syntax unified
+.thumb
+
+/*
+ * Reset handler.
+ */
+.thumb_func
+.global ResetHandler
+ResetHandler:
+ /*
+ * Stack pointers initialization.
+ */
+ ldr r0, =__ram_end__
+ ldr r1, =__main_stack_size__
+ sub r0, r0, r1
+ /* { r0 = main stack low address } */
+ msr PSP, r0
+// ldr r1, =__process_stack_size__
+// sub r0, r0, r1
+ /*
+ * Data initialization.
+ * NOTE: It assumes that the DATA size is a multiple of 4.
+ */
+ ldr r1, =_textdata
+ ldr r2, =_data
+ ldr r3, =_edata
+dloop:
+ cmp r2, r3
+ ittt lo
+ ldrlo r0, [r1], #4
+ strlo r0, [r2], #4
+ blo dloop
+ /*
+ * BSS initialization.
+ * NOTE: It assumes that the BSS size is a multiple of 4.
+ */
+ movs r0, #0
+ ldr r1, =_bss_start
+ ldr r2, =_bss_end
+bloop:
+ cmp r1, r2
+ itt lo
+ strlo r0, [r1], #4
+ blo bloop
+ /*
+ * Switches to the Process Stack and disables the interrupts globally.
+ */
+ movs r0, #CONTROL_MODE_PRIVILEGED | CONTROL_USE_PSP
+ msr CONTROL, r0
+ isb
+ movs r0, #0x10
+ msr BASEPRI, r0
+ cpsie i
+ /*
+ * Application-provided HW initialization routine.
+ */
+ bl hwinit
+ /*
+ * main(0, NULL).
+ */
+ movs r0, #0
+ mov r1, r0
+ bl main
+ bl chSysHalt
diff --git a/readme.txt b/readme.txt
index 8d5db6ccc..e6371dbee 100644
--- a/readme.txt
+++ b/readme.txt
@@ -74,6 +74,12 @@ Win32-MinGW - ChibiOS/RT simulator and demo into a WIN32 process,
*** Releases ***
*****************************************************************************
+*** 0.6.8 ***
+- FIX: Fixed a bug in the priority inheritance mechanism, the bug was only a
+ problems when the CH_USE_MESSAGES_PRIORITY was enabled, this option is
+ disabled by default in ChibiOS/RT so it should not affect any user.
+- Merged the documentation fixes submitted by Leon Woestenberg (thank you).
+
*** 0.6.7 ***
- NEW: New chThdCreateFast() API, it is a simplified form of chThdCreate()
that allows even faster threads creation. The new API does not support
diff --git a/src/chinit.c b/src/chinit.c
index 5b2c0cd24..b8d36a6e5 100644
--- a/src/chinit.c
+++ b/src/chinit.c
@@ -1,81 +1,86 @@
-/*
- ChibiOS/RT - Copyright (C) 2006-2007 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/>.
-*/
-
-/**
- * @addtogroup Initialization
- * @{
- */
-
-#include <ch.h>
-
-/**
- * ChibiOS/RT initialization. After executing this function the current
- * instructions stream becomes the main thread.
- * @note Interrupts should be still disabled when \p chSysInit() is invoked
- * and are internally enabled.
- * @note The main thread is created with priority \p NORMALPRIO.
- */
-void chSysInit(void) {
- static Thread mainthread;
- static WorkingArea(waIdleThread, IDLE_THREAD_STACK_SIZE);
-
- chSchInit();
- chDbgInit();
-#ifdef CH_USE_VIRTUAL_TIMERS
- chVTInit();
-#endif
- /*
- * Now this instructions flow becomes the main thread.
- */
- init_thread(NORMALPRIO, 0, &mainthread);
- mainthread.p_state = PRCURR;
- currp = &mainthread;
-
- chSysUnlock();
-
- /*
- * The idle thread is created using the port-provided implementation.
- * 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.
- */
- chThdCreateFast(IDLEPRIO, waIdleThread,
- sizeof(waIdleThread), (tfunc_t)_IdleThread);
-}
-
-/**
- * Preemption routine, this function must be called into an interrupt
- * handler invoked by a system timer.
- * The frequency of the timer determines the system tick granularity and,
- * together with the \p CH_TIME_QUANTUM macro, the round robin interval.
- */
-void chSysTimerHandlerI(void) {
-
- if (rlist.r_preempt > 0)
- rlist.r_preempt--;
-#ifdef CH_USE_SYSTEMTIME
- rlist.r_stime++;
-#endif
-
-#ifdef CH_USE_VIRTUAL_TIMERS
- chVTDoTickI();
-#endif
-}
-
-/** @} */
+/*
+ ChibiOS/RT - Copyright (C) 2006-2007 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/>.
+*/
+
+/**
+ * @addtogroup Initialization
+ * @{
+ */
+
+#include <ch.h>
+
+/**
+ * ChibiOS/RT initialization. After executing this function the current
+ * instructions stream becomes the main thread.
+ * @note Interrupts should be still disabled when \p chSysInit() is invoked
+ * and are internally enabled.
+ * @note The main thread is created with priority \p NORMALPRIO.
+ */
+void chSysInit(void) {
+ static Thread mainthread;
+ static WorkingArea(waIdleThread, IDLE_THREAD_STACK_SIZE);
+
+ chSchInit();
+ chDbgInit();
+#ifdef CH_USE_VIRTUAL_TIMERS
+ chVTInit();
+#endif
+ /*
+ * Now this instructions flow becomes the main thread.
+ */
+ init_thread(NORMALPRIO, 0, &mainthread);
+ mainthread.p_state = PRCURR;
+ currp = &mainthread;
+
+ chSysUnlock();
+
+ /*
+ * The idle thread is created using the port-provided implementation.
+ * 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.
+ */
+ chThdCreateFast(IDLEPRIO, waIdleThread,
+ sizeof(waIdleThread), (tfunc_t)_IdleThread);
+}
+
+/**
+ * Handles time ticks for round robin preemption and timer increments.
+ *
+ * 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.
+ */
+void chSysTimerHandlerI(void) {
+ /* running thread has not used up quantum yet? */
+ if (rlist.r_preempt > 0)
+ /* decrement remaining quantum */
+ rlist.r_preempt--;
+#ifdef CH_USE_SYSTEMTIME
+ rlist.r_stime++;
+#endif
+
+#ifdef CH_USE_VIRTUAL_TIMERS
+ chVTDoTickI();
+#endif
+}
+
+/** @} */
diff --git a/src/chmtx.c b/src/chmtx.c
index a6379836d..2e95afca6 100644
--- a/src/chmtx.c
+++ b/src/chmtx.c
@@ -1,243 +1,260 @@
-/*
- ChibiOS/RT - Copyright (C) 2006-2007 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/>.
-*/
-
-/**
- * @addtogroup Mutexes
- * @{
- */
-
-#include <ch.h>
-
-#ifdef CH_USE_MUTEXES
-
-/**
- * Initializes s \p Mutex structure.
- * @param mp pointer to a \p Mutex structure
- */
-void chMtxInit(Mutex *mp) {
-
- fifo_init(&mp->m_queue);
- mp->m_owner = NULL;
-}
-
-/**
- * Locks the specified mutex.
- * @param mp pointer to the \p Mutex structure
- */
-void chMtxLock(Mutex *mp) {
-
- chSysLock();
-
- chMtxLockS(mp);
-
- chSysUnlock();
-}
-
-/**
- * Locks the specified mutex.
- * @param mp pointer to the \p Mutex structure
- * @note This function must be called within a \p chSysLock() / \p chSysUnlock()
- * block.
- */
-void chMtxLockS(Mutex *mp) {
-
- if (mp->m_owner != NULL) {
- /*
- * Inheritance, explores the thread-mutex dependances adjusting
- * the priority of all the affected threads.
- */
- Thread *tp = mp->m_owner;
- while (tp->p_prio < currp->p_prio) {
- tp->p_prio = currp->p_prio;
- /*
- * The following states need priority queues reordering.
- */
- switch (tp->p_state) {
- case PRWTMTX:
- prio_insert(dequeue(tp), &tp->p_wtmtxp->m_queue);
- tp = tp->p_wtmtxp->m_owner;
- continue;
-#ifdef CH_USE_MESSAGES_PRIORITY
- case PRSNDMSG:
- if (tp->p_flags & P_MSGBYPRIO)
- prio_insert(dequeue(tp), &tp->p_wtthdp->p_msgqueue);
-#endif
- case PRREADY:
- chSchReadyI(dequeue(tp));
- }
- break;
- }
- /*
- * Goes to sleep on the mutex.
- */
- prio_insert(currp, &mp->m_queue);
- currp->p_wtmtxp = mp;
- chSchGoSleepS(PRWTMTX);
- chDbgAssert(mp->m_owner == NULL, "chmtx.c, chMtxLockS()");
- }
- /*
- * The mutex is now inserted in the owned mutexes list.
- */
- mp->m_owner = currp;
- mp->m_next = currp->p_mtxlist;
- currp->p_mtxlist = mp;
-}
-
-/**
- * Tries to lock a mutex. This function does not have any overhead related to
- * the priority inheritance mechanism because it does not try to enter a sleep
- * state on the mutex.
- * @param mp pointer to the \p Mutex structure
- * @return \p TRUE if the mutex was successfully acquired else \p FALSE
- */
-bool_t chMtxTryLock(Mutex *mp) {
- bool_t b;
-
- chSysLock();
-
- b = chMtxTryLockS(mp);
-
- chSysUnlock();
- return b;
-}
-
-/**
- * Tries to lock a mutex. This function does not have any overhead related to
- * the priority inheritance mechanism because it does not try to enter a sleep
- * state on the mutex.
- * @param mp pointer to the \p Mutex structure
- * @return \p TRUE if the mutex was successfully acquired else \p FALSE
- * @note This function must be called within a \p chSysLock() / \p chSysUnlock()
- * block.
- */
-bool_t chMtxTryLockS(Mutex *mp) {
-
- if (mp->m_owner != NULL)
- return FALSE;
- mp->m_owner = currp;
- mp->m_next = currp->p_mtxlist;
- currp->p_mtxlist = mp;
- return TRUE;
-}
-
-/**
- * Unlocks the next owned mutex in reverse lock order.
- */
-void chMtxUnlock(void) {
- Mutex *mp;
-
- chSysLock();
-
- chDbgAssert((currp->p_mtxlist != NULL) && (currp->p_mtxlist->m_owner == currp),
- "chmtx.c, chMtxUnlock()");
-
- /*
- * Removes the top Mutex from the owned mutexes list and marks it as not owned.
- */
- mp = currp->p_mtxlist;
- currp->p_mtxlist = mp->m_next;
- mp->m_owner = NULL;
- /*
- * If a thread is waiting on the mutex then the hard part begins.
- */
- if (chMtxQueueNotEmptyS(mp)) {
- Thread *tp = fifo_remove(&mp->m_queue);
- /*
- * Recalculates the optimal thread priority by scanning the owned mutexes list.
- */
- tprio_t newprio = currp->p_realprio;
- mp = currp->p_mtxlist;
- while (mp != NULL) {
- if (chMtxQueueNotEmptyS(mp) && (mp->m_queue.p_next->p_prio > newprio))
- newprio = mp->m_queue.p_next->p_prio;
- mp = mp->m_next;
- }
- currp->p_prio = newprio;
- chSchWakeupS(tp, RDY_OK);
- }
-
- chSysUnlock();
-}
-
-/**
- * Unlocks the next owned mutex in reverse lock order.
- * @note This function must be called within a \p chSysLock() / \p chSysUnlock()
- * block.
- * @note This function does not reschedule internally.
- */
-void chMtxUnlockS(void) {
- Mutex *mp;
-
- chDbgAssert((currp->p_mtxlist != NULL) && (currp->p_mtxlist->m_owner == currp),
- "chmtx.c, chMtxUnlockS()");
-
- /*
- * Removes the top Mutex from the owned mutexes list and marks it as not owned.
- */
- mp = currp->p_mtxlist;
- currp->p_mtxlist = mp->m_next;
- mp->m_owner = NULL;
- /*
- * If a thread is waiting on the mutex then the hard part begins.
- */
- if (chMtxQueueNotEmptyS(mp)) {
- Thread *tp = fifo_remove(&mp->m_queue);
- /*
- * Recalculates the optimal thread priority by scanning the owned mutexes list.
- */
- tprio_t newprio = currp->p_realprio;
- mp = currp->p_mtxlist;
- while (mp != NULL) {
- if (chMtxQueueNotEmptyS(mp) && (mp->m_queue.p_next->p_prio > newprio))
- newprio = mp->m_queue.p_next->p_prio;
- mp = mp->m_next;
- }
- currp->p_prio = newprio;
- chSchReadyI(tp);
- }
-}
-
-/**
- * Unlocks all the mutexes owned by the invoking thread, this 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.
- */
-void chMtxUnlockAll(void) {
-
- chSysLock();
-
- if (currp->p_mtxlist != NULL) {
- do {
- Mutex *mp = currp->p_mtxlist;
- currp->p_mtxlist = mp->m_next;
- mp->m_owner = NULL;
- if (chMtxQueueNotEmptyS(mp))
- chSchReadyI(fifo_remove(&mp->m_queue));
- } while (currp->p_mtxlist != NULL);
- currp->p_prio = currp->p_realprio;
- chSchRescheduleS();
- }
-
- chSysUnlock();
-}
-
-#endif /* CH_USE_MUTEXES */
-
-/** @} */
+/*
+ ChibiOS/RT - Copyright (C) 2006-2007 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/>.
+*/
+
+/**
+ * @addtogroup Mutexes
+ * @{
+ */
+
+#include <ch.h>
+
+#ifdef CH_USE_MUTEXES
+
+/**
+ * Initializes s \p Mutex structure.
+ * @param mp pointer to a \p Mutex structure
+ */
+void chMtxInit(Mutex *mp) {
+
+ fifo_init(&mp->m_queue);
+ mp->m_owner = NULL;
+}
+
+/**
+ * Locks the specified mutex.
+ * @param mp pointer to the \p Mutex structure
+ */
+void chMtxLock(Mutex *mp) {
+
+ chSysLock();
+
+ chMtxLockS(mp);
+
+ chSysUnlock();
+}
+
+/**
+ * Locks the specified mutex.
+ *
+ * @param mp pointer to the \p Mutex structure
+ * @note This function must be called within a \p chSysLock() / \p chSysUnlock()
+ * block.
+ */
+void chMtxLockS(Mutex *mp) {
+ /* the mutex is 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;
+ /* { tp is the thread currently owning the mutex } */
+ /* the running thread has higher priority than tp? */
+ while (tp->p_prio < currp->p_prio) {
+ /* make priority of thread tp match the running thread's priority */
+ tp->p_prio = currp->p_prio;
+ /*
+ * The following states need priority queues reordering.
+ */
+ switch (tp->p_state) {
+ /* thread tp is waiting on a mutex? */
+ case PRWTMTX:
+ /* requeue tp with its new priority on the mutex wait queue */
+ prio_insert(dequeue(tp), &tp->p_wtmtxp->m_queue);
+ /* boost the owner of this mutex if needed */
+ tp = tp->p_wtmtxp->m_owner;
+ continue;
+#ifdef CH_USE_MESSAGES_PRIORITY
+ case PRSNDMSG:
+ if (tp->p_flags & P_MSGBYPRIO)
+ /* requeue tp with its new priority on (?) */
+ prio_insert(dequeue(tp), &tp->p_wtthdp->p_msgqueue);
+ break;
+#endif
+ /* thread tp is ready? */
+ case PRREADY:
+ /* requeue tp with its new priority on the ready list */
+ chSchReadyI(dequeue(tp));
+ }
+ break;
+ }
+ /*
+ * Goes to sleep on the mutex.
+ */
+ prio_insert(currp, &mp->m_queue);
+ currp->p_wtmtxp = mp;
+ chSchGoSleepS(PRWTMTX);
+ chDbgAssert(mp->m_owner == NULL, "chmtx.c, chMtxLockS()");
+ }
+ /*
+ * The mutex is now inserted in the owned mutexes list.
+ */
+ mp->m_owner = currp;
+ mp->m_next = currp->p_mtxlist;
+ currp->p_mtxlist = mp;
+}
+
+/**
+ * Tries to lock a mutex. This function does not have any overhead related to
+ * the priority inheritance mechanism because it does not try to enter a sleep
+ * state on the mutex.
+ * @param mp pointer to the \p Mutex structure
+ * @return \p TRUE if the mutex was successfully acquired else \p FALSE
+ */
+bool_t chMtxTryLock(Mutex *mp) {
+ bool_t b;
+
+ chSysLock();
+
+ b = chMtxTryLockS(mp);
+
+ chSysUnlock();
+ return b;
+}
+
+/**
+ * Tries to lock a mutex. This function does not have any overhead related to
+ * the priority inheritance mechanism because it does not try to enter a sleep
+ * state on the mutex.
+ * @param mp pointer to the \p Mutex structure
+ * @return \p TRUE if the mutex was successfully acquired else \p FALSE
+ * @note This function must be called within a \p chSysLock() / \p chSysUnlock()
+ * block.
+ */
+bool_t chMtxTryLockS(Mutex *mp) {
+
+ if (mp->m_owner != NULL)
+ return FALSE;
+ mp->m_owner = currp;
+ mp->m_next = currp->p_mtxlist;
+ currp->p_mtxlist = mp;
+ return TRUE;
+}
+
+/**
+ * Unlocks the next owned mutex in reverse lock order.
+ */
+void chMtxUnlock(void) {
+ Mutex *mp;
+
+ chSysLock();
+
+ chDbgAssert((currp->p_mtxlist != NULL) && (currp->p_mtxlist->m_owner == currp),
+ "chmtx.c, chMtxUnlock()");
+
+ /*
+ * Removes the top Mutex from the owned mutexes list and marks it as not owned.
+ */
+ mp = currp->p_mtxlist;
+ currp->p_mtxlist = mp->m_next;
+ mp->m_owner = NULL;
+ /*
+ * If a thread is waiting on the mutex then the hard part begins.
+ */
+ if (chMtxQueueNotEmptyS(mp)) {
+ /* get the highest priority thread waiting for the unlocked mutex */
+ Thread *tp = fifo_remove(&mp->m_queue);
+ /*
+ * Recalculates the optimal thread priority by scanning the owned mutexes list.
+ */
+ tprio_t newprio = currp->p_realprio;
+ /* iterate mp over all the (other) mutexes the current thread still owns */
+ mp = currp->p_mtxlist;
+ while (mp != NULL) {
+ /* mutex mp has a higher priority thread pending? */
+ if (chMtxQueueNotEmptyS(mp) && (mp->m_queue.p_next->p_prio > newprio))
+ /* boost current thread's priority to waiting thread */
+ newprio = mp->m_queue.p_next->p_prio;
+ mp = mp->m_next;
+ }
+ /* (possibly) boost the priority of the current thread */
+ currp->p_prio = newprio;
+ /* awaken the highest priority thread waiting for the unlocked mutex */
+ chSchWakeupS(tp, RDY_OK);
+ }
+ chSysUnlock();
+}
+
+/**
+ * Unlocks the next owned mutex in reverse lock order.
+ * @note This function must be called within a \p chSysLock() / \p chSysUnlock()
+ * block.
+ * @note This function does not reschedule internally.
+ */
+void chMtxUnlockS(void) {
+ Mutex *mp;
+
+ chDbgAssert((currp->p_mtxlist != NULL) && (currp->p_mtxlist->m_owner == currp),
+ "chmtx.c, chMtxUnlockS()");
+
+ /*
+ * Removes the top Mutex from the owned mutexes list and marks it as not owned.
+ */
+ mp = currp->p_mtxlist;
+ currp->p_mtxlist = mp->m_next;
+ mp->m_owner = NULL;
+ /*
+ * If a thread is waiting on the mutex then the hard part begins.
+ */
+ if (chMtxQueueNotEmptyS(mp)) {
+ Thread *tp = fifo_remove(&mp->m_queue);
+ /*
+ * Recalculates the optimal thread priority by scanning the owned mutexes list.
+ */
+ tprio_t newprio = currp->p_realprio;
+ mp = currp->p_mtxlist;
+ while (mp != NULL) {
+ if (chMtxQueueNotEmptyS(mp) && (mp->m_queue.p_next->p_prio > newprio))
+ newprio = mp->m_queue.p_next->p_prio;
+ mp = mp->m_next;
+ }
+ currp->p_prio = newprio;
+ chSchReadyI(tp);
+ }
+}
+
+/**
+ * Unlocks all the mutexes owned by the invoking thread, this 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.
+ */
+void chMtxUnlockAll(void) {
+
+ chSysLock();
+
+ if (currp->p_mtxlist != NULL) {
+ do {
+ Mutex *mp = currp->p_mtxlist;
+ currp->p_mtxlist = mp->m_next;
+ mp->m_owner = NULL;
+ if (chMtxQueueNotEmptyS(mp))
+ chSchReadyI(fifo_remove(&mp->m_queue));
+ } while (currp->p_mtxlist != NULL);
+ currp->p_prio = currp->p_realprio;
+ chSchRescheduleS();
+ }
+
+ chSysUnlock();
+}
+
+#endif /* CH_USE_MUTEXES */
+
+/** @} */
diff --git a/src/chschd.c b/src/chschd.c
index 70c867535..6a82eb1d8 100644
--- a/src/chschd.c
+++ b/src/chschd.c
@@ -1,193 +1,215 @@
-/*
- ChibiOS/RT - Copyright (C) 2006-2007 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/>.
-*/
-
-/**
- * @addtogroup Scheduler
- * @{
- */
-
-#include <ch.h>
-
-/** @cond never */
-ReadyList rlist;
-/** @endcond */
-
-/**
- * Scheduler initialization.
- * @note Internally invoked by the \p chSysInit().
- */
-void chSchInit(void) {
-
- fifo_init(&rlist.r_queue);
- rlist.r_prio = NOPRIO;
- rlist.r_preempt = CH_TIME_QUANTUM;
-#ifdef CH_USE_SYSTEMTIME
- rlist.r_stime = 0;
-#endif
-}
-
-/**
- * Inserts a thread in the Ready List.
- * @param tp the Thread to be made ready
- * @return the Thread pointer
- * @note The function must be called in the system mutex zone.
- * @note The function does not reschedule, the \p chSchRescheduleS() should
- * be called soon after.
- * @note The function is not meant to be used in the user code directly.
- */
-#ifdef CH_OPTIMIZE_SPEED
-/* NOTE: it is inlined in this module only.*/
-INLINE Thread *chSchReadyI(Thread *tp) {
-#else
-Thread *chSchReadyI(Thread *tp) {
-#endif
- Thread *cp;
-
- tp->p_state = PRREADY;
- cp = rlist.r_queue.p_next;
- while (cp->p_prio >= tp->p_prio)
- cp = cp->p_next;
- /* Insertion on p_prev.*/
- tp->p_prev = (tp->p_next = cp)->p_prev;
- tp->p_prev->p_next = cp->p_prev = tp;
- return tp;
-}
-
-/**
- * Puts the current thread to sleep into the specified state, the next highest
- * priority thread becomes running. The threads states are described into
- * \p threads.h
- * @param newstate the new thread state
- * @note The function must be called in the system mutex zone.
- * @note The function is not meant to be used in the user code directly.
- */
-void chSchGoSleepS(tstate_t newstate) {
- Thread *otp;
-
- (otp = currp)->p_state = newstate;
- (currp = fifo_remove(&rlist.r_queue))->p_state = PRCURR;
- rlist.r_preempt = CH_TIME_QUANTUM;
-#ifdef CH_USE_TRACE
- chDbgTrace(otp, currp);
-#endif
- chSysSwitchI(otp, currp);
-}
-
-#ifdef CH_USE_VIRTUAL_TIMERS
-/*
- * Timeout wakeup callback.
- */
-static void wakeup(void *p) {
-
-#ifdef CH_USE_SEMAPHORES
- if (((Thread *)p)->p_state == PRWTSEM)
- chSemFastSignalI(((Thread *)p)->p_wtsemp);
-#endif
- chSchReadyI(p)->p_rdymsg = RDY_TIMEOUT;
-}
-
-/**
- * Puts the current thread to sleep into the specified state, the next highest
- * priority thread becomes running. The thread is automatically awakened after
- * the specified time elapsed.
- * @param newstate the new thread state
- * @param time the number of ticks before the operation timouts
- * @return the wakeup message, it is \p RDY_TIMEOUT if a timeout occurs
- * @note The function must be called in the system mutex zone.
- * @note The function is not meant to be used in the user code directly.
- */
-msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time) {
- VirtualTimer vt;
-
- chVTSetI(&vt, time, wakeup, currp);
- chSchGoSleepS(newstate);
- if (chVTIsArmedI(&vt))
- chVTResetI(&vt);
- return currp->p_rdymsg;
-}
-#endif /* CH_USE_VIRTUAL_TIMERS */
-
-/**
- * Wakeups a thread, the thread is inserted into the ready list or made
- * running directly depending on its relative priority compared to the current
- * thread.
- * @param ntp the Thread to be made ready
- * @param msg message to the awakened thread
- * @note The function must be called in the system mutex zone.
- * @note The function is not meant to be used in the user code directly.
- * @note It is equivalent to a \p chSchReadyI() followed by a
- * \p chSchRescheduleS() but much more efficient.
- */
-void chSchWakeupS(Thread *ntp, msg_t msg) {
-
- ntp->p_rdymsg = msg;
- if (ntp->p_prio <= currp->p_prio)
- chSchReadyI(ntp);
- else {
- Thread *otp = currp;
- chSchReadyI(otp);
- (currp = ntp)->p_state = PRCURR;
- rlist.r_preempt = CH_TIME_QUANTUM;
-#ifdef CH_USE_TRACE
- chDbgTrace(otp, ntp);
-#endif
- chSysSwitchI(otp, ntp);
- }
-}
-
-/**
- * Performs a reschedulation. It is meant to be called if
- * \p chSchRescRequired() evaluates to \p TRUE.
- */
-void chSchDoRescheduleI(void) {
- Thread *otp = currp;
-
- chSchReadyI(otp);
- (currp = fifo_remove(&rlist.r_queue))->p_state = PRCURR;
- rlist.r_preempt = CH_TIME_QUANTUM;
-#ifdef CH_USE_TRACE
- chDbgTrace(otp, currp);
-#endif
- chSysSwitchI(otp, currp);
-}
-
-/**
- * If a thread with an higher priority than the current thread is in the
- * ready list then it becomes running.
- * @note The function must be called in the system mutex zone.
- */
-void chSchRescheduleS(void) {
-
- if (firstprio(&rlist.r_queue) > currp->p_prio)
- chSchDoRescheduleI();
-}
-
-/**
- * Evaluates if a reschedulation is required.
- * @return \p TRUE if there is a thread that should go in running state
- * immediatly else \p FALSE.
- */
-bool_t chSchRescRequiredI(void) {
- tprio_t p1 = firstprio(&rlist.r_queue);
- tprio_t p2 = currp->p_prio;
-
- return rlist.r_preempt ? p1 > p2 : p1 >= p2;
-}
-
-/** @} */
+/*
+ ChibiOS/RT - Copyright (C) 2006-2007 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/>.
+*/
+
+/**
+ * @addtogroup Scheduler
+ * @{
+ */
+
+#include <ch.h>
+
+/** @cond never */
+ReadyList rlist;
+/** @endcond */
+
+/**
+ * Scheduler initialization.
+ * @note Internally invoked by the \p chSysInit().
+ */
+void chSchInit(void) {
+
+ fifo_init(&rlist.r_queue);
+ rlist.r_prio = NOPRIO;
+ rlist.r_preempt = CH_TIME_QUANTUM;
+#ifdef CH_USE_SYSTEMTIME
+ rlist.r_stime = 0;
+#endif
+}
+
+/**
+ * Inserts a thread in the Ready List.
+ *
+ * @param tp the Thread to be made ready
+ * @return the Thread pointer
+ * @note The function must be called in the system mutex zone.
+ * @note The function does not reschedule, the \p chSchRescheduleS() should
+ * be called soon after.
+ * @note The function is not meant to be used in the user code directly.
+ */
+#ifdef CH_OPTIMIZE_SPEED
+/* NOTE: it is inlined in this module only.*/
+INLINE Thread *chSchReadyI(Thread *tp) {
+#else
+Thread *chSchReadyI(Thread *tp) {
+#endif
+ Thread *cp;
+
+ tp->p_state = PRREADY;
+ cp = rlist.r_queue.p_next;
+ while (cp->p_prio >= tp->p_prio)
+ cp = cp->p_next;
+ /* Insertion on p_prev.*/
+ tp->p_prev = (tp->p_next = cp)->p_prev;
+ tp->p_prev->p_next = cp->p_prev = tp;
+ return tp;
+}
+
+/**
+ * Puts the current thread to sleep into the specified state, the next highest
+ * priority thread becomes running. The threads states are described into
+ * \p threads.h
+ * @param newstate the new thread state
+ * @note The function must be called in the system mutex zone.
+ * @note The function is not meant to be used in the user code directly.
+ */
+void chSchGoSleepS(tstate_t newstate) {
+ Thread *otp;
+
+ (otp = currp)->p_state = newstate;
+ (currp = fifo_remove(&rlist.r_queue))->p_state = PRCURR;
+ rlist.r_preempt = CH_TIME_QUANTUM;
+#ifdef CH_USE_TRACE
+ chDbgTrace(otp, currp);
+#endif
+ chSysSwitchI(otp, currp);
+}
+
+#ifdef CH_USE_VIRTUAL_TIMERS
+/*
+ * Timeout wakeup callback.
+ */
+static void wakeup(void *p) {
+
+#ifdef CH_USE_SEMAPHORES
+ if (((Thread *)p)->p_state == PRWTSEM)
+ chSemFastSignalI(((Thread *)p)->p_wtsemp);
+#endif
+ chSchReadyI(p)->p_rdymsg = RDY_TIMEOUT;
+}
+
+/**
+ * Put the current thread to sleep.
+ *
+ * Puts the current thread to sleep into the specified state. The next highest
+ * priority thread becomes running. The thread put to sleep is awakened after
+ * the specified time has elapsed.
+ *
+ * @param newstate the new thread state
+ * @param time the number of ticks before the operation timouts
+ * @return the wakeup message, it is \p RDY_TIMEOUT if a timeout occurs
+ * @note The function must be called in the system mutex zone.
+ * @note The function is not meant to be used in the user code directly.
+ */
+msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time) {
+ VirtualTimer vt;
+
+ chVTSetI(&vt, time, wakeup, currp);
+ chSchGoSleepS(newstate);
+ if (chVTIsArmedI(&vt))
+ chVTResetI(&vt);
+ return currp->p_rdymsg;
+}
+#endif /* CH_USE_VIRTUAL_TIMERS */
+
+/**
+ * Wakes up a thread.
+ *
+ * Wakes up a thread. The thread is inserted into the ready list or immediately
+ * made running depending on its relative priority compared to the current
+ * thread.
+ * @param ntp the Thread to be made ready
+ * @param msg message to the awakened thread
+ * @note The function must be called in the system mutex zone.
+ * @note The function is not meant to be used in the user code directly.
+ * @note It is equivalent to a \p chSchReadyI() followed by a
+ * \p chSchRescheduleS() but much more efficient.
+ */
+void chSchWakeupS(Thread *ntp, msg_t msg) {
+ ntp->p_rdymsg = msg;
+ /* the woken thread has equal or lower priority than the running thread? */
+ if (ntp->p_prio <= currp->p_prio)
+ /* put the woken thread on the ready queue */
+ chSchReadyI(ntp);
+ /* the woken thread has higher priority than the running thread */
+ else {
+ /* put the running thread on the ready queue */
+ Thread *otp = currp;
+ chSchReadyI(otp);
+ (currp = ntp)->p_state = PRCURR;
+ rlist.r_preempt = CH_TIME_QUANTUM;
+#ifdef CH_USE_TRACE
+ chDbgTrace(otp, ntp);
+#endif
+ /* switch the thread context */
+ chSysSwitchI(otp, ntp);
+ }
+}
+
+/**
+ * Switch to the first thread on the runnable queue.
+ *
+ * Intended to be called if \p chSchRescRequired() evaluates to \p TRUE.
+ */
+void chSchDoRescheduleI(void) {
+ /* put the running thread on the ready queue */
+ Thread *otp = currp;
+ chSchReadyI(otp);
+ /* pick the first thread from the ready queue */
+ (currp = fifo_remove(&rlist.r_queue))->p_state = PRCURR;
+ rlist.r_preempt = CH_TIME_QUANTUM;
+#ifdef CH_USE_TRACE
+ chDbgTrace(otp, currp);
+#endif
+ /* switch thread context */
+ chSysSwitchI(otp, currp);
+}
+
+/**
+ * Reschedule only if a higher priority thread is runnable.
+ *
+ * If a thread with a higher priority than the current thread is in the
+ * ready list then make the higher priority thread running.
+ *
+ * @note The function must be called in the system mutex zone.
+ */
+void chSchRescheduleS(void) {
+ /* first thread in the runnable queue has higher priority than the running
+ * thread? */
+ if (firstprio(&rlist.r_queue) > currp->p_prio)
+ chSchDoRescheduleI();
+}
+
+/**
+ * Evaluates if rescheduling is required.
+ *
+ * @return \p TRUE if there is a thread that should go in running state
+ * immediately else \p FALSE.
+ */
+bool_t chSchRescRequiredI(void) {
+ tprio_t p1 = firstprio(&rlist.r_queue);
+ tprio_t p2 = currp->p_prio;
+ /* 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 rlist.r_preempt ? p1 > p2 : p1 >= p2;
+}
+
+/** @} */
diff --git a/src/chthreads.c b/src/chthreads.c
index e19e04acf..990b9bdba 100644
--- a/src/chthreads.c
+++ b/src/chthreads.c
@@ -1,282 +1,287 @@
-/*
- ChibiOS/RT - Copyright (C) 2006-2007 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/>.
-*/
-
-/**
- * @addtogroup Threads
- * @{
- */
-
-#include <ch.h>
-
-/*
- * Initializes a thread structure.
- */
-void init_thread(tprio_t prio, tmode_t mode, Thread *tp) {
- static tid_t nextid = 0;
-
- tp->p_tid = nextid++;
- tp->p_flags = mode;
- tp->p_prio = prio;
-#ifdef CH_USE_MUTEXES
- tp->p_realprio = prio;
- tp->p_mtxlist = NULL;
-#endif
-#ifdef CH_USE_WAITEXIT
- list_init(&tp->p_waiting);
-#endif
-#ifdef CH_USE_MESSAGES
- fifo_init(&tp->p_msgqueue);
-#endif
-#ifdef CH_USE_EVENTS
- tp->p_epending = 0;
-#endif
-#ifdef CH_USE_EXIT_EVENT
- chEvtInit(&tp->p_exitesource);
-#endif
-}
-
-#ifdef CH_USE_DEBUG
-static void memfill(uint8_t *p, uint32_t n, uint8_t v) {
-
- while (n)
- *p++ = v, n--;
-}
-#endif
-
-/**
- * Creates a new thread.
- * @param prio the priority level for the new thread. Usually the threads are
- * created with priority \p NORMALPRIO, priorities
- * can range from \p LOWPRIO to \p HIGHPRIO.
- * @param mode the creation option flags for the thread. The following options
- * can be OR'ed in this parameter:<br>
- * <ul>
- * <li>\p P_SUSPENDED, the thread is created in the
- * \p PRSUSPENDED state and a subsequent call to
- * \p chThdResume() will make it ready for
- * execution.</li>
- * <li>\p P_TERMINATED, this flag is usually set
- * by the \p chThdTerminate() function and it is not
- * normally used as parameter for this function. The
- * result would be to create a thread with a termination
- * request already pending.</li>
- * </ul>
- * @param workspace pointer to a working area dedicated to the thread stack
- * @param wsize size of the working area.
- * @param pf the thread function. Returning from this function automatically
- * terminates the thread.
- * @param 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.
- * @note A thread can terminate by calling \p chThdExit() or by simply
- * returning from its main function.
- */
-Thread *chThdCreate(tprio_t prio, tmode_t mode, void *workspace,
- size_t wsize, tfunc_t pf, void *arg) {
- Thread *tp = workspace;
-
- chDbgAssert((wsize >= UserStackSize(0)) && (prio <= HIGHPRIO) &&
- (workspace != NULL) && (pf != NULL),
- "chthreads.c, chThdCreate()");
-#ifdef CH_USE_DEBUG
- memfill(workspace, wsize, MEM_FILL_PATTERN);
-#endif
- SETUP_CONTEXT(workspace, wsize, pf, arg);
- init_thread(prio, mode, tp);
-#ifdef CH_USE_RESUME
- if (tp->p_flags & P_SUSPENDED)
- tp->p_state = PRSUSPENDED;
- else {
-#endif
- chSysLock();
- chSchWakeupS(tp, RDY_OK);
- chSysUnlock();
-#ifdef CH_USE_RESUME
- }
-#endif
- return tp;
-}
-
-/**
- * Creates a new thread.
- * @param prio the priority level for the new thread. Usually the threads are
- * created with priority \p NORMALPRIO, priorities
- * can range from \p LOWPRIO to \p HIGHPRIO.
- * @param workspace pointer to a working area dedicated to the thread stack
- * @param wsize size of the working area.
- * @param pf the thread function. Returning from this function automatically
- * terminates the thread.
- * @return the pointer to the \p Thread structure allocated for the
- * thread into the working space area.
- * @note A thread can terminate by calling \p chThdExit() or by simply
- * returning from its main function.
- */
-Thread *chThdCreateFast(tprio_t prio, void *workspace,
- size_t wsize, tfunc_t pf) {
- Thread *tp = workspace;
-
- chDbgAssert((wsize >= UserStackSize(0)) && (prio <= HIGHPRIO) &&
- (workspace != NULL) && (pf != NULL),
- "chthreads.c, chThdCreateFast()");
-#ifdef CH_USE_DEBUG
- memfill(workspace, wsize, MEM_FILL_PATTERN);
-#endif
- SETUP_CONTEXT(workspace, wsize, pf, NULL);
- init_thread(prio, 0, tp);
- chSysLock();
- chSchWakeupS(tp, RDY_OK);
- chSysUnlock();
- return tp;
-}
-
-/**
- * Changes the thread priority, reschedules if necessary.
- * @param newprio the new priority of the invoking thread
- */
-void chThdSetPriority(tprio_t newprio) {
-
- chDbgAssert(newprio <= HIGHPRIO, "chthreads.c, chThdSetPriority()")
- chSysLock();
-
-#ifdef CH_USE_MUTEXES
- if (currp->p_prio != currp->p_realprio) {
- if (newprio > currp->p_prio)
- currp->p_prio = newprio;
- }
- else
- currp->p_prio = newprio;
- currp->p_realprio = newprio;
-#else
- currp->p_prio = newprio;
-#endif
- chSchRescheduleS();
-
- chSysUnlock();
-}
-
-#ifdef CH_USE_SUSPEND
-/**
- * Suspends the invoking thread.
- *
- * @param tpp pointer to a \p Thread pointer, the \p Thread pointer is set
- * to point to the suspended process before it enters the
- * \p PRSUSPENDED state, it is set to \p NULL after it is resumed.
- * This allows to implement a "test and resume" on the variable
- * into interrupt handlers.
- * @note The function is available only if the \p CH_USE_SUSPEND
- * option is enabled in \p chconf.h.
- */
-void chThdSuspend(Thread **tpp) {
-
- chSysLock();
-
- chDbgAssert(*tpp == NULL, "chthreads.c, chThdSuspend()");
- *tpp = currp;
- chSchGoSleepS(PRSUSPENDED);
- *tpp = NULL;
-
- chSysUnlock();
-}
-#endif /* CH_USE_SUSPEND */
-
-#ifdef CH_USE_RESUME
-/**
- * Resumes a thread created with the \p P_SUSPENDED option or suspended with
- * \p chThdSuspend().
- * @param tp the pointer to the thread
- * @note The function has no effect on threads in any other state than
- * \p PRSUSPENDED.
- * @note The function is available only if the \p CH_USE_RESUME
- * option is enabled in \p chconf.h.
- */
-void chThdResume(Thread *tp) {
-
- chSysLock();
-
- if ((tp)->p_state == PRSUSPENDED)
- chSchWakeupS(tp, RDY_OK);
-
- chSysUnlock();
-}
-#endif
-
-#ifdef CH_USE_TERMINATE
-/**
- * Requests a thread termination.
- * @param tp the pointer to the thread
- * @note The thread is not termitated but a termination request is added to
- * its \p p_flags field. The thread can read this status by
- * invoking \p chThdShouldTerminate() and then terminate cleanly.
- */
-void chThdTerminate(Thread *tp) {
-
- chSysLock();
-
- tp->p_flags |= P_TERMINATE;
-
- chSysUnlock();
-}
-#endif
-
-/**
- * Terminates the current thread by specifying an exit status code.
- * @param msg the thread exit code. The code can be retrieved by using
- * \p chThdWait().
- */
-void chThdExit(msg_t msg) {
-
- chSysLock();
-
- currp->p_exitcode = msg;
-#ifdef CH_USE_WAITEXIT
- while (notempty(&currp->p_waiting))
- chSchReadyI(list_remove(&currp->p_waiting));
-#endif
-#ifdef CH_USE_EXIT_EVENT
- chEvtSendI(&currp->p_exitesource);
-#endif
- chSchGoSleepS(PREXIT);
-}
-
-#ifdef CH_USE_WAITEXIT
-/**
- * Blocks the execution of the invoking thread until the specified thread
- * terminates then the exit code is returned.
- * @param tp the pointer to the thread
- * @return the exit code
- * @note The function is available only if the \p CH_USE_WAITEXIT
- * option is enabled in \p chconf.h.
- */
-msg_t chThdWait(Thread *tp) {
- msg_t msg;
-
- chSysLock();
-
- if (tp->p_state != PREXIT) {
- list_insert(currp, &tp->p_waiting);
- chSchGoSleepS(PRWAIT);
- }
- msg = tp->p_exitcode;
-
- chSysUnlock();
- return msg;
-}
-#endif /* CH_USE_WAITEXIT */
-
-/** @} */
+/*
+ ChibiOS/RT - Copyright (C) 2006-2007 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/>.
+*/
+
+/**
+ * @addtogroup Threads
+ * @{
+ */
+
+#include <ch.h>
+
+/*
+ * Initializes a thread structure.
+ */
+void init_thread(tprio_t prio, tmode_t mode, Thread *tp) {
+ static tid_t nextid = 0;
+
+ tp->p_tid = nextid++;
+ tp->p_flags = mode;
+ tp->p_prio = prio;
+#ifdef CH_USE_MUTEXES
+ /* realprio is the thread's own, non-inherited, priority */
+ tp->p_realprio = prio;
+ tp->p_mtxlist = NULL;
+#endif
+#ifdef CH_USE_WAITEXIT
+ list_init(&tp->p_waiting);
+#endif
+#ifdef CH_USE_MESSAGES
+ fifo_init(&tp->p_msgqueue);
+#endif
+#ifdef CH_USE_EVENTS
+ tp->p_epending = 0;
+#endif
+#ifdef CH_USE_EXIT_EVENT
+ chEvtInit(&tp->p_exitesource);
+#endif
+}
+
+#ifdef CH_USE_DEBUG
+static void memfill(uint8_t *p, uint32_t n, uint8_t v) {
+
+ while (n)
+ *p++ = v, n--;
+}
+#endif
+
+/**
+ * Creates a new thread.
+ * @param prio the priority level for the new thread. Usually the threads are
+ * created with priority \p NORMALPRIO, priorities
+ * can range from \p LOWPRIO to \p HIGHPRIO.
+ * @param mode the creation option flags for the thread. The following options
+ * can be OR'ed in this parameter:<br>
+ * <ul>
+ * <li>\p P_SUSPENDED, the thread is created in the
+ * \p PRSUSPENDED state and a subsequent call to
+ * \p chThdResume() will make it ready for
+ * execution.</li>
+ * <li>\p P_TERMINATED, this flag is usually set
+ * by the \p chThdTerminate() function and it is not
+ * normally used as parameter for this function. The
+ * result would be to create a thread with a termination
+ * request already pending.</li>
+ * </ul>
+ * @param workspace pointer to a working area dedicated to the thread stack
+ * @param wsize size of the working area.
+ * @param pf the thread function. Returning from this function automatically
+ * terminates the thread.
+ * @param 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.
+ * @note A thread can terminate by calling \p chThdExit() or by simply
+ * returning from its main function.
+ */
+Thread *chThdCreate(tprio_t prio, tmode_t mode, void *workspace,
+ size_t wsize, tfunc_t pf, void *arg) {
+ /* thread structure is layed out in the lower part of the thread workspace */
+ Thread *tp = workspace;
+
+ chDbgAssert((wsize >= UserStackSize(0)) && (prio <= HIGHPRIO) &&
+ (workspace != NULL) && (pf != NULL),
+ "chthreads.c, chThdCreate()");
+#ifdef CH_USE_DEBUG
+ memfill(workspace, wsize, MEM_FILL_PATTERN);
+#endif
+ SETUP_CONTEXT(workspace, wsize, pf, arg);
+ init_thread(prio, mode, tp);
+#ifdef CH_USE_RESUME
+ if (tp->p_flags & P_SUSPENDED)
+ tp->p_state = PRSUSPENDED;
+ else {
+#endif
+ chSysLock();
+ chSchWakeupS(tp, RDY_OK);
+ chSysUnlock();
+#ifdef CH_USE_RESUME
+ }
+#endif
+ return tp;
+}
+
+/**
+ * Creates a new thread.
+ * @param prio the priority level for the new thread. Usually the threads are
+ * created with priority \p NORMALPRIO, priorities
+ * can range from \p LOWPRIO to \p HIGHPRIO.
+ * @param workspace pointer to a working area dedicated to the thread stack
+ * @param wsize size of the working area.
+ * @param pf the thread function. Returning from this function automatically
+ * terminates the thread.
+ * @return the pointer to the \p Thread structure allocated for the
+ * thread into the working space area.
+ * @note A thread can terminate by calling \p chThdExit() or by simply
+ * returning from its main function.
+ */
+Thread *chThdCreateFast(tprio_t prio, void *workspace,
+ size_t wsize, tfunc_t pf) {
+ Thread *tp = workspace;
+
+ chDbgAssert((wsize >= UserStackSize(0)) && (prio <= HIGHPRIO) &&
+ (workspace != NULL) && (pf != NULL),
+ "chthreads.c, chThdCreateFast()");
+#ifdef CH_USE_DEBUG
+ memfill(workspace, wsize, MEM_FILL_PATTERN);
+#endif
+ SETUP_CONTEXT(workspace, wsize, pf, NULL);
+ init_thread(prio, 0, tp);
+ chSysLock();
+ chSchWakeupS(tp, RDY_OK);
+ chSysUnlock();
+ return tp;
+}
+
+/**
+ * Changes the running thread priority, reschedules if necessary.
+ *
+ * @param newprio the new priority of the running thread
+ */
+void chThdSetPriority(tprio_t newprio) {
+
+ chDbgAssert(newprio <= HIGHPRIO, "chthreads.c, chThdSetPriority()")
+ chSysLock();
+
+#ifdef CH_USE_MUTEXES
+ if (currp->p_prio != currp->p_realprio) {
+ if (newprio > currp->p_prio)
+ currp->p_prio = newprio;
+ }
+ else
+ currp->p_prio = newprio;
+ currp->p_realprio = newprio;
+#else
+ currp->p_prio = newprio;
+#endif
+ chSchRescheduleS();
+
+ chSysUnlock();
+}
+
+#ifdef CH_USE_SUSPEND
+/**
+ * Suspends the invoking thread.
+ *
+ * @param tpp pointer to a \p Thread pointer, the \p Thread pointer is set
+ * to point to the suspended process before it enters the
+ * \p PRSUSPENDED state, it is set to \p NULL after it is resumed.
+ * This allows to implement a "test and resume" on the variable
+ * into interrupt handlers.
+ * @note The function is available only if the \p CH_USE_SUSPEND
+ * option is enabled in \p chconf.h.
+ */
+void chThdSuspend(Thread **tpp) {
+
+ chSysLock();
+
+ chDbgAssert(*tpp == NULL, "chthreads.c, chThdSuspend()");
+ *tpp = currp;
+ chSchGoSleepS(PRSUSPENDED);
+ *tpp = NULL;
+
+ chSysUnlock();
+}
+#endif /* CH_USE_SUSPEND */
+
+#ifdef CH_USE_RESUME
+/**
+ * Resumes a thread created with the \p P_SUSPENDED option or suspended with
+ * \p chThdSuspend().
+ * @param tp the pointer to the thread
+ * @note The function has no effect on threads in any other state than
+ * \p PRSUSPENDED.
+ * @note The function is available only if the \p CH_USE_RESUME
+ * option is enabled in \p chconf.h.
+ */
+void chThdResume(Thread *tp) {
+
+ chSysLock();
+
+ if ((tp)->p_state == PRSUSPENDED)
+ chSchWakeupS(tp, RDY_OK);
+
+ chSysUnlock();
+}
+#endif
+
+#ifdef CH_USE_TERMINATE
+/**
+ * Requests a thread termination.
+ * @param tp the pointer to the thread
+ * @note The thread is not termitated but a termination request is added to
+ * its \p p_flags field. The thread can read this status by
+ * invoking \p chThdShouldTerminate() and then terminate cleanly.
+ */
+void chThdTerminate(Thread *tp) {
+
+ chSysLock();
+
+ tp->p_flags |= P_TERMINATE;
+
+ chSysUnlock();
+}
+#endif
+
+/**
+ * Terminates the current thread by specifying an exit status code.
+ *
+ * @param msg the thread exit code. The code can be retrieved by using
+ * \p chThdWait().
+ */
+void chThdExit(msg_t msg) {
+
+ chSysLock();
+
+ currp->p_exitcode = msg;
+#ifdef CH_USE_WAITEXIT
+ while (notempty(&currp->p_waiting))
+ chSchReadyI(list_remove(&currp->p_waiting));
+#endif
+#ifdef CH_USE_EXIT_EVENT
+ chEvtSendI(&currp->p_exitesource);
+#endif
+ chSchGoSleepS(PREXIT);
+}
+
+#ifdef CH_USE_WAITEXIT
+/**
+ * Blocks the execution of the invoking thread until the specified thread
+ * terminates then the exit code is returned.
+ *
+ * @param tp the pointer to the thread
+ * @return the exit code
+ * @note The function is available only if the \p CH_USE_WAITEXIT
+ * option is enabled in \p chconf.h.
+ */
+msg_t chThdWait(Thread *tp) {
+ msg_t msg;
+
+ chSysLock();
+
+ if (tp->p_state != PREXIT) {
+ list_insert(currp, &tp->p_waiting);
+ chSchGoSleepS(PRWAIT);
+ }
+ msg = tp->p_exitcode;
+
+ chSysUnlock();
+ return msg;
+}
+#endif /* CH_USE_WAITEXIT */
+
+/** @} */
diff --git a/src/include/queues.h b/src/include/queues.h
index 5c480e8cf..0a373b5ea 100644
--- a/src/include/queues.h
+++ b/src/include/queues.h
@@ -1,184 +1,184 @@
-/*
- ChibiOS/RT - Copyright (C) 2006-2007 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/>.
-*/
-
-/**
- * @addtogroup IOQueues
- * @{
- */
-
-#ifndef _QUEUES_H_
-#define _QUEUES_H_
-
-/** Queue notification callback type.*/
-typedef void (*qnotify_t)(void);
-
-/** Returned by the queue functions if the operation is successful.*/
-#define Q_OK RDY_OK
-/** Returned by the queue functions if a timeout occurs.*/
-#define Q_TIMEOUT RDY_TIMEOUT
-/** Returned by the queue functions if the queue is reset.*/
-#define Q_RESET RDY_RESET
-/** Returned by the queue functions if the queue is empty.*/
-#define Q_EMPTY -3
-/** Returned by the queue functions if the queue is full.*/
-#define Q_FULL -4
-
-#ifdef CH_USE_QUEUES
-/**
- * I/O queue structure, it is used by both Input and Output Queues,
- * the difference is on how the semaphore is initialized.
- */
-typedef struct {
- /** Pointer to the queue buffer.*/
- uint8_t *q_buffer;
- /** Pointer to the first location after the buffer.*/
- uint8_t *q_top;
- /** Write pointer.*/
- uint8_t *q_wrptr;
- /** Read pointer.*/
- uint8_t *q_rdptr;
- /** Counter semaphore.*/
- Semaphore q_sem;
- /** Data notification callback.*/
- qnotify_t q_notify;
-} Queue;
-
-/** Returns the queue's buffer size.*/
-#define chQSize(q) \
- ((q)->q_top - (q)->q_buffer)
-
-/** Returns the used space if used on an Input Queue and the empty space if
- * used on an Output Queue.*/
-#define chQSpace(q) \
- ((q)->q_sem.s_cnt)
-
-/** Evaluates to TRUE if the specified Input Queue is empty.*/
-#define chIQIsEmpty(q) \
- (chQSpace(q) <= 0)
-
-/** Evaluates to TRUE if the specified Input Queue is full.*/
-#define chIQIsFull(q) \
- (chQSpace(q) >= chQSize(q))
-
-/** Evaluates to TRUE if the specified Output Queue is empty.*/
-#define chOQIsEmpty(q) \
- (chQSpace(q) >= chQSize(q))
-
-/** Evaluates to TRUE if the specified Output Queue is full.*/
-#define chOQIsFull(q) \
- (chQSpace(q) <= 0)
-
-#ifdef __cplusplus
-extern "C" {
-#endif
- /*
- * Input Queues functions. An Input Queue is usually written into by an
- * interrupt handler and read from a thread.
- */
- void chIQInit(Queue *qp, uint8_t *buffer, size_t size, qnotify_t inotify);
- void chIQReset(Queue *qp);
- msg_t chIQPutI(Queue *qp, uint8_t b);
- msg_t chIQGet(Queue *qp);
- size_t chIQRead(Queue *qp, uint8_t *buffer, size_t n);
-#ifdef CH_USE_QUEUES_TIMEOUT
- msg_t chIQGetTimeout(Queue *qp, systime_t time);
-#endif
-
- /*
- * Output Queues functions. An Output Queue is usually written into by a
- * thread and read from an interrupt handler.
- */
- void chOQInit(Queue *queue, uint8_t *buffer, size_t size, qnotify_t onotify);
- void chOQReset(Queue *queue);
- void chOQPut(Queue *queue, uint8_t b);
- msg_t chOQGetI(Queue *queue);
- size_t chOQWrite(Queue *queue, uint8_t *buffer, size_t n);
-#ifdef __cplusplus
-}
-#endif
-#endif /* CH_USE_QUEUES */
-
-#ifdef CH_USE_QUEUES_HALFDUPLEX
-/**
- * Half duplex queue structure.
- */
-typedef struct {
- /** Pointer to the queue buffer.*/
- uint8_t *hdq_buffer;
- /** Pointer to the first location after the buffer.*/
- uint8_t *hdq_top;
- /** Write pointer.*/
- uint8_t *hdq_wrptr;
- /** Read pointer.*/
- uint8_t *hdq_rdptr;
- /** Input counter semaphore.*/
- Semaphore hdq_isem;
- /** Output counter semaphore.*/
- Semaphore hdq_osem;
- /** Input data notification callback.*/
- qnotify_t hdq_inotify;
- /** Output data notification callback.*/
- qnotify_t hdq_onotify;
-} HalfDuplexQueue;
-
-/** Returns the queue's buffer size.*/
-#define chHDQSize(q) \
- ((q)->hdq_top - (q)->hdq_buffer)
-
-/** Returns the queue space when in transmission mode.*/
-#define chHDQEmptySpace(q) \
- ((q)->hdq_osem.s_cnt)
-
-/** Returns the number of the bytes in the queue when in receive mode.*/
-#define chHDQFilledSpace(q) \
- ((q)->hdq_isem.s_cnt)
-
-/** Evaluates to TRUE if the queue is in transmit mode.*/
-#define chHDQIsTransmitting(q) \
- (chHDQEmptySpace(q) < chHDQSize(q))
-
-/** Evaluates to TRUE if the queue is in receive mode.*/
-#define chHDQIsReceiving(q) \
- (chHDQEmptySpaceQ(q) >= chHDQSize(q))
-
-/** Evaluates to TRUE if the receive queue is full.*/
-#define chHDQIsFullReceive(q) \
- (chHDQFilledSpace(q) >= chHDQSize(q))
-
-#ifdef __cplusplus
-extern "C" {
-#endif
- void chHDQInit(HalfDuplexQueue *qp, uint8_t *buffer, size_t size,
- qnotify_t inotify, qnotify_t onotify);
- msg_t chHDQGetReceive(HalfDuplexQueue *qp);
- void chHDQPutTransmit(HalfDuplexQueue *qp, uint8_t b);
- msg_t chHDQGetTransmitI(HalfDuplexQueue *qp);
- msg_t chHDQPutReceiveI(HalfDuplexQueue *qp, uint8_t b);
-#ifdef CH_USE_QUEUES_TIMEOUT
- msg_t chHDQGetReceiveTimeout(HalfDuplexQueue *qp, systime_t time);
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* CH_USE_QUEUES_HALFDUPLEX */
-
-#endif /* _QUEUES_H_ */
-
-/** @} */
+/*
+ ChibiOS/RT - Copyright (C) 2006-2007 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/>.
+*/
+
+/**
+ * @addtogroup IOQueues
+ * @{
+ */
+
+#ifndef _QUEUES_H_
+#define _QUEUES_H_
+
+/** Queue notification callback type. */
+typedef void (*qnotify_t)(void);
+
+/** Returned by the queue functions if the operation is successful. */
+#define Q_OK RDY_OK
+/** Returned by the queue functions if a timeout occurs. */
+#define Q_TIMEOUT RDY_TIMEOUT
+/** Returned by the queue functions if the queue is reset. */
+#define Q_RESET RDY_RESET
+/** Returned by the queue functions if the queue is empty. */
+#define Q_EMPTY -3
+/** Returned by the queue functions if the queue is full. */
+#define Q_FULL -4
+
+#ifdef CH_USE_QUEUES
+/**
+ * I/O queue structure, it is used by both Input and Output Queues,
+ * the difference is on how the semaphore is initialized.
+ */
+typedef struct {
+ /** Pointer to the queue buffer. */
+ uint8_t *q_buffer;
+ /** Pointer to the first location after the buffer. */
+ uint8_t *q_top;
+ /** Write pointer. */
+ uint8_t *q_wrptr;
+ /** Read pointer. */
+ uint8_t *q_rdptr;
+ /** Counter semaphore. */
+ Semaphore q_sem;
+ /** Data notification callback. */
+ qnotify_t q_notify;
+} Queue;
+
+/** Returns the queue's buffer size. */
+#define chQSize(q) \
+ ((q)->q_top - (q)->q_buffer)
+
+/** Returns the used space if used on an Input Queue and the empty space if
+ * used on an Output Queue. */
+#define chQSpace(q) \
+ ((q)->q_sem.s_cnt)
+
+/** Evaluates to TRUE if the specified Input Queue is empty. */
+#define chIQIsEmpty(q) \
+ (chQSpace(q) <= 0)
+
+/** Evaluates to TRUE if the specified Input Queue is full. */
+#define chIQIsFull(q) \
+ (chQSpace(q) >= chQSize(q))
+
+/** Evaluates to TRUE if the specified Output Queue is empty. */
+#define chOQIsEmpty(q) \
+ (chQSpace(q) >= chQSize(q))
+
+/** Evaluates to TRUE if the specified Output Queue is full. */
+#define chOQIsFull(q) \
+ (chQSpace(q) <= 0)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ /*
+ * Input Queues functions. An Input Queue is usually written into by an
+ * interrupt handler and read from a thread.
+ */
+ void chIQInit(Queue *qp, uint8_t *buffer, size_t size, qnotify_t inotify);
+ void chIQReset(Queue *qp);
+ msg_t chIQPutI(Queue *qp, uint8_t b);
+ msg_t chIQGet(Queue *qp);
+ size_t chIQRead(Queue *qp, uint8_t *buffer, size_t n);
+#ifdef CH_USE_QUEUES_TIMEOUT
+ msg_t chIQGetTimeout(Queue *qp, systime_t time);
+#endif
+
+ /*
+ * Output Queues functions. An Output Queue is usually written into by a
+ * thread and read from an interrupt handler.
+ */
+ void chOQInit(Queue *queue, uint8_t *buffer, size_t size, qnotify_t onotify);
+ void chOQReset(Queue *queue);
+ void chOQPut(Queue *queue, uint8_t b);
+ msg_t chOQGetI(Queue *queue);
+ size_t chOQWrite(Queue *queue, uint8_t *buffer, size_t n);
+#ifdef __cplusplus
+}
+#endif
+#endif /* CH_USE_QUEUES */
+
+#ifdef CH_USE_QUEUES_HALFDUPLEX
+/**
+ * Half duplex queue structure.
+ */
+typedef struct {
+ /** Pointer to the queue buffer. */
+ uint8_t *hdq_buffer;
+ /** Pointer to the first location after the buffer. */
+ uint8_t *hdq_top;
+ /** Write pointer.*/
+ uint8_t *hdq_wrptr;
+ /** Read pointer.*/
+ uint8_t *hdq_rdptr;
+ /** Input counter semaphore. */
+ Semaphore hdq_isem;
+ /** Output counter semaphore. */
+ Semaphore hdq_osem;
+ /** Input data notification callback. */
+ qnotify_t hdq_inotify;
+ /** Output data notification callback. */
+ qnotify_t hdq_onotify;
+} HalfDuplexQueue;
+
+/** Returns the queue's buffer size. */
+#define chHDQSize(q) \
+ ((q)->hdq_top - (q)->hdq_buffer)
+
+/** Returns the queue space when in transmission mode. */
+#define chHDQEmptySpace(q) \
+ ((q)->hdq_osem.s_cnt)
+
+/** Returns the number of the bytes in the queue when in receive mode. */
+#define chHDQFilledSpace(q) \
+ ((q)->hdq_isem.s_cnt)
+
+/** Evaluates to TRUE if the queue is in transmit mode. */
+#define chHDQIsTransmitting(q) \
+ (chHDQEmptySpace(q) < chHDQSize(q))
+
+/** Evaluates to TRUE if the queue is in receive mode. */
+#define chHDQIsReceiving(q) \
+ (chHDQEmptySpaceQ(q) >= chHDQSize(q))
+
+/** Evaluates to TRUE if the receive queue is full. */
+#define chHDQIsFullReceive(q) \
+ (chHDQFilledSpace(q) >= chHDQSize(q))
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void chHDQInit(HalfDuplexQueue *qp, uint8_t *buffer, size_t size,
+ qnotify_t inotify, qnotify_t onotify);
+ msg_t chHDQGetReceive(HalfDuplexQueue *qp);
+ void chHDQPutTransmit(HalfDuplexQueue *qp, uint8_t b);
+ msg_t chHDQGetTransmitI(HalfDuplexQueue *qp);
+ msg_t chHDQPutReceiveI(HalfDuplexQueue *qp, uint8_t b);
+#ifdef CH_USE_QUEUES_TIMEOUT
+ msg_t chHDQGetReceiveTimeout(HalfDuplexQueue *qp, systime_t time);
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CH_USE_QUEUES_HALFDUPLEX */
+
+#endif /* _QUEUES_H_ */
+
+/** @} */
diff --git a/src/include/scheduler.h b/src/include/scheduler.h
index 0235a7c97..3a6486efe 100644
--- a/src/include/scheduler.h
+++ b/src/include/scheduler.h
@@ -1,80 +1,82 @@
-/*
- ChibiOS/RT - Copyright (C) 2006-2007 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/>.
-*/
-
-/**
- * @addtogroup Scheduler
- * @{
- */
-
-#ifndef _SCHEDULER_H_
-#define _SCHEDULER_H_
-
-/** Normal \p chSchReadyI() message.*/
-#define RDY_OK 0
-/** Returned if the thread was made ready because a timeout.*/
-#define RDY_TIMEOUT -1
-/** Returned if the thread was made ready because a reset.*/
-#define RDY_RESET -2
-
-#define firstprio(rlp) ((rlp)->p_next->p_prio)
-
-/**
- * Ready list header.
- */
-typedef struct {
- ThreadsQueue r_queue;
- tprio_t r_prio;
- cnt_t r_preempt;
-#ifndef CH_CURRP_REGISTER_CACHE
- Thread *r_current;
-#endif
-#ifdef CH_USE_SYSTEMTIME
- volatile systime_t r_stime;
-#endif
-} ReadyList;
-
-extern ReadyList rlist;
-
-/*
- * Scheduler APIs.
- */
-#ifdef __cplusplus
-extern "C" {
-#endif
- void chSchInit(void);
- Thread *chSchReadyI(Thread *tp);
- void chSchGoSleepS(tstate_t newstate);
- msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time);
- void chSchWakeupS(Thread *tp, msg_t msg);
- void chSchDoRescheduleI(void);
- void chSchRescheduleS(void);
- bool_t chSchRescRequiredI(void);
-#ifdef __cplusplus
-}
-#endif
-
-#ifdef CH_CURRP_REGISTER_CACHE
-register Thread *currp asm(CH_CURRP_REGISTER_CACHE);
-#else
-#define currp rlist.r_current
-#endif
-
-#endif /* _SCHEDULER_H_ */
-
-/** @} */
+/*
+ ChibiOS/RT - Copyright (C) 2006-2007 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/>.
+*/
+
+/**
+ * @addtogroup Scheduler
+ * @{
+ */
+
+#ifndef _SCHEDULER_H_
+#define _SCHEDULER_H_
+
+/** Normal \p chSchReadyI() message. */
+#define RDY_OK 0
+/** Returned when the thread was made ready because of a timeout. */
+#define RDY_TIMEOUT -1
+/** Returned when the thread was made ready because of a reset. */
+#define RDY_RESET -2
+
+/** The priority of the first thread on the given ready list. */
+#define firstprio(rlp) ((rlp)->p_next->p_prio)
+
+/**
+ * Ready list header.
+ */
+typedef struct {
+ ThreadsQueue r_queue;
+ tprio_t r_prio;
+ cnt_t r_preempt;
+#ifndef CH_CURRP_REGISTER_CACHE
+ /** the currently running thread */
+ Thread *r_current;
+#endif
+#ifdef CH_USE_SYSTEMTIME
+ volatile systime_t r_stime;
+#endif
+} ReadyList;
+
+extern ReadyList rlist;
+
+/*
+ * Scheduler APIs.
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void chSchInit(void);
+ Thread *chSchReadyI(Thread *tp);
+ void chSchGoSleepS(tstate_t newstate);
+ msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time);
+ void chSchWakeupS(Thread *tp, msg_t msg);
+ void chSchDoRescheduleI(void);
+ void chSchRescheduleS(void);
+ bool_t chSchRescRequiredI(void);
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef CH_CURRP_REGISTER_CACHE
+register Thread *currp asm(CH_CURRP_REGISTER_CACHE);
+#else
+#define currp rlist.r_current
+#endif
+
+#endif /* _SCHEDULER_H_ */
+
+/** @} */
diff --git a/src/include/threads.h b/src/include/threads.h
index 5bfd51423..b7b1a3e29 100644
--- a/src/include/threads.h
+++ b/src/include/threads.h
@@ -1,241 +1,242 @@
-/*
- ChibiOS/RT - Copyright (C) 2006-2007 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/>.
-*/
-
-/**
- * @addtogroup Threads
- * @{
- */
-
-#ifndef _THREADS_H_
-#define _THREADS_H_
-
-/**
- * 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 {
- /** Next \p Thread in the threads list.*/
- Thread *p_next;
- /* End of the fields shared with the ThreadsList structure. */
- /** Previous \p Thread in the threads list.*/
- Thread *p_prev;
- /* End of the fields shared with the ThreadsQueue structure. */
- /** The thread priority.*/
- tprio_t p_prio;
- /* End of the fields shared with the ReadyList structure. */
- /** Thread identifier. */
- tid_t p_tid;
- /** Current thread state.*/
- tstate_t p_state;
- /** Mode flags.*/
- tmode_t p_flags;
- /** Machine dependent processor context.*/
- Context p_ctx;
- /*
- * The following fields are merged in unions because they are all
- * state-specific fields. This trick saves some extra space for each
- * thread in the system.
- */
- union {
- /** Thread wakeup code (only valid when exiting the \p PRREADY state).*/
- msg_t p_rdymsg;
- /** The thread exit code (only while in \p PREXIT state).*/
- msg_t p_exitcode;
-#ifdef CH_USE_SEMAPHORES
- /** Semaphore where the thread is waiting on (only in \p PRWTSEM state).*/
- Semaphore *p_wtsemp;
-#endif
-#ifdef CH_USE_MUTEXES
- /** Mutex where the thread is waiting on (only in \p PRWTMTX state).*/
- Mutex *p_wtmtxp;
-#endif
-#ifdef CH_USE_MESSAGES
- /** Destination thread for message send (only in \p PRSNDMSG state).*/
- Thread *p_wtthdp;
-#endif
-#ifdef CH_USE_EVENTS
- /** Enabled events mask (only while in \p PRWTEVENT state).*/
- eventmask_t p_ewmask;
-#endif
-#ifdef CH_USE_TRACE
- /** Kernel object where the thread is waiting on. It is only valid when
- the thread is some sleeping states.*/
- void *p_wtobjp;
-#endif
- };
- /*
- * Start of the optional fields.
- */
-#ifdef CH_USE_WAITEXIT
- /** The list of the threads waiting for this thread termination.*/
- ThreadsList p_waiting;
-#endif
-#ifdef CH_USE_EXIT_EVENT
- /** The thread termination \p EventSource.*/
- EventSource p_exitesource;
-#endif
-#ifdef CH_USE_MESSAGES
- ThreadsQueue p_msgqueue;
- msg_t p_msg;
-#endif
-#ifdef CH_USE_EVENTS
- /** Pending events mask.*/
- eventmask_t p_epending;
-#endif
-#ifdef CH_USE_MUTEXES
- /** Owner mutexes list, \p NULL terminated.*/
- Mutex *p_mtxlist;
- tprio_t p_realprio;
-#endif
-};
-
-/** Thread state: Thread in the ready list.*/
-#define PRREADY 0
-/** Thread state: Current.*/
-#define PRCURR 1
-/** Thread state: Thread created in suspended state.*/
-#define PRSUSPENDED 2
-/** Thread state: Waiting on a semaphore.*/
-#define PRWTSEM 3
-/** Thread state: Waiting on a mutex.*/
-#define PRWTMTX 4
-/** Thread state: Waiting in \p chThdSleep() or \p chThdSleepUntil().*/
-#define PRSLEEP 5
-/** Thread state: Waiting in \p chThdWait().*/
-#define PRWAIT 6
-/** Thread state: Waiting in \p chEvtWait().*/
-#define PRWTEVENT 7
-/** Thread state: Waiting in \p chMsgSend().*/
-#define PRSNDMSG 8
-/** Thread state: Waiting in \p chMsgWait().*/
-#define PRWTMSG 9
-/** Thread state: After termination.*/
-#define PREXIT 10
-
-#ifdef CH_USE_TERMINATE
-/** Thread option: Termination requested flag.*/
-#define P_TERMINATE 1
-#endif
-#ifdef CH_USE_RESUME
-/** Thread option: Create suspended thread.*/
-#define P_SUSPENDED 2
-#endif
-#ifdef CH_USE_MESSAGES_PRIORITY
-/** Thread option: Serve messages by priority instead of FIFO order.*/
-#define P_MSGBYPRIO 4
-#endif
-
-/** Pseudo priority used by the ready list header, do not use.*/
-#define NOPRIO 0
-/** Idle thread priority.*/
-#define IDLEPRIO 1
-/** Lowest user priority.*/
-#define LOWPRIO 2
-/** Normal user priority.*/
-#define NORMALPRIO 64
-/** Highest user priority.*/
-#define HIGHPRIO 127
-/** Greatest possible priority.*/
-#define ABSPRIO 255
-
-/* Not an API, don't use into the application code.*/
-void init_thread(tprio_t prio, tmode_t mode, Thread *tp);
-
-/** Thread function.*/
-typedef msg_t (*tfunc_t)(void *);
-
-/*
- * Threads APIs.
- */
-#ifdef __cplusplus
-extern "C" {
-#endif
- Thread *chThdCreate(tprio_t prio, tmode_t mode, void *workspace,
- size_t wsize, tfunc_t pf, void *arg);
- Thread *chThdCreateFast(tprio_t prio, void *workspace,
- size_t wsize, tfunc_t pf);
- void chThdSetPriority(tprio_t newprio);
- void chThdExit(msg_t msg);
-#ifdef CH_USE_RESUME
- void chThdResume(Thread *tp);
-#endif
-#ifdef CH_USE_SUSPEND
- void chThdSuspend(Thread **tpp);
-#endif
-#ifdef CH_USE_TERMINATE
- void chThdTerminate(Thread *tp);
-#endif
-#ifdef CH_USE_WAITEXIT
- msg_t chThdWait(Thread *tp);
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-/** Returns the pointer to the \p Thread currently in execution.*/
-#define chThdSelf() currp
-
-/** Returns the thread priority.*/
-#define chThdGetPriority() (currp->p_prio)
-
-/** Returns the pointer to the \p Thread local storage area, if any.*/
-#define chThdLS() (void *)(currp + 1)
-
-/** Verifies if the specified thread is in the \p PREXIT state.*/
-#define chThdTerminated(tp) ((tp)->p_state == PREXIT)
-
-/**
- * Verifies if the current thread has a termination request pending.
- */
-#define chThdShouldTerminate() (currp->p_flags & P_TERMINATE)
-
-/**
- * Returns the exit event source for the specified thread. The source is
- * signaled when the thread terminates.
- * @param tp the pointer to the thread
- * @note When registering on a thread termination make sure the thread
- * is still alive, if you do that after the thread termination
- * then you would miss the event. There are two ways to ensure
- * this:<br>
- * <ul>
- * <li>Create the thread suspended, register on the event source
- * and then resume the thread (recommended).</li>
- * <li>Create the thread with a lower priority then register on it.
- * This does not work if the hardware is capable of multiple
- * physical threads.</li>
- * </ul>
- * @note You dont need to unregister from a terminated thread because
- * the event source becomes inactive.
- * @note The function is available only if the \p CH_USE_EXIT_EVENT
- * option is enabled in \p chconf.h.
- */
-#define chThdGetExitEventSource(tp) (&(tp)->p_exitesource)
-
-/**
- * Resumes a thread created with the \p P_SUSPENDED option or suspended with
- * \p chThdSuspend().
- * @param tp the pointer to the thread
- */
-#define chThdResumeI(tp) chSchReadyI((tp), RDY_OK)
-
-#endif /* _THREADS_H_ */
-
-/** @} */
+/*
+ ChibiOS/RT - Copyright (C) 2006-2007 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/>.
+*/
+
+/**
+ * @addtogroup Threads
+ * @{
+ */
+
+#ifndef _THREADS_H_
+#define _THREADS_H_
+
+/**
+ * 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 {
+ /** Next \p Thread in the threads list.*/
+ Thread *p_next;
+ /* End of the fields shared with the ThreadsList structure. */
+ /** Previous \p Thread in the threads list.*/
+ Thread *p_prev;
+ /* End of the fields shared with the ThreadsQueue structure. */
+ /** The thread priority.*/
+ tprio_t p_prio;
+ /* End of the fields shared with the ReadyList structure. */
+ /** Thread identifier. */
+ tid_t p_tid;
+ /** Current thread state.*/
+ tstate_t p_state;
+ /** Mode flags. */
+ tmode_t p_flags;
+ /** Machine dependent processor context.*/
+ Context p_ctx;
+ /*
+ * The following fields are merged in unions because they are all
+ * state-specific fields. This trick saves some extra space for each
+ * thread in the system.
+ */
+ union {
+ /** Thread wakeup code (only valid when exiting the \p PRREADY state). */
+ msg_t p_rdymsg;
+ /** The thread exit code (only while in \p PREXIT state).*/
+ msg_t p_exitcode;
+#ifdef CH_USE_SEMAPHORES
+ /** Semaphore where the thread is waiting on (only in \p PRWTSEM state). */
+ Semaphore *p_wtsemp;
+#endif
+#ifdef CH_USE_MUTEXES
+ /** Mutex where the thread is waiting on (only in \p PRWTMTX state). */
+ Mutex *p_wtmtxp;
+#endif
+#ifdef CH_USE_MESSAGES
+ /** Destination thread for message send (only in \p PRSNDMSG state). */
+ Thread *p_wtthdp;
+#endif
+#ifdef CH_USE_EVENTS
+ /** Enabled events mask (only while in \p PRWTEVENT state). */
+ eventmask_t p_ewmask;
+#endif
+#ifdef CH_USE_TRACE
+ /** Kernel object where the thread is waiting on. It is only valid when
+ the thread is some sleeping states. */
+ void *p_wtobjp;
+#endif
+ };
+ /*
+ * Start of the optional fields.
+ */
+#ifdef CH_USE_WAITEXIT
+ /** The list of the threads waiting for this thread termination.*/
+ ThreadsList p_waiting;
+#endif
+#ifdef CH_USE_EXIT_EVENT
+ /** The thread termination \p EventSource.*/
+ EventSource p_exitesource;
+#endif
+#ifdef CH_USE_MESSAGES
+ ThreadsQueue p_msgqueue;
+ msg_t p_msg;
+#endif
+#ifdef CH_USE_EVENTS
+ /** Pending events mask.*/
+ eventmask_t p_epending;
+#endif
+#ifdef CH_USE_MUTEXES
+ /** List of mutexes owned by this thread, \p NULL terminated.*/
+ Mutex *p_mtxlist;
+ /** Thread's own, non-inherited, priority */
+ tprio_t p_realprio;
+#endif
+};
+
+/** Thread state: Thread in the ready list.*/
+#define PRREADY 0
+/** Thread state: Current.*/
+#define PRCURR 1
+/** Thread state: Thread created in suspended state.*/
+#define PRSUSPENDED 2
+/** Thread state: Waiting on a semaphore.*/
+#define PRWTSEM 3
+/** Thread state: Waiting on a mutex.*/
+#define PRWTMTX 4
+/** Thread state: Waiting in \p chThdSleep() or \p chThdSleepUntil().*/
+#define PRSLEEP 5
+/** Thread state: Waiting in \p chThdWait().*/
+#define PRWAIT 6
+/** Thread state: Waiting in \p chEvtWait().*/
+#define PRWTEVENT 7
+/** Thread state: Waiting in \p chMsgSend().*/
+#define PRSNDMSG 8
+/** Thread state: Waiting in \p chMsgWait().*/
+#define PRWTMSG 9
+/** Thread state: After termination.*/
+#define PREXIT 10
+
+#ifdef CH_USE_TERMINATE
+/** Thread option: Termination requested flag.*/
+#define P_TERMINATE 1
+#endif
+#ifdef CH_USE_RESUME
+/** Thread option: Create suspended thread.*/
+#define P_SUSPENDED 2
+#endif
+#ifdef CH_USE_MESSAGES_PRIORITY
+/** Thread option: Serve messages by priority instead of FIFO order.*/
+#define P_MSGBYPRIO 4
+#endif
+
+/** Pseudo priority used by the ready list header, do not use.*/
+#define NOPRIO 0
+/** Idle thread priority.*/
+#define IDLEPRIO 1
+/** Lowest user priority.*/
+#define LOWPRIO 2
+/** Normal user priority.*/
+#define NORMALPRIO 64
+/** Highest user priority.*/
+#define HIGHPRIO 127
+/** Greatest possible priority.*/
+#define ABSPRIO 255
+
+/* Not an API, don't use into the application code.*/
+void init_thread(tprio_t prio, tmode_t mode, Thread *tp);
+
+/** Thread function.*/
+typedef msg_t (*tfunc_t)(void *);
+
+/*
+ * Threads APIs.
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+ Thread *chThdCreate(tprio_t prio, tmode_t mode, void *workspace,
+ size_t wsize, tfunc_t pf, void *arg);
+ Thread *chThdCreateFast(tprio_t prio, void *workspace,
+ size_t wsize, tfunc_t pf);
+ void chThdSetPriority(tprio_t newprio);
+ void chThdExit(msg_t msg);
+#ifdef CH_USE_RESUME
+ void chThdResume(Thread *tp);
+#endif
+#ifdef CH_USE_SUSPEND
+ void chThdSuspend(Thread **tpp);
+#endif
+#ifdef CH_USE_TERMINATE
+ void chThdTerminate(Thread *tp);
+#endif
+#ifdef CH_USE_WAITEXIT
+ msg_t chThdWait(Thread *tp);
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+/** Returns the pointer to the \p Thread currently in execution.*/
+#define chThdSelf() currp
+
+/** Returns the thread priority.*/
+#define chThdGetPriority() (currp->p_prio)
+
+/** Returns the pointer to the \p Thread local storage area, if any.*/
+#define chThdLS() (void *)(currp + 1)
+
+/** Verifies if the specified thread is in the \p PREXIT state.*/
+#define chThdTerminated(tp) ((tp)->p_state == PREXIT)
+
+/**
+ * Verifies if the current thread has a termination request pending.
+ */
+#define chThdShouldTerminate() (currp->p_flags & P_TERMINATE)
+
+/**
+ * Returns the exit event source for the specified thread. The source is
+ * signaled when the thread terminates.
+ * @param tp the pointer to the thread
+ * @note When registering on a thread termination make sure the thread
+ * is still alive, if you do that after the thread termination
+ * then you would miss the event. There are two ways to ensure
+ * this:<br>
+ * <ul>
+ * <li>Create the thread suspended, register on the event source
+ * and then resume the thread (recommended).</li>
+ * <li>Create the thread with a lower priority then register on it.
+ * This does not work if the hardware is capable of multiple
+ * physical threads.</li>
+ * </ul>
+ * @note You dont need to unregister from a terminated thread because
+ * the event source becomes inactive.
+ * @note The function is available only if the \p CH_USE_EXIT_EVENT
+ * option is enabled in \p chconf.h.
+ */
+#define chThdGetExitEventSource(tp) (&(tp)->p_exitesource)
+
+/**
+ * Resumes a thread created with the \p P_SUSPENDED option or suspended with
+ * \p chThdSuspend().
+ * @param tp the pointer to the thread
+ */
+#define chThdResumeI(tp) chSchReadyI((tp), RDY_OK)
+
+#endif /* _THREADS_H_ */
+
+/** @} */