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