ChibiOS/RT Architecture - Reference Manual - Guides |
00001 /* 00002 ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio. 00003 00004 This file is part of ChibiOS/RT. 00005 00006 ChibiOS/RT is free software; you can redistribute it and/or modify 00007 it under the terms of the GNU General Public License as published by 00008 the Free Software Foundation; either version 3 of the License, or 00009 (at your option) any later version. 00010 00011 ChibiOS/RT is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU General Public License for more details. 00015 00016 You should have received a copy of the GNU General Public License 00017 along with this program. If not, see <http://www.gnu.org/licenses/>. 00018 00019 --- 00020 00021 A special exception to the GPL can be applied should you wish to distribute 00022 a combined work that includes ChibiOS/RT, without being obliged to provide 00023 the source code for any proprietary components. See the file exception.txt 00024 for full details of how and when the exception can be applied. 00025 */ 00026 00027 /** 00028 * @file chschd.c 00029 * @brief Scheduler code. 00030 * 00031 * @addtogroup scheduler 00032 * @details This module provides the default portable scheduler code, 00033 * scheduler functions can be individually captured by the port 00034 * layer in order to provide architecture optimized equivalents. 00035 * When a function is captured its default code is not built into 00036 * the OS image, the optimized version is included instead. 00037 * @{ 00038 */ 00039 00040 #include "ch.h" 00041 00042 /** 00043 * @brief Ready list header. 00044 */ 00045 #if !defined(PORT_OPTIMIZED_RLIST_VAR) || defined(__DOXYGEN__) 00046 ReadyList rlist; 00047 #endif /* !defined(PORT_OPTIMIZED_RLIST_VAR) */ 00048 00049 /** 00050 * @brief Scheduler initialization. 00051 * @note Internally invoked by the @p chSysInit(), not an API. 00052 */ 00053 void scheduler_init(void) { 00054 00055 queue_init(&rlist.r_queue); 00056 rlist.r_prio = NOPRIO; 00057 #if CH_TIME_QUANTUM > 0 00058 rlist.r_preempt = CH_TIME_QUANTUM; 00059 #endif 00060 #if CH_USE_REGISTRY 00061 rlist.r_newer = rlist.r_older = (Thread *)&rlist; 00062 #endif 00063 } 00064 00065 /** 00066 * @brief Inserts a thread in the Ready List. 00067 * @note The function does not reschedule, the @p chSchRescheduleS() should 00068 * be called soon after. 00069 * 00070 * @param[in] tp the Thread to be made ready 00071 * @return The Thread pointer. 00072 */ 00073 #if !defined(PORT_OPTIMIZED_READYI) || defined(__DOXYGEN__) 00074 #if CH_OPTIMIZE_SPEED 00075 /* NOTE: it is inlined in this module only.*/ 00076 INLINE Thread *chSchReadyI(Thread *tp) { 00077 #else 00078 Thread *chSchReadyI(Thread *tp) { 00079 #endif 00080 Thread *cp; 00081 00082 tp->p_state = THD_STATE_READY; 00083 cp = (Thread *)&rlist.r_queue; 00084 do { 00085 cp = cp->p_next; 00086 } while (cp->p_prio >= tp->p_prio); 00087 /* Insertion on p_prev.*/ 00088 tp->p_next = cp; 00089 tp->p_prev = cp->p_prev; 00090 tp->p_prev->p_next = cp->p_prev = tp; 00091 return tp; 00092 } 00093 #endif /* !defined(PORT_OPTIMIZED_READYI) */ 00094 00095 /** 00096 * @brief Puts the current thread to sleep into the specified state. 00097 * @details The thread goes into a sleeping state. The @ref thread_states are 00098 * described into @p threads.h. 00099 * 00100 * @param[in] newstate the new thread state 00101 */ 00102 #if !defined(PORT_OPTIMIZED_GOSLEEPS) || defined(__DOXYGEN__) 00103 void chSchGoSleepS(tstate_t newstate) { 00104 Thread *otp; 00105 00106 (otp = currp)->p_state = newstate; 00107 #if CH_TIME_QUANTUM > 0 00108 rlist.r_preempt = CH_TIME_QUANTUM; 00109 #endif 00110 setcurrp(fifo_remove(&rlist.r_queue)); 00111 currp->p_state = THD_STATE_CURRENT; 00112 chDbgTrace(otp); 00113 chSysSwitchI(currp, otp); 00114 } 00115 #endif /* !defined(PORT_OPTIMIZED_GOSLEEPS) */ 00116 00117 #if !defined(PORT_OPTIMIZED_GOSLEEPTIMEOUTS) || defined(__DOXYGEN__) 00118 /* 00119 * Timeout wakeup callback. 00120 */ 00121 static void wakeup(void *p) { 00122 Thread *tp = (Thread *)p; 00123 00124 switch (tp->p_state) { 00125 case THD_STATE_READY: 00126 /* Handling the special case where the thread has been made ready by 00127 another thread with higher priority.*/ 00128 return; 00129 #if CH_USE_SEMAPHORES || (CH_USE_CONDVARS && CH_USE_CONDVARS_TIMEOUT) 00130 #if CH_USE_SEMAPHORES 00131 case THD_STATE_WTSEM: 00132 chSemFastSignalI((Semaphore *)tp->p_u.wtobjp); 00133 /* Falls into, intentional. */ 00134 #endif 00135 #if CH_USE_CONDVARS && CH_USE_CONDVARS_TIMEOUT 00136 case THD_STATE_WTCOND: 00137 #endif 00138 /* States requiring dequeuing.*/ 00139 dequeue(tp); 00140 #endif 00141 } 00142 tp->p_u.rdymsg = RDY_TIMEOUT; 00143 chSchReadyI(tp); 00144 } 00145 00146 /** 00147 * @brief Puts the current thread to sleep into the specified state with 00148 * timeout specification. 00149 * @details The thread goes into a sleeping state, if it is not awakened 00150 * explicitly within the specified timeout then it is forcibly 00151 * awakened with a @p RDY_TIMEOUT low level message. The @ref 00152 * thread_states are described into @p threads.h. 00153 * 00154 * @param[in] newstate the new thread state 00155 * @param[in] time the number of ticks before the operation timeouts, the 00156 * special values are handled as follow: 00157 * - @a TIME_INFINITE the thread enters an infinite sleep 00158 * state, this is equivalent to invoking 00159 * @p chSchGoSleepS() but, of course, less efficient. 00160 * - @a TIME_IMMEDIATE this value is accepted but 00161 * interpreted as a normal time specification not as an 00162 * immediate timeout specification. 00163 * . 00164 * @return The wakeup message. 00165 * @retval RDY_TIMEOUT if a timeout occurs. 00166 */ 00167 msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time) { 00168 00169 if (TIME_INFINITE != time) { 00170 VirtualTimer vt; 00171 00172 chVTSetI(&vt, time, wakeup, currp); 00173 chSchGoSleepS(newstate); 00174 if (chVTIsArmedI(&vt)) 00175 chVTResetI(&vt); 00176 } 00177 else 00178 chSchGoSleepS(newstate); 00179 return currp->p_u.rdymsg; 00180 } 00181 #endif /* !defined(PORT_OPTIMIZED_GOSLEEPTIMEOUTS) */ 00182 00183 /** 00184 * @brief Wakes up a thread. 00185 * @details The thread is inserted into the ready list or immediately made 00186 * running depending on its relative priority compared to the current 00187 * thread. 00188 * @note It is equivalent to a @p chSchReadyI() followed by a 00189 * @p chSchRescheduleS() but much more efficient. 00190 * @note The function assumes that the current thread has the highest 00191 * priority. 00192 * 00193 * @param[in] ntp the Thread to be made ready 00194 * @param[in] msg message to the awakened thread 00195 */ 00196 #if !defined(PORT_OPTIMIZED_WAKEUPS) || defined(__DOXYGEN__) 00197 void chSchWakeupS(Thread *ntp, msg_t msg) { 00198 00199 ntp->p_u.rdymsg = msg; 00200 /* If the waken thread has a not-greater priority than the current 00201 one then it is just inserted in the ready list else it made 00202 running immediately and the invoking thread goes in the ready 00203 list instead.*/ 00204 if (ntp->p_prio <= currp->p_prio) 00205 chSchReadyI(ntp); 00206 else { 00207 Thread *otp = chSchReadyI(currp); 00208 #if CH_TIME_QUANTUM > 0 00209 rlist.r_preempt = CH_TIME_QUANTUM; 00210 #endif 00211 setcurrp(ntp); 00212 ntp->p_state = THD_STATE_CURRENT; 00213 chDbgTrace(otp); 00214 chSysSwitchI(ntp, otp); 00215 } 00216 } 00217 #endif /* !defined(PORT_OPTIMIZED_WAKEUPS) */ 00218 00219 /** 00220 * @brief Switches to the first thread on the runnable queue. 00221 * @note It is intended to be called if @p chSchRescRequiredI() evaluates 00222 * to @p TRUE. 00223 */ 00224 #if !defined(PORT_OPTIMIZED_DORESCHEDULEI) || defined(__DOXYGEN__) 00225 void chSchDoRescheduleI(void) { 00226 Thread *otp; 00227 00228 #if CH_TIME_QUANTUM > 0 00229 rlist.r_preempt = CH_TIME_QUANTUM; 00230 #endif 00231 otp = currp; 00232 /* Picks the first thread from the ready queue and makes it current.*/ 00233 setcurrp(fifo_remove(&rlist.r_queue)); 00234 currp->p_state = THD_STATE_CURRENT; 00235 chSchReadyI(otp); 00236 chDbgTrace(otp); 00237 chSysSwitchI(currp, otp); 00238 } 00239 #endif /* !defined(PORT_OPTIMIZED_DORESCHEDULEI) */ 00240 00241 /** 00242 * @brief Performs a reschedule if a higher priority thread is runnable. 00243 * @details If a thread with a higher priority than the current thread is in 00244 * the ready list then make the higher priority thread running. 00245 */ 00246 #if !defined(PORT_OPTIMIZED_RESCHEDULES) || defined(__DOXYGEN__) 00247 void chSchRescheduleS(void) { 00248 00249 if (chSchIsRescRequiredI()) 00250 chSchDoRescheduleI(); 00251 } 00252 #endif /* !defined(PORT_OPTIMIZED_RESCHEDULES) */ 00253 00254 /** 00255 * @brief Evaluates if a reschedule is required. 00256 * @details The decision is taken by comparing the relative priorities and 00257 * depending on the state of the round robin timeout counter. 00258 * @note This function is meant to be used in the timer interrupt handler 00259 * where @p chVTDoTickI() is invoked. 00260 * 00261 * @retval TRUE if there is a thread that should go in running state. 00262 * @retval FALSE if a reschedule is not required. 00263 */ 00264 #if !defined(PORT_OPTIMIZED_ISRESCHREQUIREDEXI) || defined(__DOXYGEN__) 00265 bool_t chSchIsRescRequiredExI(void) { 00266 tprio_t p1 = firstprio(&rlist.r_queue); 00267 tprio_t p2 = currp->p_prio; 00268 #if CH_TIME_QUANTUM > 0 00269 /* If the running thread has not reached its time quantum, reschedule only 00270 if the first thread on the ready queue has a higher priority. 00271 Otherwise, if the running thread has used up its time quantum, reschedule 00272 if the first thread on the ready queue has equal or higher priority.*/ 00273 return rlist.r_preempt ? p1 > p2 : p1 >= p2; 00274 #else 00275 /* If the round robin preemption feature is not enabled then performs a 00276 simpler comparison.*/ 00277 return p1 > p2; 00278 #endif 00279 } 00280 #endif /* !defined(PORT_OPTIMIZED_ISRESCHREQUIREDEXI) */ 00281 00282 /** @} */