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 chevents.c 00029 * @brief Events code. 00030 * 00031 * @addtogroup events 00032 * @details Event Flags, Event Sources and Event Listeners. 00033 * <h2>Operation mode</h2> 00034 * Each thread has a mask of pending event flags inside its @p Thread 00035 * structure. 00036 * Operations defined for event flags: 00037 * - <b>Wait</b>, the invoking thread goes to sleep until a certain 00038 * AND/OR combination of event flags becomes pending. 00039 * - <b>Clear</b>, a mask of event flags is cleared from the pending 00040 * events mask, the cleared event flags mask is returned (only the 00041 * flags that were actually pending and then cleared). 00042 * - <b>Signal</b>, an event mask is directly ORed to the mask of the 00043 * signaled thread. 00044 * - <b>Broadcast</b>, each thread registered on an Event Source is 00045 * signaled with the event flags specified in its Event Listener. 00046 * - <b>Dispatch</b>, an events mask is scanned and for each bit set 00047 * to one an associated handler function is invoked. Bit masks are 00048 * scanned from bit zero upward. 00049 * . 00050 * An Event Source is a special object that can be "broadcasted" by 00051 * a thread or an interrupt service routine. Broadcasting an Event 00052 * Source has the effect that all the threads registered on the 00053 * Event Source will be signaled with an events mask.<br> 00054 * An unlimited number of Event Sources can exists in a system and 00055 * each thread can be listening on an unlimited number of 00056 * them.<br><br> 00057 * In order to use the Events APIs the @p CH_USE_EVENTS option must be 00058 * enabled in @p chconf.h. 00059 * @{ 00060 */ 00061 00062 #include "ch.h" 00063 00064 #if CH_USE_EVENTS 00065 /** 00066 * @brief Registers an Event Listener on an Event Source. 00067 * @note Multiple Event Listeners can specify the same bits to be pended. 00068 * 00069 * @param[in] esp pointer to the @p EventSource structure 00070 * @param[in] elp pointer to the @p EventListener structure 00071 * @param[in] mask the mask of event flags to be pended to the thread when 00072 * the event source is broadcasted 00073 */ 00074 void chEvtRegisterMask(EventSource *esp, EventListener *elp, eventmask_t mask) { 00075 00076 chDbgCheck((esp != NULL) && (elp != NULL), "chEvtRegisterMask"); 00077 00078 chSysLock(); 00079 elp->el_next = esp->es_next; 00080 esp->es_next = elp; 00081 elp->el_listener = currp; 00082 elp->el_mask = mask; 00083 chSysUnlock(); 00084 } 00085 00086 /** 00087 * @brief Unregisters an Event Listener from its Event Source. 00088 * @note If the event listener is not registered on the specified event 00089 * source then the function does nothing. 00090 * @note For optimal performance it is better to perform the unregister 00091 * operations in inverse order of the register operations (elements 00092 * are found on top of the list). 00093 * 00094 * @param[in] esp pointer to the @p EventSource structure 00095 * @param[in] elp pointer to the @p EventListener structure 00096 */ 00097 void chEvtUnregister(EventSource *esp, EventListener *elp) { 00098 EventListener *p; 00099 00100 chDbgCheck((esp != NULL) && (elp != NULL), "chEvtUnregister"); 00101 00102 p = (EventListener *)esp; 00103 chSysLock(); 00104 while (p->el_next != (EventListener *)esp) { 00105 if (p->el_next == elp) { 00106 p->el_next = elp->el_next; 00107 break; 00108 } 00109 p = p->el_next; 00110 } 00111 chSysUnlock(); 00112 } 00113 00114 /** 00115 * @brief Clears the pending events specified in the mask. 00116 * 00117 * @param[in] mask the events to be cleared 00118 * @return The pending events that were cleared. 00119 */ 00120 eventmask_t chEvtClear(eventmask_t mask) { 00121 eventmask_t m; 00122 00123 chSysLock(); 00124 00125 m = currp->p_epending & mask; 00126 currp->p_epending &= ~mask; 00127 00128 chSysUnlock(); 00129 return m; 00130 } 00131 00132 /** 00133 * @brief Pends a set of event flags on the current thread, this is @b much 00134 * faster than using @p chEvtBroadcast() or @p chEvtSignal(). 00135 * 00136 * @param[in] mask the events to be pended 00137 * @return The current pending events mask. 00138 */ 00139 eventmask_t chEvtPend(eventmask_t mask) { 00140 00141 chSysLock(); 00142 00143 mask = (currp->p_epending |= mask); 00144 00145 chSysUnlock(); 00146 return mask; 00147 } 00148 00149 /** 00150 * @brief Pends a set of event flags on the specified @p Thread. 00151 * 00152 * @param[in] tp the thread to be signaled 00153 * @param[in] mask the event flags set to be pended 00154 */ 00155 void chEvtSignal(Thread *tp, eventmask_t mask) { 00156 00157 chDbgCheck(tp != NULL, "chEvtSignal"); 00158 00159 chSysLock(); 00160 chEvtSignalI(tp, mask); 00161 chSchRescheduleS(); 00162 chSysUnlock(); 00163 } 00164 00165 /** 00166 * @brief Pends a set of event flags on the specified @p Thread. 00167 * 00168 * @param[in] tp the thread to be signaled 00169 * @param[in] mask the event flags set to be pended 00170 */ 00171 void chEvtSignalI(Thread *tp, eventmask_t mask) { 00172 00173 chDbgCheck(tp != NULL, "chEvtSignalI"); 00174 00175 tp->p_epending |= mask; 00176 /* Test on the AND/OR conditions wait states.*/ 00177 if (((tp->p_state == THD_STATE_WTOREVT) && 00178 ((tp->p_epending & tp->p_u.ewmask) != 0)) || 00179 ((tp->p_state == THD_STATE_WTANDEVT) && 00180 ((tp->p_epending & tp->p_u.ewmask) == tp->p_u.ewmask))) 00181 chSchReadyI(tp)->p_u.rdymsg = RDY_OK; 00182 } 00183 00184 /** 00185 * @brief Signals all the Event Listeners registered on the specified Event 00186 * Source. 00187 * 00188 * @param[in] esp pointer to the @p EventSource structure 00189 */ 00190 void chEvtBroadcast(EventSource *esp) { 00191 00192 chSysLock(); 00193 chEvtBroadcastI(esp); 00194 chSchRescheduleS(); 00195 chSysUnlock(); 00196 } 00197 00198 /** 00199 * @brief Signals all the Event Listeners registered on the specified Event 00200 * Source. 00201 * 00202 * @param[in] esp pointer to the @p EventSource structure 00203 */ 00204 void chEvtBroadcastI(EventSource *esp) { 00205 EventListener *elp; 00206 00207 chDbgCheck(esp != NULL, "chEvtBroadcastI"); 00208 00209 elp = esp->es_next; 00210 while (elp != (EventListener *)esp) { 00211 chEvtSignalI(elp->el_listener, elp->el_mask); 00212 elp = elp->el_next; 00213 } 00214 } 00215 00216 /** 00217 * @brief Invokes the event handlers associated to an event flags mask. 00218 * 00219 * @param[in] mask mask of the events to be dispatched 00220 * @param[in] handlers an array of @p evhandler_t. The array must have size 00221 * equal to the number of bits in eventmask_t. 00222 */ 00223 void chEvtDispatch(const evhandler_t *handlers, eventmask_t mask) { 00224 eventid_t eid; 00225 00226 chDbgCheck(handlers != NULL, "chEvtDispatch"); 00227 00228 eid = 0; 00229 while (mask) { 00230 if (mask & EVENT_MASK(eid)) { 00231 chDbgAssert(handlers[eid] != NULL, 00232 "chEvtDispatch(), #1", 00233 "null handler"); 00234 mask &= ~EVENT_MASK(eid); 00235 handlers[eid](eid); 00236 } 00237 eid++; 00238 } 00239 } 00240 00241 #if CH_OPTIMIZE_SPEED || !CH_USE_EVENTS_TIMEOUT || defined(__DOXYGEN__) 00242 /** 00243 * @brief Waits for exactly one of the specified events. 00244 * @details The function waits for one event among those specified in 00245 * @p mask to become pending then the event is cleared and returned. 00246 * @note One and only one event is served in the function, the one with the 00247 * lowest event id. The function is meant to be invoked into a loop in 00248 * order to serve all the pending events.<br> 00249 * This means that Event Listeners with a lower event identifier have 00250 * an higher priority. 00251 * 00252 * @param[in] mask mask of the events that the function should wait for, 00253 * @p ALL_EVENTS enables all the events 00254 * @return The mask of the lowest id served and cleared event. 00255 */ 00256 eventmask_t chEvtWaitOne(eventmask_t mask) { 00257 Thread *ctp = currp; 00258 eventmask_t m; 00259 00260 chSysLock(); 00261 00262 if ((m = (ctp->p_epending & mask)) == 0) { 00263 ctp->p_u.ewmask = mask; 00264 chSchGoSleepS(THD_STATE_WTOREVT); 00265 m = ctp->p_epending & mask; 00266 } 00267 m &= -m; 00268 ctp->p_epending &= ~m; 00269 00270 chSysUnlock(); 00271 return m; 00272 } 00273 00274 /** 00275 * @brief Waits for any of the specified events. 00276 * @details The function waits for any event among those specified in 00277 * @p mask to become pending then the events are cleared and returned. 00278 * 00279 * @param[in] mask mask of the events that the function should wait for, 00280 * @p ALL_EVENTS enables all the events 00281 * @return The mask of the served and cleared events. 00282 */ 00283 eventmask_t chEvtWaitAny(eventmask_t mask) { 00284 Thread *ctp = currp; 00285 eventmask_t m; 00286 00287 chSysLock(); 00288 00289 if ((m = (ctp->p_epending & mask)) == 0) { 00290 ctp->p_u.ewmask = mask; 00291 chSchGoSleepS(THD_STATE_WTOREVT); 00292 m = ctp->p_epending & mask; 00293 } 00294 ctp->p_epending &= ~m; 00295 00296 chSysUnlock(); 00297 return m; 00298 } 00299 00300 /** 00301 * @brief Waits for all the specified events. 00302 * @details The function waits for all the events specified in @p mask to 00303 * become pending then the events are cleared and returned. 00304 * 00305 * @param[in] mask mask of the event ids that the function should wait for 00306 * @return The mask of the served and cleared events. 00307 */ 00308 eventmask_t chEvtWaitAll(eventmask_t mask) { 00309 Thread *ctp = currp; 00310 00311 chSysLock(); 00312 00313 if ((ctp->p_epending & mask) != mask) { 00314 ctp->p_u.ewmask = mask; 00315 chSchGoSleepS(THD_STATE_WTANDEVT); 00316 } 00317 ctp->p_epending &= ~mask; 00318 00319 chSysUnlock(); 00320 return mask; 00321 } 00322 #endif /* CH_OPTIMIZE_SPEED || !CH_USE_EVENTS_TIMEOUT */ 00323 00324 #if CH_USE_EVENTS_TIMEOUT 00325 /** 00326 * @brief Waits for exactly one of the specified events. 00327 * @details The function waits for one event among those specified in 00328 * @p mask to become pending then the event is cleared and returned. 00329 * @note One and only one event is served in the function, the one with the 00330 * lowest event id. The function is meant to be invoked into a loop in 00331 * order to serve all the pending events.<br> 00332 * This means that Event Listeners with a lower event identifier have 00333 * an higher priority. 00334 * 00335 * @param[in] mask mask of the events that the function should wait for, 00336 * @p ALL_EVENTS enables all the events 00337 * @param[in] time the number of ticks before the operation timeouts, 00338 * the following special values are allowed: 00339 * - @a TIME_IMMEDIATE immediate timeout. 00340 * - @a TIME_INFINITE no timeout. 00341 * . 00342 * @return The mask of the lowest id served and cleared event. 00343 * @retval 0 if the specified timeout expired. 00344 */ 00345 eventmask_t chEvtWaitOneTimeout(eventmask_t mask, systime_t time) { 00346 Thread *ctp = currp; 00347 eventmask_t m; 00348 00349 chSysLock(); 00350 00351 if ((m = (ctp->p_epending & mask)) == 0) { 00352 if (TIME_IMMEDIATE == time) { 00353 chSysUnlock(); 00354 return (eventmask_t)0; 00355 } 00356 ctp->p_u.ewmask = mask; 00357 if (chSchGoSleepTimeoutS(THD_STATE_WTOREVT, time) < RDY_OK) { 00358 chSysUnlock(); 00359 return (eventmask_t)0; 00360 } 00361 m = ctp->p_epending & mask; 00362 } 00363 m &= -m; 00364 ctp->p_epending &= ~m; 00365 00366 chSysUnlock(); 00367 return m; 00368 } 00369 00370 /** 00371 * @brief Waits for any of the specified events. 00372 * @details The function waits for any event among those specified in 00373 * @p mask to become pending then the events are cleared and 00374 * returned. 00375 * 00376 * @param[in] mask mask of the events that the function should wait for, 00377 * @p ALL_EVENTS enables all the events 00378 * @param[in] time the number of ticks before the operation timeouts, 00379 * the following special values are allowed: 00380 * - @a TIME_IMMEDIATE immediate timeout. 00381 * - @a TIME_INFINITE no timeout. 00382 * . 00383 * @return The mask of the served and cleared events. 00384 * @retval 0 if the specified timeout expired. 00385 */ 00386 eventmask_t chEvtWaitAnyTimeout(eventmask_t mask, systime_t time) { 00387 Thread *ctp = currp; 00388 eventmask_t m; 00389 00390 chSysLock(); 00391 00392 if ((m = (ctp->p_epending & mask)) == 0) { 00393 if (TIME_IMMEDIATE == time) { 00394 chSysUnlock(); 00395 return (eventmask_t)0; 00396 } 00397 ctp->p_u.ewmask = mask; 00398 if (chSchGoSleepTimeoutS(THD_STATE_WTOREVT, time) < RDY_OK) { 00399 chSysUnlock(); 00400 return (eventmask_t)0; 00401 } 00402 m = ctp->p_epending & mask; 00403 } 00404 ctp->p_epending &= ~m; 00405 00406 chSysUnlock(); 00407 return m; 00408 } 00409 00410 /** 00411 * @brief Waits for all the specified events. 00412 * @details The function waits for all the events specified in @p mask to 00413 * become pending then the events are cleared and returned. 00414 * 00415 * @param[in] mask mask of the event ids that the function should wait for 00416 * @param[in] time the number of ticks before the operation timeouts, 00417 * the following special values are allowed: 00418 * - @a TIME_IMMEDIATE immediate timeout. 00419 * - @a TIME_INFINITE no timeout. 00420 * . 00421 * @return The mask of the served and cleared events. 00422 * @retval 0 if the specified timeout expired. 00423 */ 00424 eventmask_t chEvtWaitAllTimeout(eventmask_t mask, systime_t time) { 00425 Thread *ctp = currp; 00426 00427 chSysLock(); 00428 00429 if ((ctp->p_epending & mask) != mask) { 00430 if (TIME_IMMEDIATE == time) { 00431 chSysUnlock(); 00432 return (eventmask_t)0; 00433 } 00434 ctp->p_u.ewmask = mask; 00435 if (chSchGoSleepTimeoutS(THD_STATE_WTANDEVT, time) < RDY_OK) { 00436 chSysUnlock(); 00437 return (eventmask_t)0; 00438 } 00439 } 00440 ctp->p_epending &= ~mask; 00441 00442 chSysUnlock(); 00443 return mask; 00444 } 00445 #endif /* CH_USE_EVENTS_TIMEOUT */ 00446 00447 #endif /* CH_USE_EVENTS */ 00448 00449 /** @} */