git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@346 35acf78f-673a-0410-8e92-d51de3d6d3f4

master
gdisirio 2008-07-22 09:55:51 +00:00
parent 71a1820c4a
commit 49c3629538
12 changed files with 1949 additions and 1867 deletions

View File

@ -1,198 +1,200 @@
/* /*
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio. ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
This file is part of ChibiOS/RT. This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or the Free Software Foundation; either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful, ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <ch.h> #include <ch.h>
#include "board.h" #include "board.h"
#include "nvic.h" #include "nvic.h"
#include "stm32_serial.h" #include "stm32_serial.h"
#include "stm32lib/stm32f10x_nvic.h" #include "stm32lib/stm32f10x_nvic.h"
#ifdef USE_USART1 #define USART_BITRATE (38400)
FullDuplexDriver COM1;
static uint8_t ib1[SERIAL_BUFFERS_SIZE]; #ifdef USE_USART1
static uint8_t ob1[SERIAL_BUFFERS_SIZE]; FullDuplexDriver COM1;
#endif static uint8_t ib1[SERIAL_BUFFERS_SIZE];
static uint8_t ob1[SERIAL_BUFFERS_SIZE];
#ifdef USE_USART2 #endif
FullDuplexDriver COM2;
static uint8_t ib2[SERIAL_BUFFERS_SIZE]; #ifdef USE_USART2
static uint8_t ob2[SERIAL_BUFFERS_SIZE]; FullDuplexDriver COM2;
#endif static uint8_t ib2[SERIAL_BUFFERS_SIZE];
static uint8_t ob2[SERIAL_BUFFERS_SIZE];
#ifdef USE_USART3 #endif
FullDuplexDriver COM3;
static uint8_t ib3[SERIAL_BUFFERS_SIZE]; #ifdef USE_USART3
static uint8_t ob3[SERIAL_BUFFERS_SIZE]; FullDuplexDriver COM3;
#endif static uint8_t ib3[SERIAL_BUFFERS_SIZE];
static uint8_t ob3[SERIAL_BUFFERS_SIZE];
static void SetError(uint16_t sr, FullDuplexDriver *com) { #endif
dflags_t sts = 0;
static void SetError(uint16_t sr, FullDuplexDriver *com) {
if (sr & SR_ORE) dflags_t sts = 0;
sts |= SD_OVERRUN_ERROR;
if (sr & SR_PE) if (sr & SR_ORE)
sts |= SD_PARITY_ERROR; sts |= SD_OVERRUN_ERROR;
if (sr & SR_FE) if (sr & SR_PE)
sts |= SD_FRAMING_ERROR; sts |= SD_PARITY_ERROR;
if (sr & SR_LBD) if (sr & SR_FE)
sts |= SD_BREAK_DETECTED; sts |= SD_FRAMING_ERROR;
chSysLock(); if (sr & SR_LBD)
chFDDAddFlagsI(com, sts); sts |= SD_BREAK_DETECTED;
chSysUnlock(); chSysLock();
} chFDDAddFlagsI(com, sts);
chSysUnlock();
static void ServeInterrupt(USART_TypeDef *u, FullDuplexDriver *com) { }
uint16_t sr = u->SR;
static void ServeInterrupt(USART_TypeDef *u, FullDuplexDriver *com) {
if (sr & (SR_ORE | SR_FE | SR_PE | SR_LBD)) uint16_t sr = u->SR;
SetError(sr, com);
if (sr & SR_RXNE) { if (sr & (SR_ORE | SR_FE | SR_PE | SR_LBD))
chSysLock(); SetError(sr, com);
chFDDIncomingDataI(com, u->DR); if (sr & SR_RXNE) {
chSysUnlock(); chSysLock();
} chFDDIncomingDataI(com, u->DR);
if (sr & SR_TXE) { chSysUnlock();
chSysLock(); }
msg_t b = chFDDRequestDataI(com); if (sr & SR_TXE) {
chSysUnlock(); chSysLock();
if (b < Q_OK) msg_t b = chFDDRequestDataI(com);
u->CR1 &= ~CR1_TXEIE; chSysUnlock();
else if (b < Q_OK)
u->DR = b; u->CR1 &= ~CR1_TXEIE;
} else
} u->DR = b;
}
#ifdef USE_USART1 }
/*
* USART1 IRQ service routine. #ifdef USE_USART1
*/ /*
void VectorD4(void) { * USART1 IRQ service routine.
*/
chSysIRQEnterI(); void VectorD4(void) {
ServeInterrupt(USART1, &COM1);
chSysIRQExitI(); chSysIRQEnterI();
} ServeInterrupt(USART1, &COM1);
chSysIRQExitI();
/* }
* Invoked by the high driver when one or more bytes are inserted in the
* output queue. /*
*/ * Invoked by the high driver when one or more bytes are inserted in the
static void OutNotify1(void) { * output queue.
*/
USART1->CR1 |= CR1_TXEIE; static void OutNotify1(void) {
}
#endif USART1->CR1 |= CR1_TXEIE;
}
#ifdef USE_USART2 #endif
/*
* USART2 IRQ service routine. #ifdef USE_USART2
*/ /*
void VectorD8(void) { * USART2 IRQ service routine.
*/
chSysIRQEnterI(); void VectorD8(void) {
ServeInterrupt(USART2, &COM2);
chSysIRQExitI(); chSysIRQEnterI();
} ServeInterrupt(USART2, &COM2);
chSysIRQExitI();
/* }
* Invoked by the high driver when one or more bytes are inserted in the
* output queue. /*
*/ * Invoked by the high driver when one or more bytes are inserted in the
static void OutNotify2(void) { * output queue.
*/
USART2->CR1 |= CR1_TXEIE; static void OutNotify2(void) {
}
#endif USART2->CR1 |= CR1_TXEIE;
}
#ifdef USE_USART3 #endif
/*
* USART3 IRQ service routine. #ifdef USE_USART3
*/ /*
void VectorDC(void) { * USART3 IRQ service routine.
*/
chSysIRQEnterI(); void VectorDC(void) {
ServeInterrupt(USART3, &COM3);
chSysIRQExitI(); chSysIRQEnterI();
} ServeInterrupt(USART3, &COM3);
chSysIRQExitI();
/* }
* Invoked by the high driver when one or more bytes are inserted in the
* output queue. /*
*/ * Invoked by the high driver when one or more bytes are inserted in the
static void OutNotify3(void) { * output queue.
*/
USART3->CR1 |= CR1_TXEIE; static void OutNotify3(void) {
}
#endif USART3->CR1 |= CR1_TXEIE;
}
/* #endif
* USART setup, must be invoked with interrupts disabled.
* NOTE: Does not reset I/O queues. /*
*/ * USART setup, must be invoked with interrupts disabled.
void SetUSARTI(USART_TypeDef *u, uint32_t speed, uint16_t cr1, * NOTE: Does not reset I/O queues.
uint16_t cr2, uint16_t cr3) { */
void SetUSARTI(USART_TypeDef *u, uint32_t speed, uint16_t cr1,
/* uint16_t cr2, uint16_t cr3) {
* Baud rate setting.
*/ /*
if (u == USART1) * Baud rate setting.
u->BRR = APB2CLK / speed; */
else if (u == USART1)
u->BRR = APB1CLK / speed; 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; * Note that some bits are enforced.
u->CR2 = cr2; */
u->CR3 = cr3 | CR3_EIE; 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. * Serial subsystem initialization.
*/ * NOTE: Handshake pins are not switched to their function because they may have
void InitSerial(uint32_t prio1, uint32_t prio2, uint32_t prio3) { * another use. Enable them externally if needed.
*/
#ifdef USE_USART1 void InitSerial(uint32_t prio1, uint32_t prio2, uint32_t prio3) {
chFDDInit(&COM1, ib1, sizeof ib1, NULL, ob1, sizeof ob1, OutNotify1);
RCC->APB2ENR |= 0x00004000; #ifdef USE_USART1
SetUSARTI(USART1, 38400, 0, CR2_STOP1_BITS | CR2_LINEN, 0); chFDDInit(&COM1, ib1, sizeof ib1, NULL, ob1, sizeof ob1, OutNotify1);
GPIOA->CRH = (GPIOA->CRH & 0xFFFFF00F) | 0x000004B0; RCC->APB2ENR |= 0x00004000;
NVICEnableVector(USART1_IRQChannel, prio1); SetUSARTI(USART1, USART_BITRATE, 0, CR2_STOP1_BITS | CR2_LINEN, 0);
#endif GPIOA->CRH = (GPIOA->CRH & 0xFFFFF00F) | 0x000004B0;
NVICEnableVector(USART1_IRQChannel, prio1);
#ifdef USE_USART2 #endif
chFDDInit(&COM2, ib2, sizeof ib2, NULL, ob2, sizeof ob2, OutNotify2);
RCC->APB1ENR |= 0x00020000; #ifdef USE_USART2
SetUSARTI(USART2, 38400, 0, CR2_STOP1_BITS | CR2_LINEN, 0); chFDDInit(&COM2, ib2, sizeof ib2, NULL, ob2, sizeof ob2, OutNotify2);
GPIOA->CRL = (GPIOA->CRL & 0xFFFF00FF) | 0x00004B00; RCC->APB1ENR |= 0x00020000;
NVICEnableVector(USART2_IRQChannel, prio2); SetUSARTI(USART2, USART_BITRATE, 0, CR2_STOP1_BITS | CR2_LINEN, 0);
#endif GPIOA->CRL = (GPIOA->CRL & 0xFFFF00FF) | 0x00004B00;
NVICEnableVector(USART2_IRQChannel, prio2);
#ifdef USE_USART3 #endif
chFDDInit(&COM3, ib3, sizeof ib3, NULL, ob3, sizeof ob3, OutNotify3);
RCC->APB1ENR |= 0x00040000; #ifdef USE_USART3
SetUSARTI(USART3, 38400, 0, CR2_STOP1_BITS | CR2_LINEN, 0); chFDDInit(&COM3, ib3, sizeof ib3, NULL, ob3, sizeof ob3, OutNotify3);
GPIOB->CRH = (GPIOB->CRH & 0xFFFF00FF) | 0x00004B00; RCC->APB1ENR |= 0x00040000;
NVICEnableVector(USART3_IRQChannel, prio3); SetUSARTI(USART3, USART_BITRATE, 0, CR2_STOP1_BITS | CR2_LINEN, 0);
#endif GPIOB->CRH = (GPIOB->CRH & 0xFFFF00FF) | 0x00004B00;
} NVICEnableVector(USART3_IRQChannel, prio3);
#endif
}

View File

@ -1,152 +1,167 @@
/* /*
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio. ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
This file is part of ChibiOS/RT. This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or the Free Software Foundation; either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful, ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <ch.h> #include <ch.h>
#include <nvic.h> #include <nvic.h>
/* /*
* System idle thread loop. * System idle thread loop.
*/ */
__attribute__((weak)) __attribute__((weak))
void _IdleThread(void *p) { void _IdleThread(void *p) {
while (TRUE) { while (TRUE) {
// asm volatile ("wfi"); // asm volatile ("wfi");
} }
} }
/* /*
* System console message (not implemented). * System console message (not implemented).
*/ */
__attribute__((weak)) __attribute__((weak))
void chSysPuts(char *msg) { void chSysPuts(char *msg) {
} }
/* /*
* System halt. * System halt.
*/ */
__attribute__((naked, weak)) __attribute__((naked, weak))
void chSysHalt(void) { void chSysHalt(void) {
asm volatile ("cpsid i"); asm volatile ("cpsid i");
while (TRUE) { while (TRUE) {
} }
} }
__attribute__((naked, weak)) /*
void threadstart(void) { * Start a thread by invoking its work function.
*
asm volatile ( \ * Start a thread by calling its work function. If the work function returns,
"blx r1 \n\t" \ * call chThdExit and chSysHalt.
"bl chThdExit \n\t" \ */
"bl chSysHalt \n\t" \ __attribute__((naked, weak))
); void threadstart(void) {
}
asm volatile ( \
/* "blx r1 \n\t" \
* System Timer vector. "bl chThdExit \n\t" \
*/ "bl chSysHalt \n\t" \
void SysTickVector(void) { );
}
chSysIRQEnterI();
chSysLock(); /*
* System Timer vector.
chSysTimerHandlerI(); */
void SysTickVector(void) {
chSysUnlock();
chSysIRQExitI(); chSysIRQEnterI();
} chSysLock();
void *retaddr; chSysTimerHandlerI();
/* chSysUnlock();
* System invoked context switch. chSysIRQExitI();
*/ }
__attribute__((naked))
void SVCallVector(Thread *otp, Thread *ntp) { void *retaddr;
#ifdef CH_CURRP_REGISTER_CACHE /*
asm volatile ("mrs r3, BASEPRI \n\t" \ * System invoked context switch.
"mrs r12, PSP \n\t" \ */
"stmdb r12!, {r3-r6,r8-r11, lr} \n\t" \ __attribute__((naked))
"str r12, [r0, #16] \n\t" \ void SVCallVector(Thread *otp, Thread *ntp) {
"ldr r12, [r1, #16] \n\t" \ /* { r0 = otp, r1 = ntp } */
"ldmia r12!, {r3-r6,r8-r11, lr} \n\t" \ /* get the BASEPRI in r3 */
"msr PSP, r12 \n\t" \ /* get the PSP in r12 */
"msr BASEPRI, r3 \n\t" \ /* push the registers on the PSP stack */
"bx lr "); /* stores the modified PSP into the thread context */
#else /* fetches the PSP position from the new thread context */
asm volatile ("mrs r3, BASEPRI \n\t" \ /* pop the registers from the PSP stack */
"mrs r12, PSP \n\t" \ /* set the PSP from r12 */
"stmdb r12!, {r3-r11, lr} \n\t" \ /* set the BASEPRI from R3 */
"str r12, [r0, #16] \n\t" \ #ifdef CH_CURRP_REGISTER_CACHE
"ldr r12, [r1, #16] \n\t" \ asm volatile ("mrs r3, BASEPRI \n\t" \
"ldmia r12!, {r3-r11, lr} \n\t" \ "mrs r12, PSP \n\t" \
"msr PSP, r12 \n\t" \ "stmdb r12!, {r3-r6,r8-r11, lr} \n\t" \
"msr BASEPRI, r3 \n\t" \ "str r12, [r0, #16] \n\t" \
"bx lr "); "ldr r12, [r1, #16] \n\t" \
#endif "ldmia r12!, {r3-r6,r8-r11, lr} \n\t" \
} "msr PSP, r12 \n\t" \
"msr BASEPRI, r3 \n\t" \
/* "bx lr ");
* Preemption invoked context switch. #else
*/ asm volatile ("mrs r3, BASEPRI \n\t" \
__attribute__((naked)) "mrs r12, PSP \n\t" \
void PendSVVector(void) { "stmdb r12!, {r3-r11, lr} \n\t" \
Thread *otp; "str r12, [r0, #16] \n\t" \
register struct intctx *sp_thd asm("r12"); "ldr r12, [r1, #16] \n\t" \
"ldmia r12!, {r3-r11, lr} \n\t" \
chSysLock(); "msr PSP, r12 \n\t" \
asm volatile ("push {lr}"); "msr BASEPRI, r3 \n\t" \
if (!chSchRescRequiredI()) { "bx lr ");
chSysUnlock(); #endif
asm volatile ("pop {pc}"); }
}
/*
asm volatile ("pop {lr} \n\t" \ * Preemption invoked context switch.
"movs r3, #0 \n\t" \ */
"mrs %0, PSP" : "=r" (sp_thd) : ); __attribute__((naked))
#ifdef CH_CURRP_REGISTER_CACHE void PendSVVector(void) {
asm volatile ("stmdb %0!, {r3-r6,r8-r11, lr}" : Thread *otp;
"=r" (sp_thd) : register struct intctx *sp_thd asm("r12");
"r" (sp_thd));
#else chSysLock();
asm volatile ("stmdb %0!, {r3-r11,lr}" : asm volatile ("push {lr}");
"=r" (sp_thd) : if (!chSchRescRequiredI()) {
"r" (sp_thd)); chSysUnlock();
#endif asm volatile ("pop {pc}");
}
(otp = currp)->p_ctx.r13 = sp_thd;
chSchReadyI(otp); asm volatile ("pop {lr} \n\t" \
(currp = fifo_remove(&rlist.r_queue))->p_state = PRCURR; "movs r3, #0 \n\t" \
rlist.r_preempt = CH_TIME_QUANTUM; "mrs %0, PSP" : "=r" (sp_thd) : );
#ifdef CH_USE_TRACE #ifdef CH_CURRP_REGISTER_CACHE
chDbgTrace(otp, currp); asm volatile ("stmdb %0!, {r3-r6,r8-r11, lr}" :
#endif "=r" (sp_thd) :
sp_thd = currp->p_ctx.r13; "r" (sp_thd));
#else
#ifdef CH_CURRP_REGISTER_CACHE asm volatile ("stmdb %0!, {r3-r11,lr}" :
asm volatile ("ldmia %0!, {r3-r6,r8-r11, lr}" : : "r" (sp_thd)); "=r" (sp_thd) :
#else "r" (sp_thd));
asm volatile ("ldmia %0!, {r3-r11, lr}" : : "r" (sp_thd)); #endif
#endif
asm volatile ("msr PSP, %0 \n\t" \ (otp = currp)->p_ctx.r13 = sp_thd;
"msr BASEPRI, r3 \n\t" \ chSchReadyI(otp);
"bx lr" : : "r" (sp_thd)); (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));
}

View File

@ -1,120 +1,126 @@
/* /*
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio. ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
This file is part of ChibiOS/RT. This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or the Free Software Foundation; either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful, ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _CHCORE_H_ #ifndef _CHCORE_H_
#define _CHCORE_H_ #define _CHCORE_H_
#define CH_ARCHITECTURE_ARMCM3 #define CH_ARCHITECTURE_ARMCM3
typedef void *regarm; typedef void *regarm;
/* /*
* Interrupt saved context, empty in this architecture. * Interrupt saved context, empty in this architecture.
*/ */
struct extctx { struct extctx {
}; };
/* /*
* System saved context. * System saved context.
*/ */
struct intctx { struct intctx {
regarm basepri; regarm basepri;
regarm r4; regarm r4;
regarm r5; regarm r5;
regarm r6; regarm r6;
#ifndef CH_CURRP_REGISTER_CACHE #ifndef CH_CURRP_REGISTER_CACHE
regarm r7; regarm r7;
#endif #endif
regarm r8; regarm r8;
regarm r9; regarm r9;
regarm r10; regarm r10;
regarm r11; regarm r11;
regarm lr_exc; regarm lr_exc;
regarm r0; regarm r0;
regarm r1; regarm r1;
regarm r2; regarm r2;
regarm r3; regarm r3;
regarm r12; regarm r12;
regarm lr_thd; regarm lr_thd;
regarm pc; regarm pc;
regarm xpsr; regarm xpsr;
}; };
/* /*
* Port dependent part of the Thread structure, you may add fields in * Port dependent part of the Thread structure, you may add fields in
* this structure. * this structure.
*/ */
typedef struct { typedef struct {
struct intctx *r13; struct intctx *r13;
} Context; } Context;
/* /*
* Platform dependent part of the \p chThdCreate() API. * Platform dependent part of the \p chThdCreate() API.
*/ *
#define SETUP_CONTEXT(workspace, wsize, pf, arg) { \ * The top of the workspace is used for the intctx datastructure.
tp->p_ctx.r13 = (struct intctx *)((uint8_t *)workspace + \ *
wsize - \ */
sizeof(struct intctx)); \ #define SETUP_CONTEXT(workspace, wsize, pf, arg) { \
tp->p_ctx.r13->basepri = 0; \ tp->p_ctx.r13 = (struct intctx *)((uint8_t *)workspace + \
tp->p_ctx.r13->lr_exc = (regarm)0xFFFFFFFD; \ wsize - \
tp->p_ctx.r13->r0 = arg; \ sizeof(struct intctx)); \
tp->p_ctx.r13->r1 = pf; \ tp->p_ctx.r13->basepri = 0; \
tp->p_ctx.r13->pc = threadstart; \ tp->p_ctx.r13->lr_exc = (regarm)0xFFFFFFFD; \
tp->p_ctx.r13->xpsr = (regarm)0x01000000; \ tp->p_ctx.r13->r0 = arg; \
} tp->p_ctx.r13->r1 = pf; \
tp->p_ctx.r13->pc = threadstart; \
#define chSysLock() { \ tp->p_ctx.r13->xpsr = (regarm)0x01000000; \
register uint32_t tmp asm ("r3"); \ }
asm volatile ("movs %0, #0x10" : "=r" (tmp): ); \
asm volatile ("msr BASEPRI, %0" : : "r" (tmp)); \ #define chSysLock() { \
} register uint32_t tmp asm ("r3"); \
#define chSysUnlock() { \ asm volatile ("movs %0, #0x10" : "=r" (tmp): ); \
register uint32_t tmp asm ("r3"); \ asm volatile ("msr BASEPRI, %0" : : "r" (tmp)); \
asm volatile ("movs %0, #0" : "=r" (tmp): ); \ }
asm volatile ("msr BASEPRI, %0" : : "r" (tmp)); \ #define chSysUnlock() { \
} register uint32_t tmp asm ("r3"); \
#define chSysSwitchI(otp, ntp) { \ asm volatile ("movs %0, #0" : "=r" (tmp): ); \
register Thread *_otp asm ("r0") = (otp); \ asm volatile ("msr BASEPRI, %0" : : "r" (tmp)); \
register Thread *_ntp asm ("r1") = (ntp); \ }
asm volatile ("svc #0" : : "r" (_otp), "r" (_ntp)); \ #define chSysSwitchI(otp, ntp) { \
} register Thread *_otp asm ("r0") = (otp); \
register Thread *_ntp asm ("r1") = (ntp); \
#define INT_REQUIRED_STACK 0 asm volatile ("svc #0" : : "r" (_otp), "r" (_ntp)); \
#define StackAlign(n) ((((n) - 1) | 3) + 1) }
#define UserStackSize(n) StackAlign(sizeof(Thread) + \
sizeof(struct intctx) + \ #define INT_REQUIRED_STACK 0
sizeof(struct extctx) + \ #define StackAlign(n) ((((n) - 1) | 3) + 1)
(n) + \ #define UserStackSize(n) StackAlign(sizeof(Thread) + \
INT_REQUIRED_STACK) sizeof(struct intctx) + \
#define WorkingArea(s, n) uint32_t s[UserStackSize(n) >> 2]; sizeof(struct extctx) + \
(n) + \
#define chSysIRQEnterI() INT_REQUIRED_STACK)
#define chSysIRQExitI() { \ #define WorkingArea(s, n) uint32_t s[UserStackSize(n) >> 2];
SCB_ICSR = ICSR_PENDSVSET; \
} /* called on each interrupt entry, currently nothing is done */
#define chSysIRQEnterI()
/* It should be 8.*/ /* called on each interrupt exit, pends a supervisor handler for
#define IDLE_THREAD_STACK_SIZE 0 * execution after all higher priority interrupts; PendSVVector() */
void _IdleThread(void *p) __attribute__((noreturn)); #define chSysIRQExitI() { \
SCB_ICSR = ICSR_PENDSVSET; \
void chSysHalt(void); }
void chSysPuts(char *msg);
void threadstart(void); /* It should be 8.*/
#define IDLE_THREAD_STACK_SIZE 0
#endif /* _CHCORE_H_ */ void _IdleThread(void *p) __attribute__((noreturn));
void chSysHalt(void);
void chSysPuts(char *msg);
void threadstart(void);
#endif /* _CHCORE_H_ */

View File

@ -1,93 +1,94 @@
/* /*
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio. ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
This file is part of ChibiOS/RT. This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or the Free Software Foundation; either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful, ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* /*
* Generic ARM-CortexM3 startup file for ChibiOS/RT. * Generic ARM-CortexM3 startup file for ChibiOS/RT.
*/ */
.set CONTROL_MODE_PRIVILEGED, 0 .set CONTROL_MODE_PRIVILEGED, 0
.set CONTROL_MODE_UNPRIVILEGED, 1 .set CONTROL_MODE_UNPRIVILEGED, 1
.set CONTROL_USE_MSP, 0 .set CONTROL_USE_MSP, 0
.set CONTROL_USE_PSP, 2 .set CONTROL_USE_PSP, 2
.text .text
.balign 2 .balign 2
.syntax unified .syntax unified
.thumb .thumb
/* /*
* Reset handler. * Reset handler.
*/ */
.thumb_func .thumb_func
.global ResetHandler .global ResetHandler
ResetHandler: ResetHandler:
/* /*
* Stack pointers initialization. * Stack pointers initialization.
*/ */
ldr r0, =__ram_end__ ldr r0, =__ram_end__
ldr r1, =__main_stack_size__ ldr r1, =__main_stack_size__
sub r0, r0, r1 sub r0, r0, r1
msr PSP, r0 /* { r0 = main stack low address } */
// ldr r1, =__process_stack_size__ msr PSP, r0
// sub r0, r0, r1 // ldr r1, =__process_stack_size__
/* // sub r0, r0, r1
* Data initialization. /*
* NOTE: It assumes that the DATA size is a multiple of 4. * Data initialization.
*/ * NOTE: It assumes that the DATA size is a multiple of 4.
ldr r1, =_textdata */
ldr r2, =_data ldr r1, =_textdata
ldr r3, =_edata ldr r2, =_data
dloop: ldr r3, =_edata
cmp r2, r3 dloop:
ittt lo cmp r2, r3
ldrlo r0, [r1], #4 ittt lo
strlo r0, [r2], #4 ldrlo r0, [r1], #4
blo dloop strlo r0, [r2], #4
/* blo dloop
* BSS initialization. /*
* NOTE: It assumes that the BSS size is a multiple of 4. * BSS initialization.
*/ * NOTE: It assumes that the BSS size is a multiple of 4.
movs r0, #0 */
ldr r1, =_bss_start movs r0, #0
ldr r2, =_bss_end ldr r1, =_bss_start
bloop: ldr r2, =_bss_end
cmp r1, r2 bloop:
itt lo cmp r1, r2
strlo r0, [r1], #4 itt lo
blo bloop strlo r0, [r1], #4
/* blo bloop
* Switches to the Process Stack and disables the interrupts globally. /*
*/ * Switches to the Process Stack and disables the interrupts globally.
movs r0, #CONTROL_MODE_PRIVILEGED | CONTROL_USE_PSP */
msr CONTROL, r0 movs r0, #CONTROL_MODE_PRIVILEGED | CONTROL_USE_PSP
isb msr CONTROL, r0
movs r0, #0x10 isb
msr BASEPRI, r0 movs r0, #0x10
cpsie i msr BASEPRI, r0
/* cpsie i
* Application-provided HW initialization routine. /*
*/ * Application-provided HW initialization routine.
bl hwinit */
/* bl hwinit
* main(0, NULL). /*
*/ * main(0, NULL).
movs r0, #0 */
mov r1, r0 movs r0, #0
bl main mov r1, r0
bl chSysHalt bl main
bl chSysHalt

View File

@ -74,6 +74,12 @@ Win32-MinGW - ChibiOS/RT simulator and demo into a WIN32 process,
*** Releases *** *** 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 *** *** 0.6.7 ***
- NEW: New chThdCreateFast() API, it is a simplified form of chThdCreate() - NEW: New chThdCreateFast() API, it is a simplified form of chThdCreate()
that allows even faster threads creation. The new API does not support that allows even faster threads creation. The new API does not support

View File

@ -1,81 +1,86 @@
/* /*
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio. ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
This file is part of ChibiOS/RT. This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or the Free Software Foundation; either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful, ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* @addtogroup Initialization * @addtogroup Initialization
* @{ * @{
*/ */
#include <ch.h> #include <ch.h>
/** /**
* ChibiOS/RT initialization. After executing this function the current * ChibiOS/RT initialization. After executing this function the current
* instructions stream becomes the main thread. * instructions stream becomes the main thread.
* @note Interrupts should be still disabled when \p chSysInit() is invoked * @note Interrupts should be still disabled when \p chSysInit() is invoked
* and are internally enabled. * and are internally enabled.
* @note The main thread is created with priority \p NORMALPRIO. * @note The main thread is created with priority \p NORMALPRIO.
*/ */
void chSysInit(void) { void chSysInit(void) {
static Thread mainthread; static Thread mainthread;
static WorkingArea(waIdleThread, IDLE_THREAD_STACK_SIZE); static WorkingArea(waIdleThread, IDLE_THREAD_STACK_SIZE);
chSchInit(); chSchInit();
chDbgInit(); chDbgInit();
#ifdef CH_USE_VIRTUAL_TIMERS #ifdef CH_USE_VIRTUAL_TIMERS
chVTInit(); chVTInit();
#endif #endif
/* /*
* Now this instructions flow becomes the main thread. * Now this instructions flow becomes the main thread.
*/ */
init_thread(NORMALPRIO, 0, &mainthread); init_thread(NORMALPRIO, 0, &mainthread);
mainthread.p_state = PRCURR; mainthread.p_state = PRCURR;
currp = &mainthread; currp = &mainthread;
chSysUnlock(); chSysUnlock();
/* /*
* The idle thread is created using the port-provided implementation. * The idle thread is created using the port-provided implementation.
* This thread has the lowest priority in the system, its role is just to * This thread has the lowest priority in the system, its role is just to
* serve interrupts in its context while keeping the lowest energy saving * serve interrupts in its context while keeping the lowest energy saving
* mode compatible with the system status. * mode compatible with the system status.
*/ */
chThdCreateFast(IDLEPRIO, waIdleThread, chThdCreateFast(IDLEPRIO, waIdleThread,
sizeof(waIdleThread), (tfunc_t)_IdleThread); sizeof(waIdleThread), (tfunc_t)_IdleThread);
} }
/** /**
* Preemption routine, this function must be called into an interrupt * Handles time ticks for round robin preemption and timer increments.
* handler invoked by a system timer. *
* The frequency of the timer determines the system tick granularity and, * Decrements the remaining time quantum of the running thread and preempts
* together with the \p CH_TIME_QUANTUM macro, the round robin interval. * it when the quantum is used up. Increments system time and manages the
*/ * timers.
void chSysTimerHandlerI(void) { *
* @note The frequency of the timer determines the system tick granularity and,
if (rlist.r_preempt > 0) * together with the \p CH_TIME_QUANTUM macro, the round robin interval.
rlist.r_preempt--; */
#ifdef CH_USE_SYSTEMTIME void chSysTimerHandlerI(void) {
rlist.r_stime++; /* running thread has not used up quantum yet? */
#endif if (rlist.r_preempt > 0)
/* decrement remaining quantum */
#ifdef CH_USE_VIRTUAL_TIMERS rlist.r_preempt--;
chVTDoTickI(); #ifdef CH_USE_SYSTEMTIME
#endif rlist.r_stime++;
} #endif
/** @} */ #ifdef CH_USE_VIRTUAL_TIMERS
chVTDoTickI();
#endif
}
/** @} */

View File

@ -1,243 +1,260 @@
/* /*
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio. ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
This file is part of ChibiOS/RT. This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or the Free Software Foundation; either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful, ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* @addtogroup Mutexes * @addtogroup Mutexes
* @{ * @{
*/ */
#include <ch.h> #include <ch.h>
#ifdef CH_USE_MUTEXES #ifdef CH_USE_MUTEXES
/** /**
* Initializes s \p Mutex structure. * Initializes s \p Mutex structure.
* @param mp pointer to a \p Mutex structure * @param mp pointer to a \p Mutex structure
*/ */
void chMtxInit(Mutex *mp) { void chMtxInit(Mutex *mp) {
fifo_init(&mp->m_queue); fifo_init(&mp->m_queue);
mp->m_owner = NULL; mp->m_owner = NULL;
} }
/** /**
* Locks the specified mutex. * Locks the specified mutex.
* @param mp pointer to the \p Mutex structure * @param mp pointer to the \p Mutex structure
*/ */
void chMtxLock(Mutex *mp) { void chMtxLock(Mutex *mp) {
chSysLock(); chSysLock();
chMtxLockS(mp); chMtxLockS(mp);
chSysUnlock(); chSysUnlock();
} }
/** /**
* Locks the specified mutex. * Locks the specified mutex.
* @param mp pointer to the \p Mutex structure *
* @note This function must be called within a \p chSysLock() / \p chSysUnlock() * @param mp pointer to the \p Mutex structure
* block. * @note This function must be called within a \p chSysLock() / \p chSysUnlock()
*/ * block.
void chMtxLockS(Mutex *mp) { */
void chMtxLockS(Mutex *mp) {
if (mp->m_owner != NULL) { /* the mutex is already locked? */
/* if (mp->m_owner != NULL) {
* Inheritance, explores the thread-mutex dependances adjusting /*
* the priority of all the affected threads. * Priority inheritance protocol; explores the thread-mutex dependencies
*/ * boosting the priority of all the affected threads to equal the priority
Thread *tp = mp->m_owner; * of the running thread requesting the mutex.
while (tp->p_prio < currp->p_prio) { */
tp->p_prio = currp->p_prio; Thread *tp = mp->m_owner;
/* /* { tp is the thread currently owning the mutex } */
* The following states need priority queues reordering. /* the running thread has higher priority than tp? */
*/ while (tp->p_prio < currp->p_prio) {
switch (tp->p_state) { /* make priority of thread tp match the running thread's priority */
case PRWTMTX: tp->p_prio = currp->p_prio;
prio_insert(dequeue(tp), &tp->p_wtmtxp->m_queue); /*
tp = tp->p_wtmtxp->m_owner; * The following states need priority queues reordering.
continue; */
#ifdef CH_USE_MESSAGES_PRIORITY switch (tp->p_state) {
case PRSNDMSG: /* thread tp is waiting on a mutex? */
if (tp->p_flags & P_MSGBYPRIO) case PRWTMTX:
prio_insert(dequeue(tp), &tp->p_wtthdp->p_msgqueue); /* requeue tp with its new priority on the mutex wait queue */
#endif prio_insert(dequeue(tp), &tp->p_wtmtxp->m_queue);
case PRREADY: /* boost the owner of this mutex if needed */
chSchReadyI(dequeue(tp)); tp = tp->p_wtmtxp->m_owner;
} continue;
break; #ifdef CH_USE_MESSAGES_PRIORITY
} case PRSNDMSG:
/* if (tp->p_flags & P_MSGBYPRIO)
* Goes to sleep on the mutex. /* requeue tp with its new priority on (?) */
*/ prio_insert(dequeue(tp), &tp->p_wtthdp->p_msgqueue);
prio_insert(currp, &mp->m_queue); break;
currp->p_wtmtxp = mp; #endif
chSchGoSleepS(PRWTMTX); /* thread tp is ready? */
chDbgAssert(mp->m_owner == NULL, "chmtx.c, chMtxLockS()"); case PRREADY:
} /* requeue tp with its new priority on the ready list */
/* chSchReadyI(dequeue(tp));
* The mutex is now inserted in the owned mutexes list. }
*/ break;
mp->m_owner = currp; }
mp->m_next = currp->p_mtxlist; /*
currp->p_mtxlist = mp; * Goes to sleep on the mutex.
} */
prio_insert(currp, &mp->m_queue);
/** currp->p_wtmtxp = mp;
* Tries to lock a mutex. This function does not have any overhead related to chSchGoSleepS(PRWTMTX);
* the priority inheritance mechanism because it does not try to enter a sleep chDbgAssert(mp->m_owner == NULL, "chmtx.c, chMtxLockS()");
* state on the mutex. }
* @param mp pointer to the \p Mutex structure /*
* @return \p TRUE if the mutex was successfully acquired else \p FALSE * The mutex is now inserted in the owned mutexes list.
*/ */
bool_t chMtxTryLock(Mutex *mp) { mp->m_owner = currp;
bool_t b; mp->m_next = currp->p_mtxlist;
currp->p_mtxlist = mp;
chSysLock(); }
b = chMtxTryLockS(mp); /**
* Tries to lock a mutex. This function does not have any overhead related to
chSysUnlock(); * the priority inheritance mechanism because it does not try to enter a sleep
return b; * state on the mutex.
} * @param mp pointer to the \p Mutex structure
* @return \p TRUE if the mutex was successfully acquired else \p FALSE
/** */
* Tries to lock a mutex. This function does not have any overhead related to bool_t chMtxTryLock(Mutex *mp) {
* the priority inheritance mechanism because it does not try to enter a sleep bool_t b;
* state on the mutex.
* @param mp pointer to the \p Mutex structure chSysLock();
* @return \p TRUE if the mutex was successfully acquired else \p FALSE
* @note This function must be called within a \p chSysLock() / \p chSysUnlock() b = chMtxTryLockS(mp);
* block.
*/ chSysUnlock();
bool_t chMtxTryLockS(Mutex *mp) { return b;
}
if (mp->m_owner != NULL)
return FALSE; /**
mp->m_owner = currp; * Tries to lock a mutex. This function does not have any overhead related to
mp->m_next = currp->p_mtxlist; * the priority inheritance mechanism because it does not try to enter a sleep
currp->p_mtxlist = mp; * state on the mutex.
return TRUE; * @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.
* Unlocks the next owned mutex in reverse lock order. */
*/ bool_t chMtxTryLockS(Mutex *mp) {
void chMtxUnlock(void) {
Mutex *mp; if (mp->m_owner != NULL)
return FALSE;
chSysLock(); mp->m_owner = currp;
mp->m_next = currp->p_mtxlist;
chDbgAssert((currp->p_mtxlist != NULL) && (currp->p_mtxlist->m_owner == currp), currp->p_mtxlist = mp;
"chmtx.c, chMtxUnlock()"); return TRUE;
}
/*
* Removes the top Mutex from the owned mutexes list and marks it as not owned. /**
*/ * Unlocks the next owned mutex in reverse lock order.
mp = currp->p_mtxlist; */
currp->p_mtxlist = mp->m_next; void chMtxUnlock(void) {
mp->m_owner = NULL; Mutex *mp;
/*
* If a thread is waiting on the mutex then the hard part begins. chSysLock();
*/
if (chMtxQueueNotEmptyS(mp)) { chDbgAssert((currp->p_mtxlist != NULL) && (currp->p_mtxlist->m_owner == currp),
Thread *tp = fifo_remove(&mp->m_queue); "chmtx.c, chMtxUnlock()");
/*
* Recalculates the optimal thread priority by scanning the owned mutexes list. /*
*/ * Removes the top Mutex from the owned mutexes list and marks it as not owned.
tprio_t newprio = currp->p_realprio; */
mp = currp->p_mtxlist; mp = currp->p_mtxlist;
while (mp != NULL) { currp->p_mtxlist = mp->m_next;
if (chMtxQueueNotEmptyS(mp) && (mp->m_queue.p_next->p_prio > newprio)) mp->m_owner = NULL;
newprio = mp->m_queue.p_next->p_prio; /*
mp = mp->m_next; * If a thread is waiting on the mutex then the hard part begins.
} */
currp->p_prio = newprio; if (chMtxQueueNotEmptyS(mp)) {
chSchWakeupS(tp, RDY_OK); /* get the highest priority thread waiting for the unlocked mutex */
} Thread *tp = fifo_remove(&mp->m_queue);
/*
chSysUnlock(); * 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 */
* Unlocks the next owned mutex in reverse lock order. mp = currp->p_mtxlist;
* @note This function must be called within a \p chSysLock() / \p chSysUnlock() while (mp != NULL) {
* block. /* mutex mp has a higher priority thread pending? */
* @note This function does not reschedule internally. if (chMtxQueueNotEmptyS(mp) && (mp->m_queue.p_next->p_prio > newprio))
*/ /* boost current thread's priority to waiting thread */
void chMtxUnlockS(void) { newprio = mp->m_queue.p_next->p_prio;
Mutex *mp; mp = mp->m_next;
}
chDbgAssert((currp->p_mtxlist != NULL) && (currp->p_mtxlist->m_owner == currp), /* (possibly) boost the priority of the current thread */
"chmtx.c, chMtxUnlockS()"); currp->p_prio = newprio;
/* awaken the highest priority thread waiting for the unlocked mutex */
/* chSchWakeupS(tp, RDY_OK);
* Removes the top Mutex from the owned mutexes list and marks it as not owned. }
*/ chSysUnlock();
mp = currp->p_mtxlist; }
currp->p_mtxlist = mp->m_next;
mp->m_owner = NULL; /**
/* * Unlocks the next owned mutex in reverse lock order.
* If a thread is waiting on the mutex then the hard part begins. * @note This function must be called within a \p chSysLock() / \p chSysUnlock()
*/ * block.
if (chMtxQueueNotEmptyS(mp)) { * @note This function does not reschedule internally.
Thread *tp = fifo_remove(&mp->m_queue); */
/* void chMtxUnlockS(void) {
* Recalculates the optimal thread priority by scanning the owned mutexes list. Mutex *mp;
*/
tprio_t newprio = currp->p_realprio; chDbgAssert((currp->p_mtxlist != NULL) && (currp->p_mtxlist->m_owner == currp),
mp = currp->p_mtxlist; "chmtx.c, chMtxUnlockS()");
while (mp != NULL) {
if (chMtxQueueNotEmptyS(mp) && (mp->m_queue.p_next->p_prio > newprio)) /*
newprio = mp->m_queue.p_next->p_prio; * Removes the top Mutex from the owned mutexes list and marks it as not owned.
mp = mp->m_next; */
} mp = currp->p_mtxlist;
currp->p_prio = newprio; currp->p_mtxlist = mp->m_next;
chSchReadyI(tp); mp->m_owner = NULL;
} /*
} * If a thread is waiting on the mutex then the hard part begins.
*/
/** if (chMtxQueueNotEmptyS(mp)) {
* Unlocks all the mutexes owned by the invoking thread, this is <b>MUCH MORE</b> Thread *tp = fifo_remove(&mp->m_queue);
* 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 * Recalculates the optimal thread priority by scanning the owned mutexes list.
* priority inheritance mechanism. */
*/ tprio_t newprio = currp->p_realprio;
void chMtxUnlockAll(void) { mp = currp->p_mtxlist;
while (mp != NULL) {
chSysLock(); if (chMtxQueueNotEmptyS(mp) && (mp->m_queue.p_next->p_prio > newprio))
newprio = mp->m_queue.p_next->p_prio;
if (currp->p_mtxlist != NULL) { mp = mp->m_next;
do { }
Mutex *mp = currp->p_mtxlist; currp->p_prio = newprio;
currp->p_mtxlist = mp->m_next; chSchReadyI(tp);
mp->m_owner = NULL; }
if (chMtxQueueNotEmptyS(mp)) }
chSchReadyI(fifo_remove(&mp->m_queue));
} while (currp->p_mtxlist != NULL); /**
currp->p_prio = currp->p_realprio; * Unlocks all the mutexes owned by the invoking thread, this is <b>MUCH MORE</b>
chSchRescheduleS(); * 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.
chSysUnlock(); */
} void chMtxUnlockAll(void) {
#endif /* CH_USE_MUTEXES */ 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 */
/** @} */

View File

@ -1,193 +1,215 @@
/* /*
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio. ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
This file is part of ChibiOS/RT. This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or the Free Software Foundation; either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful, ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* @addtogroup Scheduler * @addtogroup Scheduler
* @{ * @{
*/ */
#include <ch.h> #include <ch.h>
/** @cond never */ /** @cond never */
ReadyList rlist; ReadyList rlist;
/** @endcond */ /** @endcond */
/** /**
* Scheduler initialization. * Scheduler initialization.
* @note Internally invoked by the \p chSysInit(). * @note Internally invoked by the \p chSysInit().
*/ */
void chSchInit(void) { void chSchInit(void) {
fifo_init(&rlist.r_queue); fifo_init(&rlist.r_queue);
rlist.r_prio = NOPRIO; rlist.r_prio = NOPRIO;
rlist.r_preempt = CH_TIME_QUANTUM; rlist.r_preempt = CH_TIME_QUANTUM;
#ifdef CH_USE_SYSTEMTIME #ifdef CH_USE_SYSTEMTIME
rlist.r_stime = 0; rlist.r_stime = 0;
#endif #endif
} }
/** /**
* Inserts a thread in the Ready List. * Inserts a thread in the Ready List.
* @param tp the Thread to be made ready *
* @return the Thread pointer * @param tp the Thread to be made ready
* @note The function must be called in the system mutex zone. * @return the Thread pointer
* @note The function does not reschedule, the \p chSchRescheduleS() should * @note The function must be called in the system mutex zone.
* be called soon after. * @note The function does not reschedule, the \p chSchRescheduleS() should
* @note The function is not meant to be used in the user code directly. * 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.*/ #ifdef CH_OPTIMIZE_SPEED
INLINE Thread *chSchReadyI(Thread *tp) { /* NOTE: it is inlined in this module only.*/
#else INLINE Thread *chSchReadyI(Thread *tp) {
Thread *chSchReadyI(Thread *tp) { #else
#endif Thread *chSchReadyI(Thread *tp) {
Thread *cp; #endif
Thread *cp;
tp->p_state = PRREADY;
cp = rlist.r_queue.p_next; tp->p_state = PRREADY;
while (cp->p_prio >= tp->p_prio) cp = rlist.r_queue.p_next;
cp = cp->p_next; while (cp->p_prio >= tp->p_prio)
/* Insertion on p_prev.*/ cp = cp->p_next;
tp->p_prev = (tp->p_next = cp)->p_prev; /* Insertion on p_prev.*/
tp->p_prev->p_next = cp->p_prev = tp; tp->p_prev = (tp->p_next = cp)->p_prev;
return tp; 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 * Puts the current thread to sleep into the specified state, the next highest
* \p threads.h * priority thread becomes running. The threads states are described into
* @param newstate the new thread state * \p threads.h
* @note The function must be called in the system mutex zone. * @param newstate the new thread state
* @note The function is not meant to be used in the user code directly. * @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; void chSchGoSleepS(tstate_t newstate) {
Thread *otp;
(otp = currp)->p_state = newstate;
(currp = fifo_remove(&rlist.r_queue))->p_state = PRCURR; (otp = currp)->p_state = newstate;
rlist.r_preempt = CH_TIME_QUANTUM; (currp = fifo_remove(&rlist.r_queue))->p_state = PRCURR;
#ifdef CH_USE_TRACE rlist.r_preempt = CH_TIME_QUANTUM;
chDbgTrace(otp, currp); #ifdef CH_USE_TRACE
#endif chDbgTrace(otp, currp);
chSysSwitchI(otp, currp); #endif
} chSysSwitchI(otp, currp);
}
#ifdef CH_USE_VIRTUAL_TIMERS
/* #ifdef CH_USE_VIRTUAL_TIMERS
* Timeout wakeup callback. /*
*/ * Timeout wakeup callback.
static void wakeup(void *p) { */
static void wakeup(void *p) {
#ifdef CH_USE_SEMAPHORES
if (((Thread *)p)->p_state == PRWTSEM) #ifdef CH_USE_SEMAPHORES
chSemFastSignalI(((Thread *)p)->p_wtsemp); if (((Thread *)p)->p_state == PRWTSEM)
#endif chSemFastSignalI(((Thread *)p)->p_wtsemp);
chSchReadyI(p)->p_rdymsg = RDY_TIMEOUT; #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 * Put the current thread to sleep.
* the specified time elapsed. *
* @param newstate the new thread state * Puts the current thread to sleep into the specified state. The next highest
* @param time the number of ticks before the operation timouts * priority thread becomes running. The thread put to sleep is awakened after
* @return the wakeup message, it is \p RDY_TIMEOUT if a timeout occurs * the specified time has elapsed.
* @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. * @param newstate the new thread state
*/ * @param time the number of ticks before the operation timouts
msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time) { * @return the wakeup message, it is \p RDY_TIMEOUT if a timeout occurs
VirtualTimer vt; * @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.
chVTSetI(&vt, time, wakeup, currp); */
chSchGoSleepS(newstate); msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time) {
if (chVTIsArmedI(&vt)) VirtualTimer vt;
chVTResetI(&vt);
return currp->p_rdymsg; chVTSetI(&vt, time, wakeup, currp);
} chSchGoSleepS(newstate);
#endif /* CH_USE_VIRTUAL_TIMERS */ if (chVTIsArmedI(&vt))
chVTResetI(&vt);
/** return currp->p_rdymsg;
* Wakeups a thread, the thread is inserted into the ready list or made }
* running directly depending on its relative priority compared to the current #endif /* CH_USE_VIRTUAL_TIMERS */
* thread.
* @param ntp the Thread to be made ready /**
* @param msg message to the awakened thread * Wakes up a 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. * Wakes up a thread. The thread is inserted into the ready list or immediately
* @note It is equivalent to a \p chSchReadyI() followed by a * made running depending on its relative priority compared to the current
* \p chSchRescheduleS() but much more efficient. * thread.
*/ * @param ntp the Thread to be made ready
void chSchWakeupS(Thread *ntp, msg_t msg) { * @param msg message to the awakened thread
* @note The function must be called in the system mutex zone.
ntp->p_rdymsg = msg; * @note The function is not meant to be used in the user code directly.
if (ntp->p_prio <= currp->p_prio) * @note It is equivalent to a \p chSchReadyI() followed by a
chSchReadyI(ntp); * \p chSchRescheduleS() but much more efficient.
else { */
Thread *otp = currp; void chSchWakeupS(Thread *ntp, msg_t msg) {
chSchReadyI(otp); ntp->p_rdymsg = msg;
(currp = ntp)->p_state = PRCURR; /* the woken thread has equal or lower priority than the running thread? */
rlist.r_preempt = CH_TIME_QUANTUM; if (ntp->p_prio <= currp->p_prio)
#ifdef CH_USE_TRACE /* put the woken thread on the ready queue */
chDbgTrace(otp, ntp); chSchReadyI(ntp);
#endif /* the woken thread has higher priority than the running thread */
chSysSwitchI(otp, ntp); else {
} /* put the running thread on the ready queue */
} Thread *otp = currp;
chSchReadyI(otp);
/** (currp = ntp)->p_state = PRCURR;
* Performs a reschedulation. It is meant to be called if rlist.r_preempt = CH_TIME_QUANTUM;
* \p chSchRescRequired() evaluates to \p TRUE. #ifdef CH_USE_TRACE
*/ chDbgTrace(otp, ntp);
void chSchDoRescheduleI(void) { #endif
Thread *otp = currp; /* switch the thread context */
chSysSwitchI(otp, ntp);
chSchReadyI(otp); }
(currp = fifo_remove(&rlist.r_queue))->p_state = PRCURR; }
rlist.r_preempt = CH_TIME_QUANTUM;
#ifdef CH_USE_TRACE /**
chDbgTrace(otp, currp); * Switch to the first thread on the runnable queue.
#endif *
chSysSwitchI(otp, currp); * Intended to be called if \p chSchRescRequired() evaluates to \p TRUE.
} */
void chSchDoRescheduleI(void) {
/** /* put the running thread on the ready queue */
* If a thread with an higher priority than the current thread is in the Thread *otp = currp;
* ready list then it becomes running. chSchReadyI(otp);
* @note The function must be called in the system mutex zone. /* pick the first thread from the ready queue */
*/ (currp = fifo_remove(&rlist.r_queue))->p_state = PRCURR;
void chSchRescheduleS(void) { rlist.r_preempt = CH_TIME_QUANTUM;
#ifdef CH_USE_TRACE
if (firstprio(&rlist.r_queue) > currp->p_prio) chDbgTrace(otp, currp);
chSchDoRescheduleI(); #endif
} /* switch thread context */
chSysSwitchI(otp, currp);
/** }
* Evaluates if a reschedulation is required.
* @return \p TRUE if there is a thread that should go in running state /**
* immediatly else \p FALSE. * Reschedule only if a higher priority thread is runnable.
*/ *
bool_t chSchRescRequiredI(void) { * If a thread with a higher priority than the current thread is in the
tprio_t p1 = firstprio(&rlist.r_queue); * ready list then make the higher priority thread running.
tprio_t p2 = currp->p_prio; *
* @note The function must be called in the system mutex zone.
return rlist.r_preempt ? p1 > p2 : p1 >= p2; */
} 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;
}
/** @} */

View File

@ -1,282 +1,287 @@
/* /*
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio. ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
This file is part of ChibiOS/RT. This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or the Free Software Foundation; either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful, ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* @addtogroup Threads * @addtogroup Threads
* @{ * @{
*/ */
#include <ch.h> #include <ch.h>
/* /*
* Initializes a thread structure. * Initializes a thread structure.
*/ */
void init_thread(tprio_t prio, tmode_t mode, Thread *tp) { void init_thread(tprio_t prio, tmode_t mode, Thread *tp) {
static tid_t nextid = 0; static tid_t nextid = 0;
tp->p_tid = nextid++; tp->p_tid = nextid++;
tp->p_flags = mode; tp->p_flags = mode;
tp->p_prio = prio; tp->p_prio = prio;
#ifdef CH_USE_MUTEXES #ifdef CH_USE_MUTEXES
tp->p_realprio = prio; /* realprio is the thread's own, non-inherited, priority */
tp->p_mtxlist = NULL; tp->p_realprio = prio;
#endif tp->p_mtxlist = NULL;
#ifdef CH_USE_WAITEXIT #endif
list_init(&tp->p_waiting); #ifdef CH_USE_WAITEXIT
#endif list_init(&tp->p_waiting);
#ifdef CH_USE_MESSAGES #endif
fifo_init(&tp->p_msgqueue); #ifdef CH_USE_MESSAGES
#endif fifo_init(&tp->p_msgqueue);
#ifdef CH_USE_EVENTS #endif
tp->p_epending = 0; #ifdef CH_USE_EVENTS
#endif tp->p_epending = 0;
#ifdef CH_USE_EXIT_EVENT #endif
chEvtInit(&tp->p_exitesource); #ifdef CH_USE_EXIT_EVENT
#endif chEvtInit(&tp->p_exitesource);
} #endif
}
#ifdef CH_USE_DEBUG
static void memfill(uint8_t *p, uint32_t n, uint8_t v) { #ifdef CH_USE_DEBUG
static void memfill(uint8_t *p, uint32_t n, uint8_t v) {
while (n)
*p++ = v, n--; while (n)
} *p++ = v, n--;
#endif }
#endif
/**
* Creates a new thread. /**
* @param prio the priority level for the new thread. Usually the threads are * Creates a new thread.
* created with priority \p NORMALPRIO, priorities * @param prio the priority level for the new thread. Usually the threads are
* can range from \p LOWPRIO to \p HIGHPRIO. * created with priority \p NORMALPRIO, priorities
* @param mode the creation option flags for the thread. The following options * can range from \p LOWPRIO to \p HIGHPRIO.
* can be OR'ed in this parameter:<br> * @param mode the creation option flags for the thread. The following options
* <ul> * can be OR'ed in this parameter:<br>
* <li>\p P_SUSPENDED, the thread is created in the * <ul>
* \p PRSUSPENDED state and a subsequent call to * <li>\p P_SUSPENDED, the thread is created in the
* \p chThdResume() will make it ready for * \p PRSUSPENDED state and a subsequent call to
* execution.</li> * \p chThdResume() will make it ready for
* <li>\p P_TERMINATED, this flag is usually set * execution.</li>
* by the \p chThdTerminate() function and it is not * <li>\p P_TERMINATED, this flag is usually set
* normally used as parameter for this function. The * by the \p chThdTerminate() function and it is not
* result would be to create a thread with a termination * normally used as parameter for this function. The
* request already pending.</li> * result would be to create a thread with a termination
* </ul> * request already pending.</li>
* @param workspace pointer to a working area dedicated to the thread stack * </ul>
* @param wsize size of the working area. * @param workspace pointer to a working area dedicated to the thread stack
* @param pf the thread function. Returning from this function automatically * @param wsize size of the working area.
* terminates the thread. * @param pf the thread function. Returning from this function automatically
* @param arg an argument passed to the thread function. It can be \p NULL. * terminates the thread.
* @return the pointer to the \p Thread structure allocated for the * @param arg an argument passed to the thread function. It can be \p NULL.
* thread into the working space area. * @return the pointer to the \p Thread structure allocated for the
* @note A thread can terminate by calling \p chThdExit() or by simply * thread into the working space area.
* returning from its main function. * @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 *chThdCreate(tprio_t prio, tmode_t mode, void *workspace,
Thread *tp = workspace; size_t wsize, tfunc_t pf, void *arg) {
/* thread structure is layed out in the lower part of the thread workspace */
chDbgAssert((wsize >= UserStackSize(0)) && (prio <= HIGHPRIO) && Thread *tp = workspace;
(workspace != NULL) && (pf != NULL),
"chthreads.c, chThdCreate()"); chDbgAssert((wsize >= UserStackSize(0)) && (prio <= HIGHPRIO) &&
#ifdef CH_USE_DEBUG (workspace != NULL) && (pf != NULL),
memfill(workspace, wsize, MEM_FILL_PATTERN); "chthreads.c, chThdCreate()");
#endif #ifdef CH_USE_DEBUG
SETUP_CONTEXT(workspace, wsize, pf, arg); memfill(workspace, wsize, MEM_FILL_PATTERN);
init_thread(prio, mode, tp); #endif
#ifdef CH_USE_RESUME SETUP_CONTEXT(workspace, wsize, pf, arg);
if (tp->p_flags & P_SUSPENDED) init_thread(prio, mode, tp);
tp->p_state = PRSUSPENDED; #ifdef CH_USE_RESUME
else { if (tp->p_flags & P_SUSPENDED)
#endif tp->p_state = PRSUSPENDED;
chSysLock(); else {
chSchWakeupS(tp, RDY_OK); #endif
chSysUnlock(); chSysLock();
#ifdef CH_USE_RESUME chSchWakeupS(tp, RDY_OK);
} chSysUnlock();
#endif #ifdef CH_USE_RESUME
return tp; }
} #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 * Creates a new thread.
* can range from \p LOWPRIO to \p HIGHPRIO. * @param prio the priority level for the new thread. Usually the threads are
* @param workspace pointer to a working area dedicated to the thread stack * created with priority \p NORMALPRIO, priorities
* @param wsize size of the working area. * can range from \p LOWPRIO to \p HIGHPRIO.
* @param pf the thread function. Returning from this function automatically * @param workspace pointer to a working area dedicated to the thread stack
* terminates the thread. * @param wsize size of the working area.
* @return the pointer to the \p Thread structure allocated for the * @param pf the thread function. Returning from this function automatically
* thread into the working space area. * terminates the thread.
* @note A thread can terminate by calling \p chThdExit() or by simply * @return the pointer to the \p Thread structure allocated for the
* returning from its main function. * thread into the working space area.
*/ * @note A thread can terminate by calling \p chThdExit() or by simply
Thread *chThdCreateFast(tprio_t prio, void *workspace, * returning from its main function.
size_t wsize, tfunc_t pf) { */
Thread *tp = workspace; Thread *chThdCreateFast(tprio_t prio, void *workspace,
size_t wsize, tfunc_t pf) {
chDbgAssert((wsize >= UserStackSize(0)) && (prio <= HIGHPRIO) && Thread *tp = workspace;
(workspace != NULL) && (pf != NULL),
"chthreads.c, chThdCreateFast()"); chDbgAssert((wsize >= UserStackSize(0)) && (prio <= HIGHPRIO) &&
#ifdef CH_USE_DEBUG (workspace != NULL) && (pf != NULL),
memfill(workspace, wsize, MEM_FILL_PATTERN); "chthreads.c, chThdCreateFast()");
#endif #ifdef CH_USE_DEBUG
SETUP_CONTEXT(workspace, wsize, pf, NULL); memfill(workspace, wsize, MEM_FILL_PATTERN);
init_thread(prio, 0, tp); #endif
chSysLock(); SETUP_CONTEXT(workspace, wsize, pf, NULL);
chSchWakeupS(tp, RDY_OK); init_thread(prio, 0, tp);
chSysUnlock(); chSysLock();
return tp; chSchWakeupS(tp, RDY_OK);
} chSysUnlock();
return tp;
/** }
* Changes the thread priority, reschedules if necessary.
* @param newprio the new priority of the invoking thread /**
*/ * Changes the running thread priority, reschedules if necessary.
void chThdSetPriority(tprio_t newprio) { *
* @param newprio the new priority of the running thread
chDbgAssert(newprio <= HIGHPRIO, "chthreads.c, chThdSetPriority()") */
chSysLock(); void chThdSetPriority(tprio_t newprio) {
#ifdef CH_USE_MUTEXES chDbgAssert(newprio <= HIGHPRIO, "chthreads.c, chThdSetPriority()")
if (currp->p_prio != currp->p_realprio) { chSysLock();
if (newprio > currp->p_prio)
currp->p_prio = newprio; #ifdef CH_USE_MUTEXES
} if (currp->p_prio != currp->p_realprio) {
else if (newprio > currp->p_prio)
currp->p_prio = newprio; currp->p_prio = newprio;
currp->p_realprio = newprio; }
#else else
currp->p_prio = newprio; currp->p_prio = newprio;
#endif currp->p_realprio = newprio;
chSchRescheduleS(); #else
currp->p_prio = newprio;
chSysUnlock(); #endif
} chSchRescheduleS();
#ifdef CH_USE_SUSPEND chSysUnlock();
/** }
* Suspends the invoking thread.
* #ifdef CH_USE_SUSPEND
* @param tpp pointer to a \p Thread pointer, the \p Thread pointer is set /**
* to point to the suspended process before it enters the * Suspends the invoking thread.
* \p PRSUSPENDED state, it is set to \p NULL after it is resumed. *
* This allows to implement a "test and resume" on the variable * @param tpp pointer to a \p Thread pointer, the \p Thread pointer is set
* into interrupt handlers. * to point to the suspended process before it enters the
* @note The function is available only if the \p CH_USE_SUSPEND * \p PRSUSPENDED state, it is set to \p NULL after it is resumed.
* option is enabled in \p chconf.h. * This allows to implement a "test and resume" on the variable
*/ * into interrupt handlers.
void chThdSuspend(Thread **tpp) { * @note The function is available only if the \p CH_USE_SUSPEND
* option is enabled in \p chconf.h.
chSysLock(); */
void chThdSuspend(Thread **tpp) {
chDbgAssert(*tpp == NULL, "chthreads.c, chThdSuspend()");
*tpp = currp; chSysLock();
chSchGoSleepS(PRSUSPENDED);
*tpp = NULL; chDbgAssert(*tpp == NULL, "chthreads.c, chThdSuspend()");
*tpp = currp;
chSysUnlock(); chSchGoSleepS(PRSUSPENDED);
} *tpp = NULL;
#endif /* CH_USE_SUSPEND */
chSysUnlock();
#ifdef CH_USE_RESUME }
/** #endif /* CH_USE_SUSPEND */
* Resumes a thread created with the \p P_SUSPENDED option or suspended with
* \p chThdSuspend(). #ifdef CH_USE_RESUME
* @param tp the pointer to the thread /**
* @note The function has no effect on threads in any other state than * Resumes a thread created with the \p P_SUSPENDED option or suspended with
* \p PRSUSPENDED. * \p chThdSuspend().
* @note The function is available only if the \p CH_USE_RESUME * @param tp the pointer to the thread
* option is enabled in \p chconf.h. * @note The function has no effect on threads in any other state than
*/ * \p PRSUSPENDED.
void chThdResume(Thread *tp) { * @note The function is available only if the \p CH_USE_RESUME
* option is enabled in \p chconf.h.
chSysLock(); */
void chThdResume(Thread *tp) {
if ((tp)->p_state == PRSUSPENDED)
chSchWakeupS(tp, RDY_OK); chSysLock();
chSysUnlock(); if ((tp)->p_state == PRSUSPENDED)
} chSchWakeupS(tp, RDY_OK);
#endif
chSysUnlock();
#ifdef CH_USE_TERMINATE }
/** #endif
* Requests a thread termination.
* @param tp the pointer to the thread #ifdef CH_USE_TERMINATE
* @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 * Requests a thread termination.
* invoking \p chThdShouldTerminate() and then terminate cleanly. * @param tp the pointer to the thread
*/ * @note The thread is not termitated but a termination request is added to
void chThdTerminate(Thread *tp) { * its \p p_flags field. The thread can read this status by
* invoking \p chThdShouldTerminate() and then terminate cleanly.
chSysLock(); */
void chThdTerminate(Thread *tp) {
tp->p_flags |= P_TERMINATE;
chSysLock();
chSysUnlock();
} tp->p_flags |= P_TERMINATE;
#endif
chSysUnlock();
/** }
* Terminates the current thread by specifying an exit status code. #endif
* @param msg the thread exit code. The code can be retrieved by using
* \p chThdWait(). /**
*/ * Terminates the current thread by specifying an exit status code.
void chThdExit(msg_t msg) { *
* @param msg the thread exit code. The code can be retrieved by using
chSysLock(); * \p chThdWait().
*/
currp->p_exitcode = msg; void chThdExit(msg_t msg) {
#ifdef CH_USE_WAITEXIT
while (notempty(&currp->p_waiting)) chSysLock();
chSchReadyI(list_remove(&currp->p_waiting));
#endif currp->p_exitcode = msg;
#ifdef CH_USE_EXIT_EVENT #ifdef CH_USE_WAITEXIT
chEvtSendI(&currp->p_exitesource); while (notempty(&currp->p_waiting))
#endif chSchReadyI(list_remove(&currp->p_waiting));
chSchGoSleepS(PREXIT); #endif
} #ifdef CH_USE_EXIT_EVENT
chEvtSendI(&currp->p_exitesource);
#ifdef CH_USE_WAITEXIT #endif
/** chSchGoSleepS(PREXIT);
* 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 #ifdef CH_USE_WAITEXIT
* @return the exit code /**
* @note The function is available only if the \p CH_USE_WAITEXIT * Blocks the execution of the invoking thread until the specified thread
* option is enabled in \p chconf.h. * terminates then the exit code is returned.
*/ *
msg_t chThdWait(Thread *tp) { * @param tp the pointer to the thread
msg_t msg; * @return the exit code
* @note The function is available only if the \p CH_USE_WAITEXIT
chSysLock(); * option is enabled in \p chconf.h.
*/
if (tp->p_state != PREXIT) { msg_t chThdWait(Thread *tp) {
list_insert(currp, &tp->p_waiting); msg_t msg;
chSchGoSleepS(PRWAIT);
} chSysLock();
msg = tp->p_exitcode;
if (tp->p_state != PREXIT) {
chSysUnlock(); list_insert(currp, &tp->p_waiting);
return msg; chSchGoSleepS(PRWAIT);
} }
#endif /* CH_USE_WAITEXIT */ msg = tp->p_exitcode;
/** @} */ chSysUnlock();
return msg;
}
#endif /* CH_USE_WAITEXIT */
/** @} */

View File

@ -1,184 +1,184 @@
/* /*
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio. ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
This file is part of ChibiOS/RT. This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or the Free Software Foundation; either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful, ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* @addtogroup IOQueues * @addtogroup IOQueues
* @{ * @{
*/ */
#ifndef _QUEUES_H_ #ifndef _QUEUES_H_
#define _QUEUES_H_ #define _QUEUES_H_
/** Queue notification callback type.*/ /** Queue notification callback type. */
typedef void (*qnotify_t)(void); typedef void (*qnotify_t)(void);
/** Returned by the queue functions if the operation is successful.*/ /** Returned by the queue functions if the operation is successful. */
#define Q_OK RDY_OK #define Q_OK RDY_OK
/** Returned by the queue functions if a timeout occurs.*/ /** Returned by the queue functions if a timeout occurs. */
#define Q_TIMEOUT RDY_TIMEOUT #define Q_TIMEOUT RDY_TIMEOUT
/** Returned by the queue functions if the queue is reset.*/ /** Returned by the queue functions if the queue is reset. */
#define Q_RESET RDY_RESET #define Q_RESET RDY_RESET
/** Returned by the queue functions if the queue is empty.*/ /** Returned by the queue functions if the queue is empty. */
#define Q_EMPTY -3 #define Q_EMPTY -3
/** Returned by the queue functions if the queue is full.*/ /** Returned by the queue functions if the queue is full. */
#define Q_FULL -4 #define Q_FULL -4
#ifdef CH_USE_QUEUES #ifdef CH_USE_QUEUES
/** /**
* I/O queue structure, it is used by both Input and Output Queues, * I/O queue structure, it is used by both Input and Output Queues,
* the difference is on how the semaphore is initialized. * the difference is on how the semaphore is initialized.
*/ */
typedef struct { typedef struct {
/** Pointer to the queue buffer.*/ /** Pointer to the queue buffer. */
uint8_t *q_buffer; uint8_t *q_buffer;
/** Pointer to the first location after the buffer.*/ /** Pointer to the first location after the buffer. */
uint8_t *q_top; uint8_t *q_top;
/** Write pointer.*/ /** Write pointer. */
uint8_t *q_wrptr; uint8_t *q_wrptr;
/** Read pointer.*/ /** Read pointer. */
uint8_t *q_rdptr; uint8_t *q_rdptr;
/** Counter semaphore.*/ /** Counter semaphore. */
Semaphore q_sem; Semaphore q_sem;
/** Data notification callback.*/ /** Data notification callback. */
qnotify_t q_notify; qnotify_t q_notify;
} Queue; } Queue;
/** Returns the queue's buffer size.*/ /** Returns the queue's buffer size. */
#define chQSize(q) \ #define chQSize(q) \
((q)->q_top - (q)->q_buffer) ((q)->q_top - (q)->q_buffer)
/** Returns the used space if used on an Input Queue and the empty space if /** Returns the used space if used on an Input Queue and the empty space if
* used on an Output Queue.*/ * used on an Output Queue. */
#define chQSpace(q) \ #define chQSpace(q) \
((q)->q_sem.s_cnt) ((q)->q_sem.s_cnt)
/** Evaluates to TRUE if the specified Input Queue is empty.*/ /** Evaluates to TRUE if the specified Input Queue is empty. */
#define chIQIsEmpty(q) \ #define chIQIsEmpty(q) \
(chQSpace(q) <= 0) (chQSpace(q) <= 0)
/** Evaluates to TRUE if the specified Input Queue is full.*/ /** Evaluates to TRUE if the specified Input Queue is full. */
#define chIQIsFull(q) \ #define chIQIsFull(q) \
(chQSpace(q) >= chQSize(q)) (chQSpace(q) >= chQSize(q))
/** Evaluates to TRUE if the specified Output Queue is empty.*/ /** Evaluates to TRUE if the specified Output Queue is empty. */
#define chOQIsEmpty(q) \ #define chOQIsEmpty(q) \
(chQSpace(q) >= chQSize(q)) (chQSpace(q) >= chQSize(q))
/** Evaluates to TRUE if the specified Output Queue is full.*/ /** Evaluates to TRUE if the specified Output Queue is full. */
#define chOQIsFull(q) \ #define chOQIsFull(q) \
(chQSpace(q) <= 0) (chQSpace(q) <= 0)
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/* /*
* Input Queues functions. An Input Queue is usually written into by an * Input Queues functions. An Input Queue is usually written into by an
* interrupt handler and read from a thread. * interrupt handler and read from a thread.
*/ */
void chIQInit(Queue *qp, uint8_t *buffer, size_t size, qnotify_t inotify); void chIQInit(Queue *qp, uint8_t *buffer, size_t size, qnotify_t inotify);
void chIQReset(Queue *qp); void chIQReset(Queue *qp);
msg_t chIQPutI(Queue *qp, uint8_t b); msg_t chIQPutI(Queue *qp, uint8_t b);
msg_t chIQGet(Queue *qp); msg_t chIQGet(Queue *qp);
size_t chIQRead(Queue *qp, uint8_t *buffer, size_t n); size_t chIQRead(Queue *qp, uint8_t *buffer, size_t n);
#ifdef CH_USE_QUEUES_TIMEOUT #ifdef CH_USE_QUEUES_TIMEOUT
msg_t chIQGetTimeout(Queue *qp, systime_t time); msg_t chIQGetTimeout(Queue *qp, systime_t time);
#endif #endif
/* /*
* Output Queues functions. An Output Queue is usually written into by a * Output Queues functions. An Output Queue is usually written into by a
* thread and read from an interrupt handler. * thread and read from an interrupt handler.
*/ */
void chOQInit(Queue *queue, uint8_t *buffer, size_t size, qnotify_t onotify); void chOQInit(Queue *queue, uint8_t *buffer, size_t size, qnotify_t onotify);
void chOQReset(Queue *queue); void chOQReset(Queue *queue);
void chOQPut(Queue *queue, uint8_t b); void chOQPut(Queue *queue, uint8_t b);
msg_t chOQGetI(Queue *queue); msg_t chOQGetI(Queue *queue);
size_t chOQWrite(Queue *queue, uint8_t *buffer, size_t n); size_t chOQWrite(Queue *queue, uint8_t *buffer, size_t n);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* CH_USE_QUEUES */ #endif /* CH_USE_QUEUES */
#ifdef CH_USE_QUEUES_HALFDUPLEX #ifdef CH_USE_QUEUES_HALFDUPLEX
/** /**
* Half duplex queue structure. * Half duplex queue structure.
*/ */
typedef struct { typedef struct {
/** Pointer to the queue buffer.*/ /** Pointer to the queue buffer. */
uint8_t *hdq_buffer; uint8_t *hdq_buffer;
/** Pointer to the first location after the buffer.*/ /** Pointer to the first location after the buffer. */
uint8_t *hdq_top; uint8_t *hdq_top;
/** Write pointer.*/ /** Write pointer.*/
uint8_t *hdq_wrptr; uint8_t *hdq_wrptr;
/** Read pointer.*/ /** Read pointer.*/
uint8_t *hdq_rdptr; uint8_t *hdq_rdptr;
/** Input counter semaphore.*/ /** Input counter semaphore. */
Semaphore hdq_isem; Semaphore hdq_isem;
/** Output counter semaphore.*/ /** Output counter semaphore. */
Semaphore hdq_osem; Semaphore hdq_osem;
/** Input data notification callback.*/ /** Input data notification callback. */
qnotify_t hdq_inotify; qnotify_t hdq_inotify;
/** Output data notification callback.*/ /** Output data notification callback. */
qnotify_t hdq_onotify; qnotify_t hdq_onotify;
} HalfDuplexQueue; } HalfDuplexQueue;
/** Returns the queue's buffer size.*/ /** Returns the queue's buffer size. */
#define chHDQSize(q) \ #define chHDQSize(q) \
((q)->hdq_top - (q)->hdq_buffer) ((q)->hdq_top - (q)->hdq_buffer)
/** Returns the queue space when in transmission mode.*/ /** Returns the queue space when in transmission mode. */
#define chHDQEmptySpace(q) \ #define chHDQEmptySpace(q) \
((q)->hdq_osem.s_cnt) ((q)->hdq_osem.s_cnt)
/** Returns the number of the bytes in the queue when in receive mode.*/ /** Returns the number of the bytes in the queue when in receive mode. */
#define chHDQFilledSpace(q) \ #define chHDQFilledSpace(q) \
((q)->hdq_isem.s_cnt) ((q)->hdq_isem.s_cnt)
/** Evaluates to TRUE if the queue is in transmit mode.*/ /** Evaluates to TRUE if the queue is in transmit mode. */
#define chHDQIsTransmitting(q) \ #define chHDQIsTransmitting(q) \
(chHDQEmptySpace(q) < chHDQSize(q)) (chHDQEmptySpace(q) < chHDQSize(q))
/** Evaluates to TRUE if the queue is in receive mode.*/ /** Evaluates to TRUE if the queue is in receive mode. */
#define chHDQIsReceiving(q) \ #define chHDQIsReceiving(q) \
(chHDQEmptySpaceQ(q) >= chHDQSize(q)) (chHDQEmptySpaceQ(q) >= chHDQSize(q))
/** Evaluates to TRUE if the receive queue is full.*/ /** Evaluates to TRUE if the receive queue is full. */
#define chHDQIsFullReceive(q) \ #define chHDQIsFullReceive(q) \
(chHDQFilledSpace(q) >= chHDQSize(q)) (chHDQFilledSpace(q) >= chHDQSize(q))
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
void chHDQInit(HalfDuplexQueue *qp, uint8_t *buffer, size_t size, void chHDQInit(HalfDuplexQueue *qp, uint8_t *buffer, size_t size,
qnotify_t inotify, qnotify_t onotify); qnotify_t inotify, qnotify_t onotify);
msg_t chHDQGetReceive(HalfDuplexQueue *qp); msg_t chHDQGetReceive(HalfDuplexQueue *qp);
void chHDQPutTransmit(HalfDuplexQueue *qp, uint8_t b); void chHDQPutTransmit(HalfDuplexQueue *qp, uint8_t b);
msg_t chHDQGetTransmitI(HalfDuplexQueue *qp); msg_t chHDQGetTransmitI(HalfDuplexQueue *qp);
msg_t chHDQPutReceiveI(HalfDuplexQueue *qp, uint8_t b); msg_t chHDQPutReceiveI(HalfDuplexQueue *qp, uint8_t b);
#ifdef CH_USE_QUEUES_TIMEOUT #ifdef CH_USE_QUEUES_TIMEOUT
msg_t chHDQGetReceiveTimeout(HalfDuplexQueue *qp, systime_t time); msg_t chHDQGetReceiveTimeout(HalfDuplexQueue *qp, systime_t time);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* CH_USE_QUEUES_HALFDUPLEX */ #endif /* CH_USE_QUEUES_HALFDUPLEX */
#endif /* _QUEUES_H_ */ #endif /* _QUEUES_H_ */
/** @} */ /** @} */

View File

@ -1,80 +1,82 @@
/* /*
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio. ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
This file is part of ChibiOS/RT. This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or the Free Software Foundation; either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful, ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* @addtogroup Scheduler * @addtogroup Scheduler
* @{ * @{
*/ */
#ifndef _SCHEDULER_H_ #ifndef _SCHEDULER_H_
#define _SCHEDULER_H_ #define _SCHEDULER_H_
/** Normal \p chSchReadyI() message.*/ /** Normal \p chSchReadyI() message. */
#define RDY_OK 0 #define RDY_OK 0
/** Returned if the thread was made ready because a timeout.*/ /** Returned when the thread was made ready because of a timeout. */
#define RDY_TIMEOUT -1 #define RDY_TIMEOUT -1
/** Returned if the thread was made ready because a reset.*/ /** Returned when the thread was made ready because of a reset. */
#define RDY_RESET -2 #define RDY_RESET -2
#define firstprio(rlp) ((rlp)->p_next->p_prio) /** The priority of the first thread on the given ready list. */
#define firstprio(rlp) ((rlp)->p_next->p_prio)
/**
* Ready list header. /**
*/ * Ready list header.
typedef struct { */
ThreadsQueue r_queue; typedef struct {
tprio_t r_prio; ThreadsQueue r_queue;
cnt_t r_preempt; tprio_t r_prio;
#ifndef CH_CURRP_REGISTER_CACHE cnt_t r_preempt;
Thread *r_current; #ifndef CH_CURRP_REGISTER_CACHE
#endif /** the currently running thread */
#ifdef CH_USE_SYSTEMTIME Thread *r_current;
volatile systime_t r_stime; #endif
#endif #ifdef CH_USE_SYSTEMTIME
} ReadyList; volatile systime_t r_stime;
#endif
extern ReadyList rlist; } ReadyList;
/* extern ReadyList rlist;
* Scheduler APIs.
*/ /*
#ifdef __cplusplus * Scheduler APIs.
extern "C" { */
#endif #ifdef __cplusplus
void chSchInit(void); extern "C" {
Thread *chSchReadyI(Thread *tp); #endif
void chSchGoSleepS(tstate_t newstate); void chSchInit(void);
msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time); Thread *chSchReadyI(Thread *tp);
void chSchWakeupS(Thread *tp, msg_t msg); void chSchGoSleepS(tstate_t newstate);
void chSchDoRescheduleI(void); msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time);
void chSchRescheduleS(void); void chSchWakeupS(Thread *tp, msg_t msg);
bool_t chSchRescRequiredI(void); void chSchDoRescheduleI(void);
#ifdef __cplusplus void chSchRescheduleS(void);
} bool_t chSchRescRequiredI(void);
#endif #ifdef __cplusplus
}
#ifdef CH_CURRP_REGISTER_CACHE #endif
register Thread *currp asm(CH_CURRP_REGISTER_CACHE);
#else #ifdef CH_CURRP_REGISTER_CACHE
#define currp rlist.r_current register Thread *currp asm(CH_CURRP_REGISTER_CACHE);
#endif #else
#define currp rlist.r_current
#endif /* _SCHEDULER_H_ */ #endif
/** @} */ #endif /* _SCHEDULER_H_ */
/** @} */

View File

@ -1,241 +1,242 @@
/* /*
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio. ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
This file is part of ChibiOS/RT. This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or the Free Software Foundation; either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful, ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* @addtogroup Threads * @addtogroup Threads
* @{ * @{
*/ */
#ifndef _THREADS_H_ #ifndef _THREADS_H_
#define _THREADS_H_ #define _THREADS_H_
/** /**
* Structure representing a thread. * Structure representing a thread.
* @note Not all the listed fields are always needed, by switching off some * @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 * not needed ChibiOS/RT subsystems it is possible to save RAM space by
* shrinking the \p Thread structure. * shrinking the \p Thread structure.
*/ */
struct Thread { struct Thread {
/** Next \p Thread in the threads list.*/ /** Next \p Thread in the threads list.*/
Thread *p_next; Thread *p_next;
/* End of the fields shared with the ThreadsList structure. */ /* End of the fields shared with the ThreadsList structure. */
/** Previous \p Thread in the threads list.*/ /** Previous \p Thread in the threads list.*/
Thread *p_prev; Thread *p_prev;
/* End of the fields shared with the ThreadsQueue structure. */ /* End of the fields shared with the ThreadsQueue structure. */
/** The thread priority.*/ /** The thread priority.*/
tprio_t p_prio; tprio_t p_prio;
/* End of the fields shared with the ReadyList structure. */ /* End of the fields shared with the ReadyList structure. */
/** Thread identifier. */ /** Thread identifier. */
tid_t p_tid; tid_t p_tid;
/** Current thread state.*/ /** Current thread state.*/
tstate_t p_state; tstate_t p_state;
/** Mode flags.*/ /** Mode flags. */
tmode_t p_flags; tmode_t p_flags;
/** Machine dependent processor context.*/ /** Machine dependent processor context.*/
Context p_ctx; Context p_ctx;
/* /*
* The following fields are merged in unions because they are all * The following fields are merged in unions because they are all
* state-specific fields. This trick saves some extra space for each * state-specific fields. This trick saves some extra space for each
* thread in the system. * thread in the system.
*/ */
union { union {
/** Thread wakeup code (only valid when exiting the \p PRREADY state).*/ /** Thread wakeup code (only valid when exiting the \p PRREADY state). */
msg_t p_rdymsg; msg_t p_rdymsg;
/** The thread exit code (only while in \p PREXIT state).*/ /** The thread exit code (only while in \p PREXIT state).*/
msg_t p_exitcode; msg_t p_exitcode;
#ifdef CH_USE_SEMAPHORES #ifdef CH_USE_SEMAPHORES
/** Semaphore where the thread is waiting on (only in \p PRWTSEM state).*/ /** Semaphore where the thread is waiting on (only in \p PRWTSEM state). */
Semaphore *p_wtsemp; Semaphore *p_wtsemp;
#endif #endif
#ifdef CH_USE_MUTEXES #ifdef CH_USE_MUTEXES
/** Mutex where the thread is waiting on (only in \p PRWTMTX state).*/ /** Mutex where the thread is waiting on (only in \p PRWTMTX state). */
Mutex *p_wtmtxp; Mutex *p_wtmtxp;
#endif #endif
#ifdef CH_USE_MESSAGES #ifdef CH_USE_MESSAGES
/** Destination thread for message send (only in \p PRSNDMSG state).*/ /** Destination thread for message send (only in \p PRSNDMSG state). */
Thread *p_wtthdp; Thread *p_wtthdp;
#endif #endif
#ifdef CH_USE_EVENTS #ifdef CH_USE_EVENTS
/** Enabled events mask (only while in \p PRWTEVENT state).*/ /** Enabled events mask (only while in \p PRWTEVENT state). */
eventmask_t p_ewmask; eventmask_t p_ewmask;
#endif #endif
#ifdef CH_USE_TRACE #ifdef CH_USE_TRACE
/** Kernel object where the thread is waiting on. It is only valid when /** Kernel object where the thread is waiting on. It is only valid when
the thread is some sleeping states.*/ the thread is some sleeping states. */
void *p_wtobjp; void *p_wtobjp;
#endif #endif
}; };
/* /*
* Start of the optional fields. * Start of the optional fields.
*/ */
#ifdef CH_USE_WAITEXIT #ifdef CH_USE_WAITEXIT
/** The list of the threads waiting for this thread termination.*/ /** The list of the threads waiting for this thread termination.*/
ThreadsList p_waiting; ThreadsList p_waiting;
#endif #endif
#ifdef CH_USE_EXIT_EVENT #ifdef CH_USE_EXIT_EVENT
/** The thread termination \p EventSource.*/ /** The thread termination \p EventSource.*/
EventSource p_exitesource; EventSource p_exitesource;
#endif #endif
#ifdef CH_USE_MESSAGES #ifdef CH_USE_MESSAGES
ThreadsQueue p_msgqueue; ThreadsQueue p_msgqueue;
msg_t p_msg; msg_t p_msg;
#endif #endif
#ifdef CH_USE_EVENTS #ifdef CH_USE_EVENTS
/** Pending events mask.*/ /** Pending events mask.*/
eventmask_t p_epending; eventmask_t p_epending;
#endif #endif
#ifdef CH_USE_MUTEXES #ifdef CH_USE_MUTEXES
/** Owner mutexes list, \p NULL terminated.*/ /** List of mutexes owned by this thread, \p NULL terminated.*/
Mutex *p_mtxlist; Mutex *p_mtxlist;
tprio_t p_realprio; /** Thread's own, non-inherited, priority */
#endif tprio_t p_realprio;
}; #endif
};
/** Thread state: Thread in the ready list.*/
#define PRREADY 0 /** Thread state: Thread in the ready list.*/
/** Thread state: Current.*/ #define PRREADY 0
#define PRCURR 1 /** Thread state: Current.*/
/** Thread state: Thread created in suspended state.*/ #define PRCURR 1
#define PRSUSPENDED 2 /** Thread state: Thread created in suspended state.*/
/** Thread state: Waiting on a semaphore.*/ #define PRSUSPENDED 2
#define PRWTSEM 3 /** Thread state: Waiting on a semaphore.*/
/** Thread state: Waiting on a mutex.*/ #define PRWTSEM 3
#define PRWTMTX 4 /** Thread state: Waiting on a mutex.*/
/** Thread state: Waiting in \p chThdSleep() or \p chThdSleepUntil().*/ #define PRWTMTX 4
#define PRSLEEP 5 /** Thread state: Waiting in \p chThdSleep() or \p chThdSleepUntil().*/
/** Thread state: Waiting in \p chThdWait().*/ #define PRSLEEP 5
#define PRWAIT 6 /** Thread state: Waiting in \p chThdWait().*/
/** Thread state: Waiting in \p chEvtWait().*/ #define PRWAIT 6
#define PRWTEVENT 7 /** Thread state: Waiting in \p chEvtWait().*/
/** Thread state: Waiting in \p chMsgSend().*/ #define PRWTEVENT 7
#define PRSNDMSG 8 /** Thread state: Waiting in \p chMsgSend().*/
/** Thread state: Waiting in \p chMsgWait().*/ #define PRSNDMSG 8
#define PRWTMSG 9 /** Thread state: Waiting in \p chMsgWait().*/
/** Thread state: After termination.*/ #define PRWTMSG 9
#define PREXIT 10 /** Thread state: After termination.*/
#define PREXIT 10
#ifdef CH_USE_TERMINATE
/** Thread option: Termination requested flag.*/ #ifdef CH_USE_TERMINATE
#define P_TERMINATE 1 /** Thread option: Termination requested flag.*/
#endif #define P_TERMINATE 1
#ifdef CH_USE_RESUME #endif
/** Thread option: Create suspended thread.*/ #ifdef CH_USE_RESUME
#define P_SUSPENDED 2 /** Thread option: Create suspended thread.*/
#endif #define P_SUSPENDED 2
#ifdef CH_USE_MESSAGES_PRIORITY #endif
/** Thread option: Serve messages by priority instead of FIFO order.*/ #ifdef CH_USE_MESSAGES_PRIORITY
#define P_MSGBYPRIO 4 /** Thread option: Serve messages by priority instead of FIFO order.*/
#endif #define P_MSGBYPRIO 4
#endif
/** Pseudo priority used by the ready list header, do not use.*/
#define NOPRIO 0 /** Pseudo priority used by the ready list header, do not use.*/
/** Idle thread priority.*/ #define NOPRIO 0
#define IDLEPRIO 1 /** Idle thread priority.*/
/** Lowest user priority.*/ #define IDLEPRIO 1
#define LOWPRIO 2 /** Lowest user priority.*/
/** Normal user priority.*/ #define LOWPRIO 2
#define NORMALPRIO 64 /** Normal user priority.*/
/** Highest user priority.*/ #define NORMALPRIO 64
#define HIGHPRIO 127 /** Highest user priority.*/
/** Greatest possible priority.*/ #define HIGHPRIO 127
#define ABSPRIO 255 /** 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); /* 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 *); /** Thread function.*/
typedef msg_t (*tfunc_t)(void *);
/*
* Threads APIs. /*
*/ * Threads APIs.
#ifdef __cplusplus */
extern "C" { #ifdef __cplusplus
#endif extern "C" {
Thread *chThdCreate(tprio_t prio, tmode_t mode, void *workspace, #endif
size_t wsize, tfunc_t pf, void *arg); Thread *chThdCreate(tprio_t prio, tmode_t mode, void *workspace,
Thread *chThdCreateFast(tprio_t prio, void *workspace, size_t wsize, tfunc_t pf, void *arg);
size_t wsize, tfunc_t pf); Thread *chThdCreateFast(tprio_t prio, void *workspace,
void chThdSetPriority(tprio_t newprio); size_t wsize, tfunc_t pf);
void chThdExit(msg_t msg); void chThdSetPriority(tprio_t newprio);
#ifdef CH_USE_RESUME void chThdExit(msg_t msg);
void chThdResume(Thread *tp); #ifdef CH_USE_RESUME
#endif void chThdResume(Thread *tp);
#ifdef CH_USE_SUSPEND #endif
void chThdSuspend(Thread **tpp); #ifdef CH_USE_SUSPEND
#endif void chThdSuspend(Thread **tpp);
#ifdef CH_USE_TERMINATE #endif
void chThdTerminate(Thread *tp); #ifdef CH_USE_TERMINATE
#endif void chThdTerminate(Thread *tp);
#ifdef CH_USE_WAITEXIT #endif
msg_t chThdWait(Thread *tp); #ifdef CH_USE_WAITEXIT
#endif msg_t chThdWait(Thread *tp);
#ifdef __cplusplus #endif
} #ifdef __cplusplus
#endif }
#endif
/** Returns the pointer to the \p Thread currently in execution.*/
#define chThdSelf() currp /** Returns the pointer to the \p Thread currently in execution.*/
#define chThdSelf() currp
/** Returns the thread priority.*/
#define chThdGetPriority() (currp->p_prio) /** 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) /** 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 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. /**
*/ * Verifies if the current thread has a termination request pending.
#define chThdShouldTerminate() (currp->p_flags & P_TERMINATE) */
#define chThdShouldTerminate() (currp->p_flags & P_TERMINATE)
/**
* Returns the exit event source for the specified thread. The source is /**
* signaled when the thread terminates. * Returns the exit event source for the specified thread. The source is
* @param tp the pointer to the thread * signaled when the thread terminates.
* @note When registering on a thread termination make sure the thread * @param tp the pointer to the thread
* is still alive, if you do that after the thread termination * @note When registering on a thread termination make sure the thread
* then you would miss the event. There are two ways to ensure * is still alive, if you do that after the thread termination
* this:<br> * then you would miss the event. There are two ways to ensure
* <ul> * this:<br>
* <li>Create the thread suspended, register on the event source * <ul>
* and then resume the thread (recommended).</li> * <li>Create the thread suspended, register on the event source
* <li>Create the thread with a lower priority then register on it. * and then resume the thread (recommended).</li>
* This does not work if the hardware is capable of multiple * <li>Create the thread with a lower priority then register on it.
* physical threads.</li> * This does not work if the hardware is capable of multiple
* </ul> * physical threads.</li>
* @note You dont need to unregister from a terminated thread because * </ul>
* the event source becomes inactive. * @note You dont need to unregister from a terminated thread because
* @note The function is available only if the \p CH_USE_EXIT_EVENT * the event source becomes inactive.
* option is enabled in \p chconf.h. * @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) */
#define chThdGetExitEventSource(tp) (&(tp)->p_exitesource)
/**
* Resumes a thread created with the \p P_SUSPENDED option or suspended with /**
* \p chThdSuspend(). * Resumes a thread created with the \p P_SUSPENDED option or suspended with
* @param tp the pointer to the thread * \p chThdSuspend().
*/ * @param tp the pointer to the thread
#define chThdResumeI(tp) chSchReadyI((tp), RDY_OK) */
#define chThdResumeI(tp) chSchReadyI((tp), RDY_OK)
#endif /* _THREADS_H_ */
#endif /* _THREADS_H_ */
/** @} */
/** @} */