Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers UserAllocatedEvent.h Source File

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