|
ChibiOS/RT
2.5.1 |
00001 /* 00002 ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, 00003 2011,2012 Giovanni Di Sirio. 00004 00005 This file is part of ChibiOS/RT. 00006 00007 ChibiOS/RT is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 3 of the License, or 00010 (at your option) any later version. 00011 00012 ChibiOS/RT is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program. If not, see <http://www.gnu.org/licenses/>. 00019 */ 00020 /* 00021 Concepts and parts of this file have been contributed by Scott (skute). 00022 */ 00023 00024 /** 00025 * @file chevents.c 00026 * @brief Events code. 00027 * 00028 * @addtogroup events 00029 * @details Event Flags, Event Sources and Event Listeners. 00030 * <h2>Operation mode</h2> 00031 * Each thread has a mask of pending event flags inside its @p Thread 00032 * structure. 00033 * Operations defined for event flags: 00034 * - <b>Wait</b>, the invoking thread goes to sleep until a certain 00035 * AND/OR combination of event flags becomes pending. 00036 * - <b>Clear</b>, a mask of event flags is cleared from the pending 00037 * events mask, the cleared event flags mask is returned (only the 00038 * flags that were actually pending and then cleared). 00039 * - <b>Signal</b>, an event mask is directly ORed to the mask of the 00040 * signaled thread. 00041 * - <b>Broadcast</b>, each thread registered on an Event Source is 00042 * signaled with the event flags specified in its Event Listener. 00043 * - <b>Dispatch</b>, an events mask is scanned and for each bit set 00044 * to one an associated handler function is invoked. Bit masks are 00045 * scanned from bit zero upward. 00046 * . 00047 * An Event Source is a special object that can be "broadcasted" by 00048 * a thread or an interrupt service routine. Broadcasting an Event 00049 * Source has the effect that all the threads registered on the 00050 * Event Source will be signaled with an events mask.<br> 00051 * An unlimited number of Event Sources can exists in a system and 00052 * each thread can be listening on an unlimited number of 00053 * them. 00054 * @pre In order to use the Events APIs the @p CH_USE_EVENTS option must be 00055 * enabled in @p chconf.h. 00056 * @post Enabling events requires 1-4 (depending on the architecture) 00057 * extra bytes in the @p Thread structure. 00058 * @{ 00059 */ 00060 00061 #include "ch.h" 00062 00063 #if CH_USE_EVENTS || defined(__DOXYGEN__) 00064 /** 00065 * @brief Registers an Event Listener on an Event Source. 00066 * @details Once a thread has registered as listener on an event source it 00067 * will be notified of all events broadcasted there. 00068 * @note Multiple Event Listeners can specify the same bits to be ORed to 00069 * different threads. 00070 * 00071 * @param[in] esp pointer to the @p EventSource structure 00072 * @param[in] elp pointer to the @p EventListener structure 00073 * @param[in] mask the mask of event flags to be ORed to the thread when 00074 * the event source is broadcasted 00075 * 00076 * @api 00077 */ 00078 void chEvtRegisterMask(EventSource *esp, EventListener *elp, eventmask_t mask) { 00079 00080 chDbgCheck((esp != NULL) && (elp != NULL), "chEvtRegisterMask"); 00081 00082 chSysLock(); 00083 elp->el_next = esp->es_next; 00084 esp->es_next = elp; 00085 elp->el_listener = currp; 00086 elp->el_mask = mask; 00087 elp->el_flags = 0; 00088 chSysUnlock(); 00089 } 00090 00091 /** 00092 * @brief Unregisters an Event Listener from its Event Source. 00093 * @note If the event listener is not registered on the specified event 00094 * source then the function does nothing. 00095 * @note For optimal performance it is better to perform the unregister 00096 * operations in inverse order of the register operations (elements 00097 * are found on top of the list). 00098 * 00099 * @param[in] esp pointer to the @p EventSource structure 00100 * @param[in] elp pointer to the @p EventListener structure 00101 * 00102 * @api 00103 */ 00104 void chEvtUnregister(EventSource *esp, EventListener *elp) { 00105 EventListener *p; 00106 00107 chDbgCheck((esp != NULL) && (elp != NULL), "chEvtUnregister"); 00108 00109 p = (EventListener *)esp; 00110 chSysLock(); 00111 while (p->el_next != (EventListener *)esp) { 00112 if (p->el_next == elp) { 00113 p->el_next = elp->el_next; 00114 break; 00115 } 00116 p = p->el_next; 00117 } 00118 chSysUnlock(); 00119 } 00120 00121 /** 00122 * @brief Clears the pending events specified in the mask. 00123 * 00124 * @param[in] mask the events to be cleared 00125 * @return The pending events that were cleared. 00126 * 00127 * @api 00128 */ 00129 eventmask_t chEvtGetAndClearEvents(eventmask_t mask) { 00130 eventmask_t m; 00131 00132 chSysLock(); 00133 00134 m = currp->p_epending & mask; 00135 currp->p_epending &= ~mask; 00136 00137 chSysUnlock(); 00138 return m; 00139 } 00140 00141 /** 00142 * @brief Adds (OR) a set of event flags on the current thread, this is 00143 * @b much faster than using @p chEvtBroadcast() or @p chEvtSignal(). 00144 * 00145 * @param[in] mask the event flags to be ORed 00146 * @return The current pending events mask. 00147 * 00148 * @api 00149 */ 00150 eventmask_t chEvtAddEvents(eventmask_t mask) { 00151 00152 chSysLock(); 00153 00154 mask = (currp->p_epending |= mask); 00155 00156 chSysUnlock(); 00157 return mask; 00158 } 00159 00160 /** 00161 * @brief Signals all the Event Listeners registered on the specified Event 00162 * Source. 00163 * @details This function variants ORs the specified event flags to all the 00164 * threads registered on the @p EventSource in addition to the event 00165 * flags specified by the threads themselves in the 00166 * @p EventListener objects. 00167 * @post This function does not reschedule so a call to a rescheduling 00168 * function must be performed before unlocking the kernel. Note that 00169 * interrupt handlers always reschedule on exit so an explicit 00170 * reschedule must not be performed in ISRs. 00171 * 00172 * @param[in] esp pointer to the @p EventSource structure 00173 * @param[in] flags the flags set to be added to the listener flags mask 00174 * 00175 * @iclass 00176 */ 00177 void chEvtBroadcastFlagsI(EventSource *esp, flagsmask_t flags) { 00178 EventListener *elp; 00179 00180 chDbgCheckClassI(); 00181 chDbgCheck(esp != NULL, "chEvtBroadcastMaskI"); 00182 00183 elp = esp->es_next; 00184 while (elp != (EventListener *)esp) { 00185 elp->el_flags |= flags; 00186 chEvtSignalI(elp->el_listener, elp->el_mask); 00187 elp = elp->el_next; 00188 } 00189 } 00190 00191 /** 00192 * @brief Returns the flags associated to an @p EventListener. 00193 * @details The flags are returned and the @p EventListener flags mask is 00194 * cleared. 00195 * 00196 * @param[in] elp pointer to the @p EventListener structure 00197 * @return The flags added to the listener by the associated 00198 * event source. 00199 * 00200 * @iclass 00201 */ 00202 flagsmask_t chEvtGetAndClearFlags(EventListener *elp) { 00203 flagsmask_t flags; 00204 00205 chSysLock(); 00206 00207 flags = elp->el_flags; 00208 elp->el_flags = 0; 00209 00210 chSysUnlock(); 00211 return flags; 00212 } 00213 00214 /** 00215 * @brief Adds a set of event flags directly to specified @p Thread. 00216 * 00217 * @param[in] tp the thread to be signaled 00218 * @param[in] mask the event flags set to be ORed 00219 * 00220 * @api 00221 */ 00222 void chEvtSignal(Thread *tp, eventmask_t mask) { 00223 00224 chDbgCheck(tp != NULL, "chEvtSignal"); 00225 00226 chSysLock(); 00227 chEvtSignalI(tp, mask); 00228 chSchRescheduleS(); 00229 chSysUnlock(); 00230 } 00231 00232 /** 00233 * @brief Adds a set of event flags directly to specified @p Thread. 00234 * @post This function does not reschedule so a call to a rescheduling 00235 * function must be performed before unlocking the kernel. Note that 00236 * interrupt handlers always reschedule on exit so an explicit 00237 * reschedule must not be performed in ISRs. 00238 * 00239 * @param[in] tp the thread to be signaled 00240 * @param[in] mask the event flags set to be ORed 00241 * 00242 * @iclass 00243 */ 00244 void chEvtSignalI(Thread *tp, eventmask_t mask) { 00245 00246 chDbgCheckClassI(); 00247 chDbgCheck(tp != NULL, "chEvtSignalI"); 00248 00249 tp->p_epending |= mask; 00250 /* Test on the AND/OR conditions wait states.*/ 00251 if (((tp->p_state == THD_STATE_WTOREVT) && 00252 ((tp->p_epending & tp->p_u.ewmask) != 0)) || 00253 ((tp->p_state == THD_STATE_WTANDEVT) && 00254 ((tp->p_epending & tp->p_u.ewmask) == tp->p_u.ewmask))) 00255 chSchReadyI(tp)->p_u.rdymsg = RDY_OK; 00256 } 00257 00258 /** 00259 * @brief Signals all the Event Listeners registered on the specified Event 00260 * Source. 00261 * @details This function variants ORs the specified event flags to all the 00262 * threads registered on the @p EventSource in addition to the event 00263 * flags specified by the threads themselves in the 00264 * @p EventListener objects. 00265 * 00266 * @param[in] esp pointer to the @p EventSource structure 00267 * @param[in] flags the flags set to be added to the listener flags mask 00268 * 00269 * @api 00270 */ 00271 void chEvtBroadcastFlags(EventSource *esp, flagsmask_t flags) { 00272 00273 chSysLock(); 00274 chEvtBroadcastFlagsI(esp, flags); 00275 chSchRescheduleS(); 00276 chSysUnlock(); 00277 } 00278 00279 /** 00280 * @brief Returns the flags associated to an @p EventListener. 00281 * @details The flags are returned and the @p EventListener flags mask is 00282 * cleared. 00283 * 00284 * @param[in] elp pointer to the @p EventListener structure 00285 * @return The flags added to the listener by the associated 00286 * event source. 00287 * 00288 * @iclass 00289 */ 00290 flagsmask_t chEvtGetAndClearFlagsI(EventListener *elp) { 00291 flagsmask_t flags; 00292 00293 flags = elp->el_flags; 00294 elp->el_flags = 0; 00295 00296 return flags; 00297 } 00298 00299 /** 00300 * @brief Invokes the event handlers associated to an event flags mask. 00301 * 00302 * @param[in] mask mask of the event flags to be dispatched 00303 * @param[in] handlers an array of @p evhandler_t. The array must have size 00304 * equal to the number of bits in eventmask_t. 00305 * 00306 * @api 00307 */ 00308 void chEvtDispatch(const evhandler_t *handlers, eventmask_t mask) { 00309 eventid_t eid; 00310 00311 chDbgCheck(handlers != NULL, "chEvtDispatch"); 00312 00313 eid = 0; 00314 while (mask) { 00315 if (mask & EVENT_MASK(eid)) { 00316 chDbgAssert(handlers[eid] != NULL, 00317 "chEvtDispatch(), #1", 00318 "null handler"); 00319 mask &= ~EVENT_MASK(eid); 00320 handlers[eid](eid); 00321 } 00322 eid++; 00323 } 00324 } 00325 00326 #if CH_OPTIMIZE_SPEED || !CH_USE_EVENTS_TIMEOUT || defined(__DOXYGEN__) 00327 /** 00328 * @brief Waits for exactly one of the specified events. 00329 * @details The function waits for one event among those specified in 00330 * @p mask to become pending then the event is cleared and returned. 00331 * @note One and only one event is served in the function, the one with the 00332 * lowest event id. The function is meant to be invoked into a loop in 00333 * order to serve all the pending events.<br> 00334 * This means that Event Listeners with a lower event identifier have 00335 * an higher priority. 00336 * 00337 * @param[in] mask mask of the event flags that the function should wait 00338 * for, @p ALL_EVENTS enables all the events 00339 * @return The mask of the lowest id served and cleared event. 00340 * 00341 * @api 00342 */ 00343 eventmask_t chEvtWaitOne(eventmask_t mask) { 00344 Thread *ctp = currp; 00345 eventmask_t m; 00346 00347 chSysLock(); 00348 00349 if ((m = (ctp->p_epending & mask)) == 0) { 00350 ctp->p_u.ewmask = mask; 00351 chSchGoSleepS(THD_STATE_WTOREVT); 00352 m = ctp->p_epending & mask; 00353 } 00354 m &= -m; 00355 ctp->p_epending &= ~m; 00356 00357 chSysUnlock(); 00358 return m; 00359 } 00360 00361 /** 00362 * @brief Waits for any of the specified events. 00363 * @details The function waits for any event among those specified in 00364 * @p mask to become pending then the events are cleared and returned. 00365 * 00366 * @param[in] mask mask of the event flags that the function should wait 00367 * for, @p ALL_EVENTS enables all the events 00368 * @return The mask of the served and cleared events. 00369 * 00370 * @api 00371 */ 00372 eventmask_t chEvtWaitAny(eventmask_t mask) { 00373 Thread *ctp = currp; 00374 eventmask_t m; 00375 00376 chSysLock(); 00377 00378 if ((m = (ctp->p_epending & mask)) == 0) { 00379 ctp->p_u.ewmask = mask; 00380 chSchGoSleepS(THD_STATE_WTOREVT); 00381 m = ctp->p_epending & mask; 00382 } 00383 ctp->p_epending &= ~m; 00384 00385 chSysUnlock(); 00386 return m; 00387 } 00388 00389 /** 00390 * @brief Waits for all the specified events. 00391 * @details The function waits for all the events specified in @p mask to 00392 * become pending then the events are cleared and returned. 00393 * 00394 * @param[in] mask mask of the event flags that the function should wait 00395 * for, @p ALL_EVENTS requires all the events 00396 * @return The mask of the served and cleared events. 00397 * 00398 * @api 00399 */ 00400 eventmask_t chEvtWaitAll(eventmask_t mask) { 00401 Thread *ctp = currp; 00402 00403 chSysLock(); 00404 00405 if ((ctp->p_epending & mask) != mask) { 00406 ctp->p_u.ewmask = mask; 00407 chSchGoSleepS(THD_STATE_WTANDEVT); 00408 } 00409 ctp->p_epending &= ~mask; 00410 00411 chSysUnlock(); 00412 return mask; 00413 } 00414 #endif /* CH_OPTIMIZE_SPEED || !CH_USE_EVENTS_TIMEOUT */ 00415 00416 #if CH_USE_EVENTS_TIMEOUT || defined(__DOXYGEN__) 00417 /** 00418 * @brief Waits for exactly one of the specified events. 00419 * @details The function waits for one event among those specified in 00420 * @p mask to become pending then the event is cleared and returned. 00421 * @note One and only one event is served in the function, the one with the 00422 * lowest event id. The function is meant to be invoked into a loop in 00423 * order to serve all the pending events.<br> 00424 * This means that Event Listeners with a lower event identifier have 00425 * an higher priority. 00426 * 00427 * @param[in] mask mask of the event flags that the function should wait 00428 * for, @p ALL_EVENTS enables all the events 00429 * @param[in] time the number of ticks before the operation timeouts, 00430 * the following special values are allowed: 00431 * - @a TIME_IMMEDIATE immediate timeout. 00432 * - @a TIME_INFINITE no timeout. 00433 * . 00434 * @return The mask of the lowest id served and cleared event. 00435 * @retval 0 if the operation has timed out. 00436 * 00437 * @api 00438 */ 00439 eventmask_t chEvtWaitOneTimeout(eventmask_t mask, systime_t time) { 00440 Thread *ctp = currp; 00441 eventmask_t m; 00442 00443 chSysLock(); 00444 00445 if ((m = (ctp->p_epending & mask)) == 0) { 00446 if (TIME_IMMEDIATE == time) { 00447 chSysUnlock(); 00448 return (eventmask_t)0; 00449 } 00450 ctp->p_u.ewmask = mask; 00451 if (chSchGoSleepTimeoutS(THD_STATE_WTOREVT, time) < RDY_OK) { 00452 chSysUnlock(); 00453 return (eventmask_t)0; 00454 } 00455 m = ctp->p_epending & mask; 00456 } 00457 m &= -m; 00458 ctp->p_epending &= ~m; 00459 00460 chSysUnlock(); 00461 return m; 00462 } 00463 00464 /** 00465 * @brief Waits for any of the specified events. 00466 * @details The function waits for any event among those specified in 00467 * @p mask to become pending then the events are cleared and 00468 * returned. 00469 * 00470 * @param[in] mask mask of the event flags that the function should wait 00471 * for, @p ALL_EVENTS enables all the events 00472 * @param[in] time the number of ticks before the operation timeouts, 00473 * the following special values are allowed: 00474 * - @a TIME_IMMEDIATE immediate timeout. 00475 * - @a TIME_INFINITE no timeout. 00476 * . 00477 * @return The mask of the served and cleared events. 00478 * @retval 0 if the operation has timed out. 00479 * 00480 * @api 00481 */ 00482 eventmask_t chEvtWaitAnyTimeout(eventmask_t mask, systime_t time) { 00483 Thread *ctp = currp; 00484 eventmask_t m; 00485 00486 chSysLock(); 00487 00488 if ((m = (ctp->p_epending & mask)) == 0) { 00489 if (TIME_IMMEDIATE == time) { 00490 chSysUnlock(); 00491 return (eventmask_t)0; 00492 } 00493 ctp->p_u.ewmask = mask; 00494 if (chSchGoSleepTimeoutS(THD_STATE_WTOREVT, time) < RDY_OK) { 00495 chSysUnlock(); 00496 return (eventmask_t)0; 00497 } 00498 m = ctp->p_epending & mask; 00499 } 00500 ctp->p_epending &= ~m; 00501 00502 chSysUnlock(); 00503 return m; 00504 } 00505 00506 /** 00507 * @brief Waits for all the specified events. 00508 * @details The function waits for all the events specified in @p mask to 00509 * become pending then the events are cleared and returned. 00510 * 00511 * @param[in] mask mask of the event flags that the function should wait 00512 * for, @p ALL_EVENTS requires all the events 00513 * @param[in] time the number of ticks before the operation timeouts, 00514 * the following special values are allowed: 00515 * - @a TIME_IMMEDIATE immediate timeout. 00516 * - @a TIME_INFINITE no timeout. 00517 * . 00518 * @return The mask of the served and cleared events. 00519 * @retval 0 if the operation has timed out. 00520 * 00521 * @api 00522 */ 00523 eventmask_t chEvtWaitAllTimeout(eventmask_t mask, systime_t time) { 00524 Thread *ctp = currp; 00525 00526 chSysLock(); 00527 00528 if ((ctp->p_epending & mask) != mask) { 00529 if (TIME_IMMEDIATE == time) { 00530 chSysUnlock(); 00531 return (eventmask_t)0; 00532 } 00533 ctp->p_u.ewmask = mask; 00534 if (chSchGoSleepTimeoutS(THD_STATE_WTANDEVT, time) < RDY_OK) { 00535 chSysUnlock(); 00536 return (eventmask_t)0; 00537 } 00538 } 00539 ctp->p_epending &= ~mask; 00540 00541 chSysUnlock(); 00542 return mask; 00543 } 00544 #endif /* CH_USE_EVENTS_TIMEOUT */ 00545 00546 #endif /* CH_USE_EVENTS */ 00547 00548 /** @} */