Mistake on this page?
Report an issue in GitHub or email us
equeue.h
1 
2 /*
3  * Flexible event queue for dispatching events
4  *
5  * Copyright (c) 2016-2019 ARM Limited
6  * SPDX-License-Identifier: Apache-2.0
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 #ifndef EQUEUE_H
21 #define EQUEUE_H
22 
23 #ifdef __cplusplus
24 extern "C" {
25 #endif
26 
27 // Platform specific files
28 #include "events/internal/equeue_platform.h"
29 
30 #include <stddef.h>
31 #include <stdint.h>
32 
33 /**
34  * \addtogroup events-public-api
35  * @{
36  */
37 
38 // The minimum size of an event
39 // This size is guaranteed to fit events created by event_call
40 #define EQUEUE_EVENT_SIZE (sizeof(struct equeue_event) + 2*sizeof(void*))
41 
42 // Internal event structure
43 struct equeue_event {
44  unsigned size;
45  uint8_t id;
46  uint8_t generation;
47 
48  struct equeue_event *next;
49  struct equeue_event *sibling;
50  struct equeue_event **ref;
51 
52  unsigned target;
53  int period;
54  void (*dtor)(void *);
55 
56  void (*cb)(void *);
57  // data follows
58 };
59 
60 // Event queue structure
61 typedef struct equeue {
62  struct equeue_event *queue;
63  unsigned tick;
64  bool break_requested;
65  uint8_t generation;
66 
67  unsigned char *buffer;
68  unsigned npw2;
69  void *allocated;
70 
71  struct equeue_event *chunks;
72  struct equeue_slab {
73  size_t size;
74  unsigned char *data;
75  } slab;
76 
78  bool active;
79  void (*update)(void *timer, int ms);
80  void *timer;
81  } background;
82 
83  equeue_sema_t eventsema;
84  equeue_mutex_t queuelock;
85  equeue_mutex_t memlock;
86 } equeue_t;
87 
88 
89 // Queue lifetime operations
90 //
91 // Creates and destroys an event queue. The event queue either allocates a
92 // buffer of the specified size with malloc or uses a user provided buffer
93 // if constructed with equeue_create_inplace.
94 //
95 // If the event queue creation fails, equeue_create returns a negative,
96 // platform-specific error code.
97 //
98 // If queues are chained, it is needed to unchain them first, before calling destroy,
99 // or call the destroy function on queues in order that chained queues are destroyed first.
100 int equeue_create(equeue_t *queue, size_t size);
101 int equeue_create_inplace(equeue_t *queue, size_t size, void *buffer);
102 void equeue_destroy(equeue_t *queue);
103 
104 // Dispatch events
105 //
106 // Executes events until the specified milliseconds have passed. If ms is
107 // negative, equeue_dispatch will dispatch events indefinitely or until
108 // equeue_break is called on this queue.
109 //
110 // When called with a finite timeout, the equeue_dispatch function is
111 // guaranteed to terminate. When called with a timeout of 0, the
112 // equeue_dispatch does not wait and is irq safe.
113 void equeue_dispatch(equeue_t *queue, int ms);
114 
115 // Break out of a running event loop
116 //
117 // Forces the specified event queue's dispatch loop to terminate. Pending
118 // events may finish executing, but no new events will be executed.
119 void equeue_break(equeue_t *queue);
120 
121 // Simple event calls
122 //
123 // The specified callback will be executed in the context of the event queue's
124 // dispatch loop. When the callback is executed depends on the call function.
125 //
126 // equeue_call - Immediately post an event to the queue
127 // equeue_call_in - Post an event after a specified time in milliseconds
128 // equeue_call_every - Post an event periodically every milliseconds
129 //
130 // All equeue_call functions are irq safe and can act as a mechanism for
131 // moving events out of irq contexts.
132 //
133 // The return value is a unique id that represents the posted event and can
134 // be passed to equeue_cancel. If there is not enough memory to allocate the
135 // event, equeue_call returns an id of 0.
136 int equeue_call(equeue_t *queue, void (*cb)(void *), void *data);
137 int equeue_call_in(equeue_t *queue, int ms, void (*cb)(void *), void *data);
138 int equeue_call_every(equeue_t *queue, int ms, void (*cb)(void *), void *data);
139 
140 // Allocate memory for events
141 //
142 // The equeue_alloc function allocates an event that can be manually dispatched
143 // with equeue_post. The equeue_dealloc function may be used to free an event
144 // that has not been posted. Once posted, an event's memory is managed by the
145 // event queue and should not be deallocated.
146 //
147 // Both equeue_alloc and equeue_dealloc are irq safe.
148 //
149 // The equeue allocator is designed to minimize jitter in interrupt contexts as
150 // well as avoid memory fragmentation on small devices. The allocator achieves
151 // both constant-runtime and zero-fragmentation for fixed-size events, however
152 // grows linearly as the quantity of different sized allocations increases.
153 //
154 // The equeue_alloc function returns a pointer to the event's allocated memory
155 // and acts as a handle to the underlying event. If there is not enough memory
156 // to allocate the event, equeue_alloc returns null.
157 void *equeue_alloc(equeue_t *queue, size_t size);
158 void equeue_dealloc(equeue_t *queue, void *event);
159 
160 // Configure an allocated event
161 //
162 // equeue_event_delay - Millisecond delay before dispatching an event
163 // equeue_event_period - Millisecond period for repeating dispatching an event
164 // equeue_event_dtor - Destructor to run when the event is deallocated
165 void equeue_event_delay(void *event, int ms);
166 void equeue_event_period(void *event, int ms);
167 void equeue_event_dtor(void *event, void (*dtor)(void *));
168 
169 // Post an event onto the event queue
170 //
171 // The equeue_post function takes a callback and a pointer to an event
172 // allocated by equeue_alloc. The specified callback will be executed in the
173 // context of the event queue's dispatch loop with the allocated event
174 // as its argument.
175 //
176 // The equeue_post function is irq safe and can act as a mechanism for
177 // moving events out of irq contexts.
178 //
179 // The return value is a unique id that represents the posted event and can
180 // be passed to equeue_cancel.
181 int equeue_post(equeue_t *queue, void (*cb)(void *), void *event);
182 
183 // Post an user allocated event onto the event queue
184 //
185 // The equeue_post_user_allocated function takes a callback and a pointer
186 // to an event allocated by user. The specified callback will be executed
187 // in the context of the event queue's dispatch loop with the allocated
188 // event as its argument.
189 //
190 // The equeue_post_user_allocated function is irq safe and can act as
191 // a mechanism for moving events out of irq contexts.
192 void equeue_post_user_allocated(equeue_t *queue, void (*cb)(void *), void *event);
193 
194 // Cancel an in-flight event
195 //
196 // Attempts to cancel an event referenced by the unique id returned from
197 // equeue_call or equeue_post. It is safe to call equeue_cancel after an event
198 // has already been dispatched.
199 //
200 // The equeue_cancel function is irq safe.
201 //
202 // If called while the event queue's dispatch loop is active in another thread,
203 // equeue_cancel does not guarantee that the event will not execute after it returns as
204 // the event may have already begun executing.
205 // Returning true guarantees that cancel succeeded and event will not execute.
206 // Returning false if invalid id or already started executing.
207 bool equeue_cancel(equeue_t *queue, int id);
208 
209 // Cancel an in-flight user allocated event
210 //
211 // Attempts to cancel an event referenced by its address.
212 // It is safe to call equeue_cancel_user_allocated after an event
213 // has already been dispatched.
214 //
215 // The equeue_cancel_user_allocated function is irq safe.
216 //
217 // If called while the event queue's dispatch loop is active,
218 // equeue_cancel_user_allocated does not guarantee that the event
219 // will not not execute after it returns as the event may have
220 // already begun executing.
221 bool equeue_cancel_user_allocated(equeue_t *queue, void *event);
222 
223 // Query how much time is left for delayed event
224 //
225 // If event is delayed, this function can be used to query how much time
226 // is left until the event is due to be dispatched.
227 //
228 // This function is irq safe.
229 //
230 int equeue_timeleft(equeue_t *q, int id);
231 
232 // Query how much time is left for delayed user allocated event
233 //
234 // If event is delayed, this function can be used to query how much time
235 // is left until the event is due to be dispatched.
236 //
237 // This function is irq safe.
238 //
239 int equeue_timeleft_user_allocated(equeue_t *q, void *event);
240 
241 // Background an event queue onto a single-shot timer
242 //
243 // The provided update function will be called to indicate when the queue
244 // should be dispatched. A negative timeout will be passed to the update
245 // function when the timer is no longer needed.
246 //
247 // Passing a null update function disables the existing timer.
248 //
249 // The equeue_background function allows an event queue to take advantage
250 // of hardware timers or even other event loops, allowing an event queue to
251 // be effectively backgrounded.
252 void equeue_background(equeue_t *queue,
253  void (*update)(void *timer, int ms), void *timer);
254 
255 // Chain an event queue onto another event queue
256 //
257 // After chaining a queue to a target, calling equeue_dispatch on the
258 // target queue will also dispatch events from this queue. The queues
259 // use their own buffers and events must be managed independently.
260 //
261 // Passing a null queue as the target will unchain the existing queue.
262 //
263 // The equeue_chain function allows multiple equeues to be composed, sharing
264 // the context of a dispatch loop while still being managed independently.
265 //
266 // If the event queue chaining fails, equeue_chain returns a negative,
267 // platform-specific error code.
268 int equeue_chain(equeue_t *queue, equeue_t *target);
269 
270 /** @}*/
271 
272 #ifdef __cplusplus
273 }
274 #endif
275 
276 #endif
Definition: equeue.h:61
Important Information for this Arm website

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies. If you are not happy with the use of these cookies, please review our Cookie Policy to learn how they can be disabled. By disabling cookies, some features of the site will not work.