This is a fork of the `events` subdirectory of https://github.com/ARMmbed/mbed-os
Dependents: HelloWorld_CCA01M1 HelloWorld_CCA02M1 CI-data-logger-server HelloWorld_CCA02M1 ... more
This is a fork of the events
subdirectory of https://github.com/ARMmbed/mbed-os.
Note, you must import this library with import name: events
!!!
equeue/equeue.h@2:a60d8117d0e0, 2016-10-01 (annotated)
- Committer:
- Sam Grove
- Date:
- Sat Oct 01 02:11:36 2016 -0500
- Revision:
- 2:a60d8117d0e0
- Parent:
- 0:a792d4bf36c2
- Child:
- 5:705843a08e16
For drivers, events, hal, platform, rtos and mbed.h add one level of path to make sure specific and unique includes files are found.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Bogdan Marinescu |
0:a792d4bf36c2 | 1 | /* |
Bogdan Marinescu |
0:a792d4bf36c2 | 2 | * Flexible event queue for dispatching events |
Bogdan Marinescu |
0:a792d4bf36c2 | 3 | * |
Bogdan Marinescu |
0:a792d4bf36c2 | 4 | * Copyright (c) 2016 Christopher Haster |
Bogdan Marinescu |
0:a792d4bf36c2 | 5 | * |
Bogdan Marinescu |
0:a792d4bf36c2 | 6 | * Licensed under the Apache License, Version 2.0 (the "License"); |
Bogdan Marinescu |
0:a792d4bf36c2 | 7 | * you may not use this file except in compliance with the License. |
Bogdan Marinescu |
0:a792d4bf36c2 | 8 | * You may obtain a copy of the License at |
Bogdan Marinescu |
0:a792d4bf36c2 | 9 | * |
Bogdan Marinescu |
0:a792d4bf36c2 | 10 | * http://www.apache.org/licenses/LICENSE-2.0 |
Bogdan Marinescu |
0:a792d4bf36c2 | 11 | * |
Bogdan Marinescu |
0:a792d4bf36c2 | 12 | * Unless required by applicable law or agreed to in writing, software |
Bogdan Marinescu |
0:a792d4bf36c2 | 13 | * distributed under the License is distributed on an "AS IS" BASIS, |
Bogdan Marinescu |
0:a792d4bf36c2 | 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
Bogdan Marinescu |
0:a792d4bf36c2 | 15 | * See the License for the specific language governing permissions and |
Bogdan Marinescu |
0:a792d4bf36c2 | 16 | * limitations under the License. |
Bogdan Marinescu |
0:a792d4bf36c2 | 17 | */ |
Bogdan Marinescu |
0:a792d4bf36c2 | 18 | #ifndef EQUEUE_H |
Bogdan Marinescu |
0:a792d4bf36c2 | 19 | #define EQUEUE_H |
Bogdan Marinescu |
0:a792d4bf36c2 | 20 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 21 | #ifdef __cplusplus |
Bogdan Marinescu |
0:a792d4bf36c2 | 22 | extern "C" { |
Bogdan Marinescu |
0:a792d4bf36c2 | 23 | #endif |
Bogdan Marinescu |
0:a792d4bf36c2 | 24 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 25 | // Platform specific files |
Sam Grove |
2:a60d8117d0e0 | 26 | #include "equeue/equeue_platform.h" |
Bogdan Marinescu |
0:a792d4bf36c2 | 27 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 28 | #include <stddef.h> |
Bogdan Marinescu |
0:a792d4bf36c2 | 29 | #include <stdint.h> |
Bogdan Marinescu |
0:a792d4bf36c2 | 30 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 31 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 32 | // The minimum size of an event |
Bogdan Marinescu |
0:a792d4bf36c2 | 33 | // This size is guaranteed to fit events created by event_call |
Bogdan Marinescu |
0:a792d4bf36c2 | 34 | #define EQUEUE_EVENT_SIZE (sizeof(struct equeue_event) + 2*sizeof(void*)) |
Bogdan Marinescu |
0:a792d4bf36c2 | 35 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 36 | // Internal event structure |
Bogdan Marinescu |
0:a792d4bf36c2 | 37 | struct equeue_event { |
Bogdan Marinescu |
0:a792d4bf36c2 | 38 | unsigned size; |
Bogdan Marinescu |
0:a792d4bf36c2 | 39 | uint8_t id; |
Bogdan Marinescu |
0:a792d4bf36c2 | 40 | uint8_t generation; |
Bogdan Marinescu |
0:a792d4bf36c2 | 41 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 42 | struct equeue_event *next; |
Bogdan Marinescu |
0:a792d4bf36c2 | 43 | struct equeue_event *sibling; |
Bogdan Marinescu |
0:a792d4bf36c2 | 44 | struct equeue_event **ref; |
Bogdan Marinescu |
0:a792d4bf36c2 | 45 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 46 | unsigned target; |
Bogdan Marinescu |
0:a792d4bf36c2 | 47 | int period; |
Bogdan Marinescu |
0:a792d4bf36c2 | 48 | void (*dtor)(void *); |
Bogdan Marinescu |
0:a792d4bf36c2 | 49 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 50 | void (*cb)(void *); |
Bogdan Marinescu |
0:a792d4bf36c2 | 51 | // data follows |
Bogdan Marinescu |
0:a792d4bf36c2 | 52 | }; |
Bogdan Marinescu |
0:a792d4bf36c2 | 53 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 54 | // Event queue structure |
Bogdan Marinescu |
0:a792d4bf36c2 | 55 | typedef struct equeue { |
Bogdan Marinescu |
0:a792d4bf36c2 | 56 | struct equeue_event *queue; |
Bogdan Marinescu |
0:a792d4bf36c2 | 57 | unsigned tick; |
Bogdan Marinescu |
0:a792d4bf36c2 | 58 | unsigned breaks; |
Bogdan Marinescu |
0:a792d4bf36c2 | 59 | uint8_t generation; |
Bogdan Marinescu |
0:a792d4bf36c2 | 60 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 61 | unsigned char *buffer; |
Bogdan Marinescu |
0:a792d4bf36c2 | 62 | unsigned npw2; |
Bogdan Marinescu |
0:a792d4bf36c2 | 63 | void *allocated; |
Bogdan Marinescu |
0:a792d4bf36c2 | 64 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 65 | struct equeue_event *chunks; |
Bogdan Marinescu |
0:a792d4bf36c2 | 66 | struct equeue_slab { |
Bogdan Marinescu |
0:a792d4bf36c2 | 67 | size_t size; |
Bogdan Marinescu |
0:a792d4bf36c2 | 68 | unsigned char *data; |
Bogdan Marinescu |
0:a792d4bf36c2 | 69 | } slab; |
Bogdan Marinescu |
0:a792d4bf36c2 | 70 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 71 | struct equeue_background { |
Bogdan Marinescu |
0:a792d4bf36c2 | 72 | bool active; |
Bogdan Marinescu |
0:a792d4bf36c2 | 73 | void (*update)(void *timer, int ms); |
Bogdan Marinescu |
0:a792d4bf36c2 | 74 | void *timer; |
Bogdan Marinescu |
0:a792d4bf36c2 | 75 | } background; |
Bogdan Marinescu |
0:a792d4bf36c2 | 76 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 77 | equeue_sema_t eventsema; |
Bogdan Marinescu |
0:a792d4bf36c2 | 78 | equeue_mutex_t queuelock; |
Bogdan Marinescu |
0:a792d4bf36c2 | 79 | equeue_mutex_t memlock; |
Bogdan Marinescu |
0:a792d4bf36c2 | 80 | } equeue_t; |
Bogdan Marinescu |
0:a792d4bf36c2 | 81 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 82 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 83 | // Queue lifetime operations |
Bogdan Marinescu |
0:a792d4bf36c2 | 84 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 85 | // Creates and destroys an event queue. The event queue either allocates a |
Bogdan Marinescu |
0:a792d4bf36c2 | 86 | // buffer of the specified size with malloc or uses a user provided buffer |
Bogdan Marinescu |
0:a792d4bf36c2 | 87 | // if constructed with equeue_create_inplace. |
Bogdan Marinescu |
0:a792d4bf36c2 | 88 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 89 | // If the event queue creation fails, equeue_create returns a negative, |
Bogdan Marinescu |
0:a792d4bf36c2 | 90 | // platform-specific error code. |
Bogdan Marinescu |
0:a792d4bf36c2 | 91 | int equeue_create(equeue_t *queue, size_t size); |
Bogdan Marinescu |
0:a792d4bf36c2 | 92 | int equeue_create_inplace(equeue_t *queue, size_t size, void *buffer); |
Bogdan Marinescu |
0:a792d4bf36c2 | 93 | void equeue_destroy(equeue_t *queue); |
Bogdan Marinescu |
0:a792d4bf36c2 | 94 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 95 | // Dispatch events |
Bogdan Marinescu |
0:a792d4bf36c2 | 96 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 97 | // Executes events until the specified milliseconds have passed. If ms is |
Bogdan Marinescu |
0:a792d4bf36c2 | 98 | // negative, equeue_dispatch will dispatch events indefinitely or until |
Bogdan Marinescu |
0:a792d4bf36c2 | 99 | // equeue_break is called on this queue. |
Bogdan Marinescu |
0:a792d4bf36c2 | 100 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 101 | // When called with a finite timeout, the equeue_dispatch function is |
Bogdan Marinescu |
0:a792d4bf36c2 | 102 | // guaranteed to terminate. When called with a timeout of 0, the |
Bogdan Marinescu |
0:a792d4bf36c2 | 103 | // equeue_dispatch does not wait and is irq safe. |
Bogdan Marinescu |
0:a792d4bf36c2 | 104 | void equeue_dispatch(equeue_t *queue, int ms); |
Bogdan Marinescu |
0:a792d4bf36c2 | 105 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 106 | // Break out of a running event loop |
Bogdan Marinescu |
0:a792d4bf36c2 | 107 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 108 | // Forces the specified event queue's dispatch loop to terminate. Pending |
Bogdan Marinescu |
0:a792d4bf36c2 | 109 | // events may finish executing, but no new events will be executed. |
Bogdan Marinescu |
0:a792d4bf36c2 | 110 | void equeue_break(equeue_t *queue); |
Bogdan Marinescu |
0:a792d4bf36c2 | 111 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 112 | // Simple event calls |
Bogdan Marinescu |
0:a792d4bf36c2 | 113 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 114 | // The specified callback will be executed in the context of the event queue's |
Bogdan Marinescu |
0:a792d4bf36c2 | 115 | // dispatch loop. When the callback is executed depends on the call function. |
Bogdan Marinescu |
0:a792d4bf36c2 | 116 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 117 | // equeue_call - Immediately post an event to the queue |
Bogdan Marinescu |
0:a792d4bf36c2 | 118 | // equeue_call_in - Post an event after a specified time in milliseconds |
Bogdan Marinescu |
0:a792d4bf36c2 | 119 | // equeue_call_every - Post an event periodically every milliseconds |
Bogdan Marinescu |
0:a792d4bf36c2 | 120 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 121 | // All equeue_call functions are irq safe and can act as a mechanism for |
Bogdan Marinescu |
0:a792d4bf36c2 | 122 | // moving events out of irq contexts. |
Bogdan Marinescu |
0:a792d4bf36c2 | 123 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 124 | // The return value is a unique id that represents the posted event and can |
Bogdan Marinescu |
0:a792d4bf36c2 | 125 | // be passed to equeue_cancel. If there is not enough memory to allocate the |
Bogdan Marinescu |
0:a792d4bf36c2 | 126 | // event, equeue_call returns an id of 0. |
Bogdan Marinescu |
0:a792d4bf36c2 | 127 | int equeue_call(equeue_t *queue, void (*cb)(void *), void *data); |
Bogdan Marinescu |
0:a792d4bf36c2 | 128 | int equeue_call_in(equeue_t *queue, int ms, void (*cb)(void *), void *data); |
Bogdan Marinescu |
0:a792d4bf36c2 | 129 | int equeue_call_every(equeue_t *queue, int ms, void (*cb)(void *), void *data); |
Bogdan Marinescu |
0:a792d4bf36c2 | 130 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 131 | // Allocate memory for events |
Bogdan Marinescu |
0:a792d4bf36c2 | 132 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 133 | // The equeue_alloc function allocates an event that can be manually dispatched |
Bogdan Marinescu |
0:a792d4bf36c2 | 134 | // with equeue_post. The equeue_dealloc function may be used to free an event |
Bogdan Marinescu |
0:a792d4bf36c2 | 135 | // that has not been posted. Once posted, an event's memory is managed by the |
Bogdan Marinescu |
0:a792d4bf36c2 | 136 | // event queue and should not be deallocated. |
Bogdan Marinescu |
0:a792d4bf36c2 | 137 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 138 | // Both equeue_alloc and equeue_dealloc are irq safe. |
Bogdan Marinescu |
0:a792d4bf36c2 | 139 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 140 | // The equeue allocator is designed to minimize jitter in interrupt contexts as |
Bogdan Marinescu |
0:a792d4bf36c2 | 141 | // well as avoid memory fragmentation on small devices. The allocator achieves |
Bogdan Marinescu |
0:a792d4bf36c2 | 142 | // both constant-runtime and zero-fragmentation for fixed-size events, however |
Bogdan Marinescu |
0:a792d4bf36c2 | 143 | // grows linearly as the quantity of different sized allocations increases. |
Bogdan Marinescu |
0:a792d4bf36c2 | 144 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 145 | // The equeue_alloc function returns a pointer to the event's allocated memory |
Bogdan Marinescu |
0:a792d4bf36c2 | 146 | // and acts as a handle to the underlying event. If there is not enough memory |
Bogdan Marinescu |
0:a792d4bf36c2 | 147 | // to allocate the event, equeue_alloc returns null. |
Bogdan Marinescu |
0:a792d4bf36c2 | 148 | void *equeue_alloc(equeue_t *queue, size_t size); |
Bogdan Marinescu |
0:a792d4bf36c2 | 149 | void equeue_dealloc(equeue_t *queue, void *event); |
Bogdan Marinescu |
0:a792d4bf36c2 | 150 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 151 | // Configure an allocated event |
Bogdan Marinescu |
0:a792d4bf36c2 | 152 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 153 | // equeue_event_delay - Millisecond delay before dispatching an event |
Bogdan Marinescu |
0:a792d4bf36c2 | 154 | // equeue_event_period - Millisecond period for repeating dispatching an event |
Bogdan Marinescu |
0:a792d4bf36c2 | 155 | // equeue_event_dtor - Destructor to run when the event is deallocated |
Bogdan Marinescu |
0:a792d4bf36c2 | 156 | void equeue_event_delay(void *event, int ms); |
Bogdan Marinescu |
0:a792d4bf36c2 | 157 | void equeue_event_period(void *event, int ms); |
Bogdan Marinescu |
0:a792d4bf36c2 | 158 | void equeue_event_dtor(void *event, void (*dtor)(void *)); |
Bogdan Marinescu |
0:a792d4bf36c2 | 159 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 160 | // Post an event onto the event queue |
Bogdan Marinescu |
0:a792d4bf36c2 | 161 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 162 | // The equeue_post function takes a callback and a pointer to an event |
Bogdan Marinescu |
0:a792d4bf36c2 | 163 | // allocated by equeue_alloc. The specified callback will be executed in the |
Bogdan Marinescu |
0:a792d4bf36c2 | 164 | // context of the event queue's dispatch loop with the allocated event |
Bogdan Marinescu |
0:a792d4bf36c2 | 165 | // as its argument. |
Bogdan Marinescu |
0:a792d4bf36c2 | 166 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 167 | // The equeue_post function is irq safe and can act as a mechanism for |
Bogdan Marinescu |
0:a792d4bf36c2 | 168 | // moving events out of irq contexts. |
Bogdan Marinescu |
0:a792d4bf36c2 | 169 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 170 | // The return value is a unique id that represents the posted event and can |
Bogdan Marinescu |
0:a792d4bf36c2 | 171 | // be passed to equeue_cancel. |
Bogdan Marinescu |
0:a792d4bf36c2 | 172 | int equeue_post(equeue_t *queue, void (*cb)(void *), void *event); |
Bogdan Marinescu |
0:a792d4bf36c2 | 173 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 174 | // Cancel an in-flight event |
Bogdan Marinescu |
0:a792d4bf36c2 | 175 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 176 | // Attempts to cancel an event referenced by the unique id returned from |
Bogdan Marinescu |
0:a792d4bf36c2 | 177 | // equeue_call or equeue_post. It is safe to call equeue_cancel after an event |
Bogdan Marinescu |
0:a792d4bf36c2 | 178 | // has already been dispatched. |
Bogdan Marinescu |
0:a792d4bf36c2 | 179 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 180 | // The equeue_cancel function is irq safe. |
Bogdan Marinescu |
0:a792d4bf36c2 | 181 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 182 | // If called while the event queue's dispatch loop is active, equeue_cancel |
Bogdan Marinescu |
0:a792d4bf36c2 | 183 | // does not guarantee that the event will not not execute after it returns as |
Bogdan Marinescu |
0:a792d4bf36c2 | 184 | // the event may have already begun executing. |
Bogdan Marinescu |
0:a792d4bf36c2 | 185 | void equeue_cancel(equeue_t *queue, int id); |
Bogdan Marinescu |
0:a792d4bf36c2 | 186 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 187 | // Background an event queue onto a single-shot timer |
Bogdan Marinescu |
0:a792d4bf36c2 | 188 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 189 | // The provided update function will be called to indicate when the queue |
Bogdan Marinescu |
0:a792d4bf36c2 | 190 | // should be dispatched. A negative timeout will be passed to the update |
Bogdan Marinescu |
0:a792d4bf36c2 | 191 | // function when the timer is no longer needed. |
Bogdan Marinescu |
0:a792d4bf36c2 | 192 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 193 | // Passing a null update function disables the existing timer. |
Bogdan Marinescu |
0:a792d4bf36c2 | 194 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 195 | // The equeue_background function allows an event queue to take advantage |
Bogdan Marinescu |
0:a792d4bf36c2 | 196 | // of hardware timers or even other event loops, allowing an event queue to |
Bogdan Marinescu |
0:a792d4bf36c2 | 197 | // be effectively backgrounded. |
Bogdan Marinescu |
0:a792d4bf36c2 | 198 | void equeue_background(equeue_t *queue, |
Bogdan Marinescu |
0:a792d4bf36c2 | 199 | void (*update)(void *timer, int ms), void *timer); |
Bogdan Marinescu |
0:a792d4bf36c2 | 200 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 201 | // Chain an event queue onto another event queue |
Bogdan Marinescu |
0:a792d4bf36c2 | 202 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 203 | // After chaining a queue to a target, calling equeue_dispatch on the |
Bogdan Marinescu |
0:a792d4bf36c2 | 204 | // target queue will also dispatch events from this queue. The queues |
Bogdan Marinescu |
0:a792d4bf36c2 | 205 | // use their own buffers and events must be managed independently. |
Bogdan Marinescu |
0:a792d4bf36c2 | 206 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 207 | // Passing a null queue as the target will unchain the existing queue. |
Bogdan Marinescu |
0:a792d4bf36c2 | 208 | // |
Bogdan Marinescu |
0:a792d4bf36c2 | 209 | // The equeue_chain function allows multiple equeues to be composed, sharing |
Bogdan Marinescu |
0:a792d4bf36c2 | 210 | // the context of a dispatch loop while still being managed independently. |
Bogdan Marinescu |
0:a792d4bf36c2 | 211 | void equeue_chain(equeue_t *queue, equeue_t *target); |
Bogdan Marinescu |
0:a792d4bf36c2 | 212 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 213 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 214 | #ifdef __cplusplus |
Bogdan Marinescu |
0:a792d4bf36c2 | 215 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 216 | #endif |
Bogdan Marinescu |
0:a792d4bf36c2 | 217 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 218 | #endif |