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