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