/* 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 */