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

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

View File

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

View File

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

View File

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

View File

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

View File

@ -74,6 +74,12 @@ Win32-MinGW - ChibiOS/RT simulator and demo into a WIN32 process,
*** Releases ***
*****************************************************************************
*** 0.6.8 ***
- FIX: Fixed a bug in the priority inheritance mechanism, the bug was only a
problems when the CH_USE_MESSAGES_PRIORITY was enabled, this option is
disabled by default in ChibiOS/RT so it should not affect any user.
- Merged the documentation fixes submitted by Leon Woestenberg (thank you).
*** 0.6.7 ***
- NEW: New chThdCreateFast() API, it is a simplified form of chThdCreate()
that allows even faster threads creation. The new API does not support

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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