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