/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 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 .
*/
/**
* @page article_wakeup How to wake up a thread from an interrupt handler
* Waking up a thread after an hardware event is one of the most common tasks
* that an RTOS must be able to perform efficiently. In ChibiOS/RT there are
* several mechanisms that can be used, often each mechanism is best suited
* in a specific scenario.
*
*
Synchronously waking up a specific thread
* A common situation is to have to synchronously wake up a specific thread.
* This can be accomplished without the use of any specific synchronization
* primitive, it uses the very efficient low level scheduler APIs, note that
* you can also optionally send a simple message from the IRQ handler to
* the thread.
* @code
static Thread *tp = NULL;
void mythread(void *p) {
while (TRUE) {
msg_t msg;
// Waiting for the IRQ to happen.
chSysLock();
tp = chThdSelf();
chSchGoSleepS(PRSUSPENDED);
msg = chThdSelf()->p_rdymsg; // Retrieving the message, optional
chSysUnlock();
// Perform processing here.
}
}
CH_IRQ_HANDLER(myIRQ) {
CH_IRQ_PROLOGUE();
// Wakes up the thread.
chSysLockFromIsr();
if (tp != NULL) {
tp->p_rdymsg = (msg_t)55; // Sending the message, optional
chSchReadyI(tp);
tp = NULL;
}
chSysUnlockFromIsr().
CH_IRQ_EPILOGUE();
}
* @endcode
*
* Synchronously waking up one of the waiting threads
* Lets assume you have a queue of waiting threads, you want to wake up
* the threads one by one in FIFO order, if there are no waiting threads
* then nothing happens.
* This can be accomplished using a @p Semaphore object initialized to zero:
* @code
CH_IRQ_HANDLER(myIRQ) {
CH_IRQ_PROLOGUE();
// If there is at least one waiting thread then signal it.
chSysLockFromIsr();
if (chSemGetCounterI(&mysem) < 0)
chSemSignalI(&mysem);
chSysUnlockFromIsr().
CH_IRQ_EPILOGUE();
}
* @endcode
*
* Synchronously waking up all the waiting threads
* In this scenario you want to synchronously wake up all the waiting threads,
* if there are no waiting threads then nothing happens.
* This can be accomplished using a @p Semaphore object initialized to zero:
* @code
CH_IRQ_HANDLER(myIRQ) {
CH_IRQ_PROLOGUE();
// Wakes up all the threads waiting on the semaphore.
chSysLockFromIsr();
chSemResetI(&mysem);
chSysUnlockFromIsr().
CH_IRQ_EPILOGUE();
}
* @endcode
*
* Asynchronously waking up a specific thread
* If you have to asynchronously wake up a specific thread then a simple
* event flags can be used.
* @code
static Thread *tp;
void mythread(void *p) {
tp = chThdSelf();
while (TRUE) {
// Checks if an IRQ happened else wait.
chEvtWaitAny((eventmask_t)1);
// Perform processing here.
}
}
CH_IRQ_HANDLER(myIRQ) {
CH_IRQ_PROLOGUE();
// Wakes up the thread.
chSysLockFromIsr();
chEvtSignalI(tp, (eventmask_t)1);
chSysUnlockFromIsr().
CH_IRQ_EPILOGUE();
}
* @endcode
*
* Asynchronously waking up one or more threads
* By using event sources it is possible to asynchronously wake up one or more
* listener threads. The mechanism requires a single initialized
* @p EventSource object, all the threads registered as listeners on the
* event source will be broadcasted.
* @code
CH_IRQ_HANDLER(myIRQ) {
CH_IRQ_PROLOGUE();
// Pends an event flag on all the listening threads.
chSysLockFromIsr();
chEvtBroadcastI(&my_event_source);
chSysUnlockFromIsr().
CH_IRQ_EPILOGUE();
}
* @endcode
*/