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.
mbed-os/events/equeue/README.md@0:8fdf9a60065b, 2018-10-10 (annotated)
- Committer:
- kadonotakashi
- Date:
- Wed Oct 10 00:33:53 2018 +0000
- Revision:
- 0:8fdf9a60065b
how to make mbed librry
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
kadonotakashi | 0:8fdf9a60065b | 1 | ## The equeue library ## |
kadonotakashi | 0:8fdf9a60065b | 2 | |
kadonotakashi | 0:8fdf9a60065b | 3 | The equeue library is designed as a simple but powerful library for scheduling |
kadonotakashi | 0:8fdf9a60065b | 4 | events on composable queues. |
kadonotakashi | 0:8fdf9a60065b | 5 | |
kadonotakashi | 0:8fdf9a60065b | 6 | ``` c |
kadonotakashi | 0:8fdf9a60065b | 7 | #include "equeue.h" |
kadonotakashi | 0:8fdf9a60065b | 8 | #include <stdio.h> |
kadonotakashi | 0:8fdf9a60065b | 9 | |
kadonotakashi | 0:8fdf9a60065b | 10 | int main() { |
kadonotakashi | 0:8fdf9a60065b | 11 | // creates a queue with space for 32 basic events |
kadonotakashi | 0:8fdf9a60065b | 12 | equeue_t queue; |
kadonotakashi | 0:8fdf9a60065b | 13 | equeue_create(&queue, 32*EQUEUE_EVENT_SIZE); |
kadonotakashi | 0:8fdf9a60065b | 14 | |
kadonotakashi | 0:8fdf9a60065b | 15 | // events can be simple callbacks |
kadonotakashi | 0:8fdf9a60065b | 16 | equeue_call(&queue, print, "called immediately"); |
kadonotakashi | 0:8fdf9a60065b | 17 | equeue_call_in(&queue, 2000, print, "called in 2 seconds"); |
kadonotakashi | 0:8fdf9a60065b | 18 | equeue_call_every(&queue, 1000, print, "called every 1 seconds"); |
kadonotakashi | 0:8fdf9a60065b | 19 | |
kadonotakashi | 0:8fdf9a60065b | 20 | // events are executed in equeue_dispatch |
kadonotakashi | 0:8fdf9a60065b | 21 | equeue_dispatch(&queue, 3000); |
kadonotakashi | 0:8fdf9a60065b | 22 | |
kadonotakashi | 0:8fdf9a60065b | 23 | print("called after 3 seconds"); |
kadonotakashi | 0:8fdf9a60065b | 24 | |
kadonotakashi | 0:8fdf9a60065b | 25 | equeue_destroy(&queue); |
kadonotakashi | 0:8fdf9a60065b | 26 | } |
kadonotakashi | 0:8fdf9a60065b | 27 | ``` |
kadonotakashi | 0:8fdf9a60065b | 28 | |
kadonotakashi | 0:8fdf9a60065b | 29 | The equeue library can be used as a normal event loop, or it can be |
kadonotakashi | 0:8fdf9a60065b | 30 | backgrounded on a single hardware timer or even another event loop. It |
kadonotakashi | 0:8fdf9a60065b | 31 | is both thread and irq safe, and provides functions for easily composing |
kadonotakashi | 0:8fdf9a60065b | 32 | multiple queues. |
kadonotakashi | 0:8fdf9a60065b | 33 | |
kadonotakashi | 0:8fdf9a60065b | 34 | The equeue library can act as a drop-in scheduler, provide synchronization |
kadonotakashi | 0:8fdf9a60065b | 35 | between multiple threads, or just act as a mechanism for moving events |
kadonotakashi | 0:8fdf9a60065b | 36 | out of interrupt contexts. |
kadonotakashi | 0:8fdf9a60065b | 37 | |
kadonotakashi | 0:8fdf9a60065b | 38 | ## Documentation ## |
kadonotakashi | 0:8fdf9a60065b | 39 | |
kadonotakashi | 0:8fdf9a60065b | 40 | The in-depth documentation on specific functions can be found in |
kadonotakashi | 0:8fdf9a60065b | 41 | [equeue.h](equeue.h). |
kadonotakashi | 0:8fdf9a60065b | 42 | |
kadonotakashi | 0:8fdf9a60065b | 43 | The core of the equeue library is the `equeue_t` type which represents a |
kadonotakashi | 0:8fdf9a60065b | 44 | single event queue, and the `equeue_dispatch` function which runs the equeue, |
kadonotakashi | 0:8fdf9a60065b | 45 | providing the context for executing events. |
kadonotakashi | 0:8fdf9a60065b | 46 | |
kadonotakashi | 0:8fdf9a60065b | 47 | On top of this, `equeue_call`, `equeue_call_in`, and `equeue_call_every` |
kadonotakashi | 0:8fdf9a60065b | 48 | provide easy methods for posting events to execute in the context of the |
kadonotakashi | 0:8fdf9a60065b | 49 | `equeue_dispatch` function. |
kadonotakashi | 0:8fdf9a60065b | 50 | |
kadonotakashi | 0:8fdf9a60065b | 51 | ``` c |
kadonotakashi | 0:8fdf9a60065b | 52 | #include "equeue.h" |
kadonotakashi | 0:8fdf9a60065b | 53 | #include "game.h" |
kadonotakashi | 0:8fdf9a60065b | 54 | |
kadonotakashi | 0:8fdf9a60065b | 55 | equeue_t queue; |
kadonotakashi | 0:8fdf9a60065b | 56 | struct game game; |
kadonotakashi | 0:8fdf9a60065b | 57 | |
kadonotakashi | 0:8fdf9a60065b | 58 | // button_isr may be in interrupt context |
kadonotakashi | 0:8fdf9a60065b | 59 | void button_isr(void) { |
kadonotakashi | 0:8fdf9a60065b | 60 | equeue_call(&queue, game_button_update, &game); |
kadonotakashi | 0:8fdf9a60065b | 61 | } |
kadonotakashi | 0:8fdf9a60065b | 62 | |
kadonotakashi | 0:8fdf9a60065b | 63 | // a simple user-interface framework |
kadonotakashi | 0:8fdf9a60065b | 64 | int main() { |
kadonotakashi | 0:8fdf9a60065b | 65 | equeue_create(&queue, 4096); |
kadonotakashi | 0:8fdf9a60065b | 66 | game_create(&game); |
kadonotakashi | 0:8fdf9a60065b | 67 | |
kadonotakashi | 0:8fdf9a60065b | 68 | // call game_screen_udpate at 60 Hz |
kadonotakashi | 0:8fdf9a60065b | 69 | equeue_call_every(&queue, 1000/60, game_screen_update, &game); |
kadonotakashi | 0:8fdf9a60065b | 70 | |
kadonotakashi | 0:8fdf9a60065b | 71 | // dispatch forever |
kadonotakashi | 0:8fdf9a60065b | 72 | equeue_dispatch(&queue, -1); |
kadonotakashi | 0:8fdf9a60065b | 73 | } |
kadonotakashi | 0:8fdf9a60065b | 74 | ``` |
kadonotakashi | 0:8fdf9a60065b | 75 | |
kadonotakashi | 0:8fdf9a60065b | 76 | In addition to simple callbacks, an event can be manually allocated with |
kadonotakashi | 0:8fdf9a60065b | 77 | `equeue_alloc` and posted with `equeue_post` to allow passing an arbitrary |
kadonotakashi | 0:8fdf9a60065b | 78 | amount of context to the execution of the event. This memory is allocated out |
kadonotakashi | 0:8fdf9a60065b | 79 | of the equeue's buffer, and dynamic memory can be completely avoided. |
kadonotakashi | 0:8fdf9a60065b | 80 | |
kadonotakashi | 0:8fdf9a60065b | 81 | The equeue allocator is designed to minimize jitter in interrupt contexts as |
kadonotakashi | 0:8fdf9a60065b | 82 | well as avoid memory fragmentation on small devices. The allocator achieves |
kadonotakashi | 0:8fdf9a60065b | 83 | both constant-runtime and zero-fragmentation for fixed-size events, however |
kadonotakashi | 0:8fdf9a60065b | 84 | grows linearly as the quantity of differently-sized allocations increases. |
kadonotakashi | 0:8fdf9a60065b | 85 | |
kadonotakashi | 0:8fdf9a60065b | 86 | ``` c |
kadonotakashi | 0:8fdf9a60065b | 87 | #include "equeue.h" |
kadonotakashi | 0:8fdf9a60065b | 88 | |
kadonotakashi | 0:8fdf9a60065b | 89 | equeue_t queue; |
kadonotakashi | 0:8fdf9a60065b | 90 | |
kadonotakashi | 0:8fdf9a60065b | 91 | // arbitrary data can be moved to a different context |
kadonotakashi | 0:8fdf9a60065b | 92 | int enet_consume(void *buffer, int size) { |
kadonotakashi | 0:8fdf9a60065b | 93 | if (size > 512) { |
kadonotakashi | 0:8fdf9a60065b | 94 | size = 512; |
kadonotakashi | 0:8fdf9a60065b | 95 | } |
kadonotakashi | 0:8fdf9a60065b | 96 | |
kadonotakashi | 0:8fdf9a60065b | 97 | void *data = equeue_alloc(&queue, 512); |
kadonotakashi | 0:8fdf9a60065b | 98 | memcpy(data, buffer, size); |
kadonotakashi | 0:8fdf9a60065b | 99 | equeue_post(&queue, handle_data_elsewhere, data); |
kadonotakashi | 0:8fdf9a60065b | 100 | |
kadonotakashi | 0:8fdf9a60065b | 101 | return size; |
kadonotakashi | 0:8fdf9a60065b | 102 | } |
kadonotakashi | 0:8fdf9a60065b | 103 | ``` |
kadonotakashi | 0:8fdf9a60065b | 104 | |
kadonotakashi | 0:8fdf9a60065b | 105 | Additionally, in-flight events can be cancelled with `equeue_cancel`. Events |
kadonotakashi | 0:8fdf9a60065b | 106 | are given unique ids on post, allowing safe cancellation of expired events. |
kadonotakashi | 0:8fdf9a60065b | 107 | |
kadonotakashi | 0:8fdf9a60065b | 108 | ``` c |
kadonotakashi | 0:8fdf9a60065b | 109 | #include "equeue.h" |
kadonotakashi | 0:8fdf9a60065b | 110 | |
kadonotakashi | 0:8fdf9a60065b | 111 | equeue_t queue; |
kadonotakashi | 0:8fdf9a60065b | 112 | int sonar_value; |
kadonotakashi | 0:8fdf9a60065b | 113 | int sonar_timeout_id; |
kadonotakashi | 0:8fdf9a60065b | 114 | |
kadonotakashi | 0:8fdf9a60065b | 115 | void sonar_isr(int value) { |
kadonotakashi | 0:8fdf9a60065b | 116 | equeue_cancel(&queue, sonar_timeout_id); |
kadonotakashi | 0:8fdf9a60065b | 117 | sonar_value = value; |
kadonotakashi | 0:8fdf9a60065b | 118 | } |
kadonotakashi | 0:8fdf9a60065b | 119 | |
kadonotakashi | 0:8fdf9a60065b | 120 | void sonar_timeout(void *) { |
kadonotakashi | 0:8fdf9a60065b | 121 | sonar_value = -1; |
kadonotakashi | 0:8fdf9a60065b | 122 | } |
kadonotakashi | 0:8fdf9a60065b | 123 | |
kadonotakashi | 0:8fdf9a60065b | 124 | void sonar_read(void) { |
kadonotakashi | 0:8fdf9a60065b | 125 | sonar_timeout_id = equeue_call_in(&queue, 300, sonar_timeout, 0); |
kadonotakashi | 0:8fdf9a60065b | 126 | sonar_start(); |
kadonotakashi | 0:8fdf9a60065b | 127 | } |
kadonotakashi | 0:8fdf9a60065b | 128 | ``` |
kadonotakashi | 0:8fdf9a60065b | 129 | |
kadonotakashi | 0:8fdf9a60065b | 130 | From an architectural standpoint, event queues easily align with module |
kadonotakashi | 0:8fdf9a60065b | 131 | boundaries, where internal state can be implicitly synchronized through |
kadonotakashi | 0:8fdf9a60065b | 132 | event dispatch. |
kadonotakashi | 0:8fdf9a60065b | 133 | |
kadonotakashi | 0:8fdf9a60065b | 134 | On platforms where multiple threads are unavailable, multiple modules |
kadonotakashi | 0:8fdf9a60065b | 135 | can use independent event queues and still be composed through the |
kadonotakashi | 0:8fdf9a60065b | 136 | `equeue_chain` function. |
kadonotakashi | 0:8fdf9a60065b | 137 | |
kadonotakashi | 0:8fdf9a60065b | 138 | ``` c |
kadonotakashi | 0:8fdf9a60065b | 139 | #include "equeue.h" |
kadonotakashi | 0:8fdf9a60065b | 140 | |
kadonotakashi | 0:8fdf9a60065b | 141 | // run a simultaneous localization and mapping loop in one queue |
kadonotakashi | 0:8fdf9a60065b | 142 | struct slam { |
kadonotakashi | 0:8fdf9a60065b | 143 | equeue_t queue; |
kadonotakashi | 0:8fdf9a60065b | 144 | }; |
kadonotakashi | 0:8fdf9a60065b | 145 | |
kadonotakashi | 0:8fdf9a60065b | 146 | void slam_create(struct slam *s, equeue_t *target) { |
kadonotakashi | 0:8fdf9a60065b | 147 | equeue_create(&s->queue, 4096); |
kadonotakashi | 0:8fdf9a60065b | 148 | equeue_chain(&s->queue, target); |
kadonotakashi | 0:8fdf9a60065b | 149 | equeue_call_every(&s->queue, 100, slam_filter); |
kadonotakashi | 0:8fdf9a60065b | 150 | } |
kadonotakashi | 0:8fdf9a60065b | 151 | |
kadonotakashi | 0:8fdf9a60065b | 152 | // run a sonar with it's own queue |
kadonotakashi | 0:8fdf9a60065b | 153 | struct sonar { |
kadonotakashi | 0:8fdf9a60065b | 154 | equeue_t equeue; |
kadonotakashi | 0:8fdf9a60065b | 155 | struct slam *slam; |
kadonotakashi | 0:8fdf9a60065b | 156 | }; |
kadonotakashi | 0:8fdf9a60065b | 157 | |
kadonotakashi | 0:8fdf9a60065b | 158 | void sonar_create(struct sonar *s, equeue_t *target) { |
kadonotakashi | 0:8fdf9a60065b | 159 | equeue_create(&s->queue, 64); |
kadonotakashi | 0:8fdf9a60065b | 160 | equeue_chain(&s->queue, target); |
kadonotakashi | 0:8fdf9a60065b | 161 | equeue_call_in(&s->queue, 5, sonar_update, s); |
kadonotakashi | 0:8fdf9a60065b | 162 | } |
kadonotakashi | 0:8fdf9a60065b | 163 | |
kadonotakashi | 0:8fdf9a60065b | 164 | // all of the above queues can be combined into a single thread of execution |
kadonotakashi | 0:8fdf9a60065b | 165 | int main() { |
kadonotakashi | 0:8fdf9a60065b | 166 | equeue_t queue; |
kadonotakashi | 0:8fdf9a60065b | 167 | equeue_create(&queue, 1024); |
kadonotakashi | 0:8fdf9a60065b | 168 | |
kadonotakashi | 0:8fdf9a60065b | 169 | struct sonar s1, s2, s3; |
kadonotakashi | 0:8fdf9a60065b | 170 | sonar_create(&s1, &queue); |
kadonotakashi | 0:8fdf9a60065b | 171 | sonar_create(&s2, &queue); |
kadonotakashi | 0:8fdf9a60065b | 172 | sonar_create(&s3, &queue); |
kadonotakashi | 0:8fdf9a60065b | 173 | |
kadonotakashi | 0:8fdf9a60065b | 174 | struct slam slam; |
kadonotakashi | 0:8fdf9a60065b | 175 | slam_create(&slam, &queue); |
kadonotakashi | 0:8fdf9a60065b | 176 | |
kadonotakashi | 0:8fdf9a60065b | 177 | // dispatches events from all of the modules |
kadonotakashi | 0:8fdf9a60065b | 178 | equeue_dispatch(&queue, -1); |
kadonotakashi | 0:8fdf9a60065b | 179 | } |
kadonotakashi | 0:8fdf9a60065b | 180 | ``` |
kadonotakashi | 0:8fdf9a60065b | 181 | |
kadonotakashi | 0:8fdf9a60065b | 182 | ## Platform ## |
kadonotakashi | 0:8fdf9a60065b | 183 | |
kadonotakashi | 0:8fdf9a60065b | 184 | The equeue library has a minimal porting layer that is flexible depending |
kadonotakashi | 0:8fdf9a60065b | 185 | on the requirements of the underlying platform. Platform specific declarations |
kadonotakashi | 0:8fdf9a60065b | 186 | and more information can be found in [equeue_platform.h](equeue_platform.h). |
kadonotakashi | 0:8fdf9a60065b | 187 | |
kadonotakashi | 0:8fdf9a60065b | 188 | ## Tests ## |
kadonotakashi | 0:8fdf9a60065b | 189 | |
kadonotakashi | 0:8fdf9a60065b | 190 | The equeue library uses a set of local tests based on the posix implementation. |
kadonotakashi | 0:8fdf9a60065b | 191 | |
kadonotakashi | 0:8fdf9a60065b | 192 | Runtime tests are located in [tests.c](tests/tests.c): |
kadonotakashi | 0:8fdf9a60065b | 193 | |
kadonotakashi | 0:8fdf9a60065b | 194 | ``` bash |
kadonotakashi | 0:8fdf9a60065b | 195 | make test |
kadonotakashi | 0:8fdf9a60065b | 196 | ``` |
kadonotakashi | 0:8fdf9a60065b | 197 | |
kadonotakashi | 0:8fdf9a60065b | 198 | Profiling tests based on rdtsc are located in [prof.c](tests/prof.c): |
kadonotakashi | 0:8fdf9a60065b | 199 | |
kadonotakashi | 0:8fdf9a60065b | 200 | ``` bash |
kadonotakashi | 0:8fdf9a60065b | 201 | make prof |
kadonotakashi | 0:8fdf9a60065b | 202 | ``` |
kadonotakashi | 0:8fdf9a60065b | 203 | |
kadonotakashi | 0:8fdf9a60065b | 204 | To make profiling results more tangible, the profiler also supports percentage |
kadonotakashi | 0:8fdf9a60065b | 205 | comparison with previous runs: |
kadonotakashi | 0:8fdf9a60065b | 206 | ``` bash |
kadonotakashi | 0:8fdf9a60065b | 207 | make prof | tee results.txt |
kadonotakashi | 0:8fdf9a60065b | 208 | cat results.txt | make prof |
kadonotakashi | 0:8fdf9a60065b | 209 | ``` |
kadonotakashi | 0:8fdf9a60065b | 210 |