/* 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 . */ /** * @addtogroup Scheduler * @{ */ #include /** @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 * @param msg message to the awakened thread * @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 void chSchReadyI(Thread *tp, t_msg msg) { #else void chSchReadyI(Thread *tp, t_msg msg) { #endif Thread *cp = rlist.r_queue.p_next; tp->p_state = PRREADY; tp->p_rdymsg = msg; 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; } /** * 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 * @return the wakeup message * @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(t_tstate 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 static void wakeup(void *p) { if (((Thread *)p)->p_state == PRWTSEM) chSemFastSignalI(((Thread *)p)->p_wtsemp); chSchReadyI(p, 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. */ t_msg chSchGoSleepTimeoutS(t_tstate newstate, t_time 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, t_msg msg) { if (ntp->p_prio <= currp->p_prio) chSchReadyI(ntp, msg); else { Thread *otp = currp; chSchReadyI(otp, RDY_OK); (currp = ntp)->p_state = PRCURR; ntp->p_rdymsg = msg; 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, RDY_OK); (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 (isempty(&rlist.r_queue) || firstprio(&rlist.r_queue) <= currp->p_prio) return; 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. */ t_bool chSchRescRequiredI(void) { if (isempty(&rlist.r_queue)) return FALSE; if (rlist.r_preempt) { if (firstprio(&rlist.r_queue) <= currp->p_prio) return FALSE; } else { /* Time quantum elapsed. */ if (firstprio(&rlist.r_queue) < currp->p_prio) return FALSE; } return TRUE; } /** @} */