Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
UserAllocatedEvent.h
00001 /* 00002 * Copyright (c) 2019 ARM Limited 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 #ifndef USER_ALLOCATED_EVENT_H 00018 #define USER_ALLOCATED_EVENT_H 00019 00020 #include "events/EventQueue.h" 00021 #include "platform/mbed_assert.h" 00022 #include "platform/mbed_atomic.h" 00023 00024 namespace events { 00025 /** 00026 * \addtogroup events-public-api 00027 * @{ 00028 */ 00029 template <typename F, typename A> 00030 class UserAllocatedEvent; 00031 00032 /** 00033 * \defgroup events_Event UserAllocatedEvent class 00034 * @{ 00035 */ 00036 00037 /** UserAllocatedEvent 00038 * 00039 * Representation of an static event for fine-grain dispatch control. 00040 * 00041 * UserAllocatedEvent provides mechanism for event posting and dispatching 00042 * without utilization of queue internal memory. It embeds all underlying 00043 * event data and doesn't require any memory allocation while posting and dispatching. 00044 * All of these makes it cannot fail due to memory exhaustion while posting 00045 * 00046 * Usage: 00047 * @code 00048 * #include "mbed.h" 00049 * 00050 * void handler(int data) { ... } 00051 * 00052 * class Device { 00053 * public: 00054 * void handler(int data) { ... } 00055 * }; 00056 * 00057 * Device dev; 00058 * 00059 * // queue with not internal storage for dynamic events 00060 * // accepts only user allocated events 00061 * static EventQueue queue(0); 00062 * // Create events 00063 * static auto e1 = make_user_allocated_event(&dev, Device::handler, 2); 00064 * static auto e2 = queue.make_user_allocated_event(handler, 3); 00065 * 00066 * int main() 00067 * { 00068 * e1.call_on(&queue); 00069 * e2.call(); 00070 * 00071 * queue.dispatch(1); 00072 * } 00073 * @endcode 00074 */ 00075 template <typename F, typename... ArgTs> 00076 class UserAllocatedEvent<F, void(ArgTs...)> { 00077 public: 00078 typedef EventQueue::context<F, ArgTs...> C; 00079 00080 /** Create an event 00081 * 00082 * Constructs an event. The specified callback acts as the target 00083 * for the event and is executed in the context of the 00084 * event queue's dispatch loop once posted. 00085 * 00086 * @param f Function to execute when the event is dispatched 00087 * @param args Arguments to bind to the callback 00088 */ 00089 constexpr UserAllocatedEvent(F f, ArgTs... args) : _e(get_default_equeue_event()), _c(f, args...), _equeue(), _post_ref() 00090 { 00091 } 00092 00093 /** Create an event 00094 * 00095 * Constructs an event. The specified callback acts as the target 00096 * for the event and is executed in the context of the 00097 * event queue's dispatch loop once posted. 00098 * 00099 * @param queue Event queue to dispatch on 00100 * @param f Function to execute when the event is dispatched 00101 * @param args Arguments to bind to the callback 00102 */ 00103 constexpr UserAllocatedEvent(EventQueue *queue, F f, ArgTs... args) : _e(get_default_equeue_event()), _c(f, args...), _equeue(&queue->_equeue), _post_ref() 00104 { 00105 } 00106 00107 /** Destructor for events 00108 */ 00109 #if !defined(NDEBUG) 00110 // Remove the user provided destructor in release to allow constexpr optimization 00111 // constexpr requires destructor to be trivial and only default one is treated as trivial 00112 ~UserAllocatedEvent() 00113 { 00114 MBED_ASSERT(!_post_ref); 00115 } 00116 #endif 00117 00118 /** Posts an event onto the underlying event queue, returning void 00119 * 00120 * The event is posted to the underlying queue and is executed in the 00121 * context of the event queue's dispatch loop. 00122 * 00123 * This call cannot fail due queue memory exhaustion 00124 * because it doesn't allocate any memory 00125 * 00126 * The post function is IRQ safe and can act as a mechanism for moving 00127 * events out of IRQ contexts. 00128 * 00129 */ 00130 void call() 00131 { 00132 MBED_ASSERT(!_post_ref); 00133 MBED_ASSERT(_equeue); 00134 MBED_UNUSED bool status = post(); 00135 MBED_ASSERT(status); 00136 } 00137 00138 /** Posts an event onto the event queue passed as argument, returning void 00139 * 00140 * The event is posted to the event queue passed as argument 00141 * and is executed in the context of the event queue's dispatch loop. 00142 * 00143 * This call cannot fail due queue memory exhaustion 00144 * because it doesn't allocate any memory 00145 * 00146 * The post function is IRQ safe and can act as a mechanism for moving 00147 * events out of IRQ contexts. 00148 * 00149 * @param queue Event queue to dispatch on. Will replace earlier bound EventQueue. 00150 * 00151 */ 00152 void call_on(EventQueue *queue) 00153 { 00154 MBED_ASSERT(!_post_ref); 00155 MBED_UNUSED bool status = post_on(queue); 00156 MBED_ASSERT(status); 00157 } 00158 00159 /** Posts an event onto the underlying event queue 00160 * 00161 * The event is posted to the event queue passed as argument 00162 * and is executed in the context of the event queue's dispatch loop. 00163 * 00164 * This call cannot fail due queue memory exhaustion 00165 * because it doesn't allocate any memory 00166 * 00167 * @return False if the event was already posted 00168 * true otherwise 00169 * 00170 */ 00171 bool try_call() 00172 { 00173 return post(); 00174 } 00175 00176 /** Posts an event onto the event queue passed as argument, 00177 * 00178 * The event is posted to the underlying queue and is executed in the 00179 * context of the event queue's dispatch loop. 00180 * 00181 * This call cannot fail due queue memory exhaustion 00182 * because it doesn't allocate any memory 00183 * 00184 * @param queue Event queue to dispatch on. Will replace earlier bound EventQueue. 00185 * @return False if the event was already posted 00186 * true otherwise 00187 * 00188 */ 00189 bool try_call_on(EventQueue *queue) 00190 { 00191 return post_on(queue); 00192 } 00193 00194 /** Posts an event onto the underlying event queue, returning void 00195 * 00196 * The event is posted to the underlying queue and is executed in the 00197 * context of the event queue's dispatch loop. 00198 * 00199 * This call cannot fail due queue memory exhaustion 00200 * because it doesn't allocate any memory 00201 * 00202 * The post function is IRQ safe and can act as a mechanism for moving 00203 * events out of IRQ contexts. 00204 * 00205 */ 00206 void operator()() 00207 { 00208 return call(); 00209 } 00210 00211 /** Configure the delay of an event 00212 * 00213 * @param delay Millisecond delay before dispatching the event 00214 */ 00215 void delay(int delay) 00216 { 00217 MBED_ASSERT(!_post_ref); 00218 equeue_event_delay(&_e + 1, delay); 00219 } 00220 00221 /** Configure the period of an event 00222 * 00223 * @param period Millisecond period for repeatedly dispatching an event 00224 */ 00225 void period(int period) 00226 { 00227 MBED_ASSERT(!_post_ref); 00228 equeue_event_period(&_e + 1, period); 00229 } 00230 00231 /** Cancels posted event 00232 * 00233 * Attempts to cancel posted event. It is safe to call 00234 * cancel after an event has already been dispatched. 00235 * 00236 * The cancel function is IRQ safe. 00237 * 00238 * If called while the event queue's dispatch loop is active, the cancel 00239 * function does not guarantee that the event will not execute after it 00240 * returns, as the event may have already begun executing. 00241 * 00242 * @return true if event was successfully cancelled 00243 */ 00244 bool cancel() 00245 { 00246 return equeue_cancel_user_allocated(_equeue, &_e); 00247 } 00248 00249 00250 private: 00251 friend class EventQueue; 00252 struct equeue_event _e; 00253 C _c; 00254 struct equeue *_equeue; 00255 uint8_t _post_ref; 00256 00257 bool post() 00258 { 00259 if (_post_ref) { 00260 return false; 00261 } 00262 core_util_atomic_incr_u8(&_post_ref, 1); 00263 equeue_post_user_allocated(_equeue, &EventQueue::function_call<C>, &_e); 00264 return true; 00265 } 00266 00267 bool post_on(EventQueue *queue) 00268 { 00269 if (_post_ref) { 00270 return false; 00271 } 00272 _equeue = &(queue->_equeue); 00273 core_util_atomic_incr_u8(&_post_ref, 1); 00274 equeue_post_user_allocated(_equeue, &EventQueue::function_call<C>, &_e); 00275 return true; 00276 } 00277 00278 static void event_dtor(void *p) 00279 { 00280 UserAllocatedEvent<F, void(ArgTs...)> *instance = (UserAllocatedEvent<F, void(ArgTs...)> *)(((equeue_event *)p) - 1); 00281 core_util_atomic_decr_u8(&instance->_post_ref, 1); 00282 MBED_ASSERT(!instance->_post_ref); 00283 } 00284 00285 constexpr static equeue_event get_default_equeue_event() 00286 { 00287 return equeue_event{ 0, 0, 0, NULL, NULL, NULL, 0, -1, &UserAllocatedEvent::event_dtor, NULL }; 00288 } 00289 00290 public: 00291 00292 /** Create an event 00293 * @see UserAllocatedEvent::UserAllocatedEvent 00294 */ 00295 template <typename T, typename R> 00296 constexpr UserAllocatedEvent(T *obj, R(T::*method)(ArgTs...), ArgTs... args) : 00297 UserAllocatedEvent(mbed::callback(obj, method), args...) { } 00298 00299 /** Create an event 00300 * @see UserAllocatedEvent::UserAllocatedEvent 00301 */ 00302 template <typename T, typename R> 00303 constexpr UserAllocatedEvent(EventQueue *q, T *obj, R(T::*method)(ArgTs...), ArgTs... args) : 00304 UserAllocatedEvent(q, mbed::callback(obj, method), args...) { } 00305 00306 /** Create an event 00307 * @see UserAllocatedEvent::UserAllocatedEvent 00308 */ 00309 template <typename T, typename R> 00310 constexpr UserAllocatedEvent(const T *obj, R(T::*method)(ArgTs...) const, ArgTs... args) : 00311 UserAllocatedEvent(mbed::callback(obj, method), args...) { } 00312 00313 /** Create an event 00314 * @see UserAllocatedEvent::UserAllocatedEvent 00315 */ 00316 template <typename T, typename R> 00317 constexpr UserAllocatedEvent(EventQueue *q, const T *obj, R(T::*method)(ArgTs...) const, ArgTs... args) : 00318 UserAllocatedEvent(q, mbed::callback(obj, method), args...) { } 00319 00320 /** Create an event 00321 * @see UserAllocatedEvent::UserAllocatedEvent 00322 */ 00323 template <typename T, typename R> 00324 constexpr UserAllocatedEvent(volatile T *obj, R(T::*method)(ArgTs...) volatile, ArgTs... args) : 00325 UserAllocatedEvent(mbed::callback(obj, method), args...) { } 00326 00327 /** Create an event 00328 * @see UserAllocatedEvent::UserAllocatedEvent 00329 */ 00330 template <typename T, typename R> 00331 constexpr UserAllocatedEvent(EventQueue *q, volatile T *obj, R(T::*method)(ArgTs...) volatile, ArgTs... args) : 00332 UserAllocatedEvent(q, mbed::callback(obj, method), args...) { } 00333 00334 /** Create an event 00335 * @see UserAllocatedEvent::UserAllocatedEvent 00336 */ 00337 template <typename T, typename R> 00338 constexpr UserAllocatedEvent(const volatile T *obj, R(T::*method)(ArgTs...) const volatile, ArgTs... args) : 00339 UserAllocatedEvent(mbed::callback(obj, method), args...) { } 00340 00341 /** Create an event 00342 * @see UserAllocatedEvent::UserAllocatedEvent 00343 */ 00344 template <typename T, typename R> 00345 constexpr UserAllocatedEvent(EventQueue *q, const volatile T *obj, R(T::*method)(ArgTs...) const volatile, ArgTs... args) : 00346 UserAllocatedEvent(q, mbed::callback(obj, method), args...) { } 00347 }; 00348 00349 // Convenience functions declared here to avoid cyclic 00350 // dependency between Event and EventQueue 00351 template <typename F, typename... ArgTs> 00352 UserAllocatedEvent<F, void(ArgTs...)> EventQueue::make_user_allocated_event(F f, ArgTs... args) 00353 { 00354 return UserAllocatedEvent<F, void(ArgTs...)>(this, f, args...); 00355 } 00356 00357 template <typename T, typename R, typename... ArgTs> 00358 UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> EventQueue::make_user_allocated_event(T *obj, R(T::*method)(ArgTs... args), ArgTs... args) 00359 { 00360 return UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)>(this, mbed::callback(obj, method), args...); 00361 } 00362 00363 template <typename T, typename R, typename... ArgTs> 00364 UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> EventQueue::make_user_allocated_event(const T *obj, R(T::*method)(ArgTs... args) const, ArgTs... args) 00365 { 00366 return UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)>(this, mbed::callback(obj, method), args...); 00367 } 00368 00369 template <typename T, typename R, typename... ArgTs> 00370 UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> EventQueue::make_user_allocated_event(volatile T *obj, R(T::*method)(ArgTs... args) volatile, ArgTs... args) 00371 { 00372 return UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)>(this, mbed::callback(obj, method), args...); 00373 } 00374 00375 template <typename T, typename R, typename... ArgTs> 00376 UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> EventQueue::make_user_allocated_event(const volatile T *obj, R(T::*method)(ArgTs... args) const volatile, ArgTs... args) 00377 { 00378 return UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)>(this, mbed::callback(obj, method), args...); 00379 } 00380 00381 00382 /** Creates a UserAllocatedEvent object, deducing the target type from the types of arguments 00383 * 00384 * UserAllocatedEvent doesn't utilize EventQueue internal memory, 00385 * therefore it can be posted on the queue without being afraid 00386 * of post fail due to queue memory exhaustion 00387 * 00388 * @return UserAllocatedEvent object instance 00389 * 00390 */ 00391 template <typename F, typename... ArgTs> 00392 constexpr UserAllocatedEvent<F, void(ArgTs...)> make_user_allocated_event(F f, ArgTs... args) 00393 { 00394 return UserAllocatedEvent<F, void(ArgTs...)>(f, args...); 00395 } 00396 00397 /** Creates a UserAllocatedEvent object, deducing the target type from the types of arguments 00398 * 00399 * UserAllocatedEvent doesn't utilize EventQueue internal memory, 00400 * therefore it can be posted on the queue without being afraid 00401 * of post fail due to queue memory exhaustion 00402 * 00403 * @return UserAllocatedEvent object instance 00404 * 00405 */ 00406 template <typename T, typename R, typename... ArgTs> 00407 constexpr UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> make_user_allocated_event(T *obj, R(T::*method)(ArgTs... args), ArgTs... args) 00408 { 00409 return UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)>(mbed::callback(obj, method), args...); 00410 } 00411 00412 /** Creates a UserAllocatedEvent object, deducing the target type from the types of arguments 00413 * 00414 * UserAllocatedEvent doesn't utilize EventQueue internal memory, 00415 * therefore it can be posted on the queue without being afraid 00416 * of post fail due to queue memory exhaustion 00417 * 00418 * @return UserAllocatedEvent object instance 00419 * 00420 */ 00421 template <typename T, typename R, typename... ArgTs> 00422 constexpr UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> make_user_allocated_event(const T *obj, R(T::*method)(ArgTs... args) const, ArgTs... args) 00423 { 00424 return UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)>(mbed::callback(obj, method), args...); 00425 } 00426 00427 /** Creates a UserAllocatedEvent object, deducing the target type from the types of arguments 00428 * 00429 * UserAllocatedEvent doesn't utilize EventQueue internal memory, 00430 * therefore it can be posted on the queue without being afraid 00431 * of post fail due to queue memory exhaustion 00432 * 00433 * @return UserAllocatedEvent object instance 00434 * 00435 */ 00436 template <typename T, typename R, typename... ArgTs> 00437 constexpr UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> make_user_allocated_event(volatile T *obj, R(T::*method)(ArgTs... args) volatile, ArgTs... args) 00438 { 00439 return UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)>(mbed::callback(obj, method), args...); 00440 } 00441 00442 /** Creates a UserAllocatedEvent object, deducing the target type from the types of arguments 00443 * 00444 * UserAllocatedEvent doesn't utilize EventQueue internal memory, 00445 * therefore it can be posted on the queue without being afraid 00446 * of post fail due to queue memory exhaustion 00447 * 00448 * @return UserAllocatedEvent object instance 00449 * 00450 */ 00451 template <typename T, typename R, typename... ArgTs> 00452 constexpr UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> make_user_allocated_event(const volatile T *obj, R(T::*method)(ArgTs... args) const volatile, ArgTs... args) 00453 { 00454 return UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)>(mbed::callback(obj, method), args...); 00455 } 00456 00457 /** @}*/ 00458 00459 /** @}*/ 00460 } 00461 #endif
Generated on Tue Jul 12 2022 13:55:03 by
