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.c@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:
- 3:3d3560169945
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 | */ |
Sam Grove |
2:a60d8117d0e0 | 18 | #include "equeue/equeue.h" |
Bogdan Marinescu |
0:a792d4bf36c2 | 19 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 20 | #include <stdlib.h> |
Bogdan Marinescu |
0:a792d4bf36c2 | 21 | #include <string.h> |
Bogdan Marinescu |
0:a792d4bf36c2 | 22 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 23 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 24 | // calculate the relative-difference between absolute times while |
Bogdan Marinescu |
0:a792d4bf36c2 | 25 | // correctly handling overflow conditions |
Bogdan Marinescu |
0:a792d4bf36c2 | 26 | static inline int equeue_tickdiff(unsigned a, unsigned b) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 27 | return (int)(a - b); |
Bogdan Marinescu |
0:a792d4bf36c2 | 28 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 29 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 30 | // calculate the relative-difference between absolute times, but |
Bogdan Marinescu |
0:a792d4bf36c2 | 31 | // also clamp to zero, resulting in only non-zero values. |
Bogdan Marinescu |
0:a792d4bf36c2 | 32 | static inline int equeue_clampdiff(unsigned a, unsigned b) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 33 | int diff = equeue_tickdiff(a, b); |
Bogdan Marinescu |
0:a792d4bf36c2 | 34 | return ~(diff >> (8*sizeof(int)-1)) & diff; |
Bogdan Marinescu |
0:a792d4bf36c2 | 35 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 36 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 37 | // Increment the unique id in an event, hiding the event from cancel |
Bogdan Marinescu |
0:a792d4bf36c2 | 38 | static inline void equeue_incid(equeue_t *q, struct equeue_event *e) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 39 | e->id += 1; |
Bogdan Marinescu |
0:a792d4bf36c2 | 40 | if (!(e->id << q->npw2)) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 41 | e->id = 1; |
Bogdan Marinescu |
0:a792d4bf36c2 | 42 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 43 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 44 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 45 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 46 | // equeue lifetime management |
Bogdan Marinescu |
0:a792d4bf36c2 | 47 | int equeue_create(equeue_t *q, size_t size) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 48 | // dynamically allocate the specified buffer |
Bogdan Marinescu |
0:a792d4bf36c2 | 49 | void *buffer = malloc(size); |
Bogdan Marinescu |
0:a792d4bf36c2 | 50 | if (!buffer) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 51 | return -1; |
Bogdan Marinescu |
0:a792d4bf36c2 | 52 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 53 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 54 | int err = equeue_create_inplace(q, size, buffer); |
Bogdan Marinescu |
0:a792d4bf36c2 | 55 | q->allocated = buffer; |
Bogdan Marinescu |
0:a792d4bf36c2 | 56 | return err; |
Bogdan Marinescu |
0:a792d4bf36c2 | 57 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 58 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 59 | int equeue_create_inplace(equeue_t *q, size_t size, void *buffer) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 60 | // setup queue around provided buffer |
Bogdan Marinescu |
0:a792d4bf36c2 | 61 | q->buffer = buffer; |
Bogdan Marinescu |
0:a792d4bf36c2 | 62 | q->allocated = 0; |
Bogdan Marinescu |
0:a792d4bf36c2 | 63 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 64 | q->npw2 = 0; |
Bogdan Marinescu |
0:a792d4bf36c2 | 65 | for (unsigned s = size; s; s >>= 1) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 66 | q->npw2++; |
Bogdan Marinescu |
0:a792d4bf36c2 | 67 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 68 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 69 | q->chunks = 0; |
Bogdan Marinescu |
0:a792d4bf36c2 | 70 | q->slab.size = size; |
Bogdan Marinescu |
0:a792d4bf36c2 | 71 | q->slab.data = buffer; |
Bogdan Marinescu |
0:a792d4bf36c2 | 72 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 73 | q->queue = 0; |
Bogdan Marinescu |
0:a792d4bf36c2 | 74 | q->tick = equeue_tick(); |
Bogdan Marinescu |
0:a792d4bf36c2 | 75 | q->generation = 0; |
Bogdan Marinescu |
0:a792d4bf36c2 | 76 | q->breaks = 0; |
Bogdan Marinescu |
0:a792d4bf36c2 | 77 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 78 | q->background.active = false; |
Bogdan Marinescu |
0:a792d4bf36c2 | 79 | q->background.update = 0; |
Bogdan Marinescu |
0:a792d4bf36c2 | 80 | q->background.timer = 0; |
Bogdan Marinescu |
0:a792d4bf36c2 | 81 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 82 | // initialize platform resources |
Bogdan Marinescu |
0:a792d4bf36c2 | 83 | int err; |
Bogdan Marinescu |
0:a792d4bf36c2 | 84 | err = equeue_sema_create(&q->eventsema); |
Bogdan Marinescu |
0:a792d4bf36c2 | 85 | if (err < 0) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 86 | return err; |
Bogdan Marinescu |
0:a792d4bf36c2 | 87 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 88 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 89 | err = equeue_mutex_create(&q->queuelock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 90 | if (err < 0) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 91 | return err; |
Bogdan Marinescu |
0:a792d4bf36c2 | 92 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 93 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 94 | err = equeue_mutex_create(&q->memlock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 95 | if (err < 0) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 96 | return err; |
Bogdan Marinescu |
0:a792d4bf36c2 | 97 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 98 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 99 | return 0; |
Bogdan Marinescu |
0:a792d4bf36c2 | 100 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 101 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 102 | void equeue_destroy(equeue_t *q) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 103 | // call destructors on pending events |
Bogdan Marinescu |
0:a792d4bf36c2 | 104 | for (struct equeue_event *es = q->queue; es; es = es->next) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 105 | for (struct equeue_event *e = q->queue; e; e = e->sibling) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 106 | if (e->dtor) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 107 | e->dtor(e + 1); |
Bogdan Marinescu |
0:a792d4bf36c2 | 108 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 109 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 110 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 111 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 112 | // notify background timer |
Bogdan Marinescu |
0:a792d4bf36c2 | 113 | if (q->background.update) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 114 | q->background.update(q->background.timer, -1); |
Bogdan Marinescu |
0:a792d4bf36c2 | 115 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 116 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 117 | // clean up platform resources + memory |
Bogdan Marinescu |
0:a792d4bf36c2 | 118 | equeue_mutex_destroy(&q->memlock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 119 | equeue_mutex_destroy(&q->queuelock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 120 | equeue_sema_destroy(&q->eventsema); |
Bogdan Marinescu |
0:a792d4bf36c2 | 121 | free(q->allocated); |
Bogdan Marinescu |
0:a792d4bf36c2 | 122 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 123 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 124 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 125 | // equeue chunk allocation functions |
Bogdan Marinescu |
0:a792d4bf36c2 | 126 | static struct equeue_event *equeue_mem_alloc(equeue_t *q, size_t size) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 127 | // add event overhead |
Bogdan Marinescu |
0:a792d4bf36c2 | 128 | size += sizeof(struct equeue_event); |
Bogdan Marinescu |
0:a792d4bf36c2 | 129 | size = (size + sizeof(void*)-1) & ~(sizeof(void*)-1); |
Bogdan Marinescu |
0:a792d4bf36c2 | 130 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 131 | equeue_mutex_lock(&q->memlock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 132 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 133 | // check if a good chunk is available |
Bogdan Marinescu |
0:a792d4bf36c2 | 134 | for (struct equeue_event **p = &q->chunks; *p; p = &(*p)->next) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 135 | if ((*p)->size >= size) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 136 | struct equeue_event *e = *p; |
Bogdan Marinescu |
0:a792d4bf36c2 | 137 | if (e->sibling) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 138 | *p = e->sibling; |
Bogdan Marinescu |
0:a792d4bf36c2 | 139 | (*p)->next = e->next; |
Bogdan Marinescu |
0:a792d4bf36c2 | 140 | } else { |
Bogdan Marinescu |
0:a792d4bf36c2 | 141 | *p = e->next; |
Bogdan Marinescu |
0:a792d4bf36c2 | 142 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 143 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 144 | equeue_mutex_unlock(&q->memlock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 145 | return e; |
Bogdan Marinescu |
0:a792d4bf36c2 | 146 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 147 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 148 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 149 | // otherwise allocate a new chunk out of the slab |
Bogdan Marinescu |
0:a792d4bf36c2 | 150 | if (q->slab.size >= size) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 151 | struct equeue_event *e = (struct equeue_event *)q->slab.data; |
Bogdan Marinescu |
0:a792d4bf36c2 | 152 | q->slab.data += size; |
Bogdan Marinescu |
0:a792d4bf36c2 | 153 | q->slab.size -= size; |
Bogdan Marinescu |
0:a792d4bf36c2 | 154 | e->size = size; |
Bogdan Marinescu |
0:a792d4bf36c2 | 155 | e->id = 1; |
Bogdan Marinescu |
0:a792d4bf36c2 | 156 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 157 | equeue_mutex_unlock(&q->memlock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 158 | return e; |
Bogdan Marinescu |
0:a792d4bf36c2 | 159 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 160 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 161 | equeue_mutex_unlock(&q->memlock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 162 | return 0; |
Bogdan Marinescu |
0:a792d4bf36c2 | 163 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 164 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 165 | static void equeue_mem_dealloc(equeue_t *q, struct equeue_event *e) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 166 | equeue_mutex_lock(&q->memlock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 167 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 168 | // stick chunk into list of chunks |
Bogdan Marinescu |
0:a792d4bf36c2 | 169 | struct equeue_event **p = &q->chunks; |
Bogdan Marinescu |
0:a792d4bf36c2 | 170 | while (*p && (*p)->size < e->size) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 171 | p = &(*p)->next; |
Bogdan Marinescu |
0:a792d4bf36c2 | 172 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 173 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 174 | if (*p && (*p)->size == e->size) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 175 | e->sibling = *p; |
Bogdan Marinescu |
0:a792d4bf36c2 | 176 | e->next = (*p)->next; |
Bogdan Marinescu |
0:a792d4bf36c2 | 177 | } else { |
Bogdan Marinescu |
0:a792d4bf36c2 | 178 | e->sibling = 0; |
Bogdan Marinescu |
0:a792d4bf36c2 | 179 | e->next = *p; |
Bogdan Marinescu |
0:a792d4bf36c2 | 180 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 181 | *p = e; |
Bogdan Marinescu |
0:a792d4bf36c2 | 182 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 183 | equeue_mutex_unlock(&q->memlock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 184 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 185 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 186 | void *equeue_alloc(equeue_t *q, size_t size) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 187 | struct equeue_event *e = equeue_mem_alloc(q, size); |
Bogdan Marinescu |
0:a792d4bf36c2 | 188 | if (!e) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 189 | return 0; |
Bogdan Marinescu |
0:a792d4bf36c2 | 190 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 191 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 192 | e->target = 0; |
Bogdan Marinescu |
0:a792d4bf36c2 | 193 | e->period = -1; |
Bogdan Marinescu |
0:a792d4bf36c2 | 194 | e->dtor = 0; |
Bogdan Marinescu |
0:a792d4bf36c2 | 195 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 196 | return e + 1; |
Bogdan Marinescu |
0:a792d4bf36c2 | 197 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 198 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 199 | void equeue_dealloc(equeue_t *q, void *p) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 200 | struct equeue_event *e = (struct equeue_event*)p - 1; |
Bogdan Marinescu |
0:a792d4bf36c2 | 201 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 202 | if (e->dtor) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 203 | e->dtor(e+1); |
Bogdan Marinescu |
0:a792d4bf36c2 | 204 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 205 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 206 | equeue_mem_dealloc(q, e); |
Bogdan Marinescu |
0:a792d4bf36c2 | 207 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 208 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 209 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 210 | // equeue scheduling functions |
Bogdan Marinescu |
0:a792d4bf36c2 | 211 | static int equeue_enqueue(equeue_t *q, struct equeue_event *e, unsigned tick) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 212 | // setup event and hash local id with buffer offset for unique id |
Bogdan Marinescu |
0:a792d4bf36c2 | 213 | int id = (e->id << q->npw2) | ((unsigned char *)e - q->buffer); |
Bogdan Marinescu |
0:a792d4bf36c2 | 214 | e->target = tick + equeue_clampdiff(e->target, tick); |
Bogdan Marinescu |
0:a792d4bf36c2 | 215 | e->generation = q->generation; |
Bogdan Marinescu |
0:a792d4bf36c2 | 216 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 217 | equeue_mutex_lock(&q->queuelock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 218 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 219 | // find the event slot |
Bogdan Marinescu |
0:a792d4bf36c2 | 220 | struct equeue_event **p = &q->queue; |
Bogdan Marinescu |
0:a792d4bf36c2 | 221 | while (*p && equeue_tickdiff((*p)->target, e->target) < 0) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 222 | p = &(*p)->next; |
Bogdan Marinescu |
0:a792d4bf36c2 | 223 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 224 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 225 | // insert at head in slot |
Bogdan Marinescu |
0:a792d4bf36c2 | 226 | if (*p && (*p)->target == e->target) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 227 | e->next = (*p)->next; |
Bogdan Marinescu |
0:a792d4bf36c2 | 228 | if (e->next) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 229 | e->next->ref = &e->next; |
Bogdan Marinescu |
0:a792d4bf36c2 | 230 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 231 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 232 | e->sibling = *p; |
Bogdan Marinescu |
0:a792d4bf36c2 | 233 | e->sibling->ref = &e->sibling; |
Bogdan Marinescu |
0:a792d4bf36c2 | 234 | } else { |
Bogdan Marinescu |
0:a792d4bf36c2 | 235 | e->next = *p; |
Bogdan Marinescu |
0:a792d4bf36c2 | 236 | if (e->next) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 237 | e->next->ref = &e->next; |
Bogdan Marinescu |
0:a792d4bf36c2 | 238 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 239 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 240 | e->sibling = 0; |
Bogdan Marinescu |
0:a792d4bf36c2 | 241 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 242 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 243 | *p = e; |
Bogdan Marinescu |
0:a792d4bf36c2 | 244 | e->ref = p; |
Bogdan Marinescu |
0:a792d4bf36c2 | 245 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 246 | // notify background timer |
Bogdan Marinescu |
0:a792d4bf36c2 | 247 | if ((q->background.update && q->background.active) && |
Bogdan Marinescu |
0:a792d4bf36c2 | 248 | (q->queue == e && !e->sibling)) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 249 | q->background.update(q->background.timer, |
Bogdan Marinescu |
0:a792d4bf36c2 | 250 | equeue_clampdiff(e->target, tick)); |
Bogdan Marinescu |
0:a792d4bf36c2 | 251 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 252 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 253 | equeue_mutex_unlock(&q->queuelock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 254 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 255 | return id; |
Bogdan Marinescu |
0:a792d4bf36c2 | 256 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 257 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 258 | static struct equeue_event *equeue_unqueue(equeue_t *q, int id) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 259 | // decode event from unique id and check that the local id matches |
Bogdan Marinescu |
0:a792d4bf36c2 | 260 | struct equeue_event *e = (struct equeue_event *) |
Bogdan Marinescu |
0:a792d4bf36c2 | 261 | &q->buffer[id & ((1 << q->npw2)-1)]; |
Bogdan Marinescu |
0:a792d4bf36c2 | 262 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 263 | equeue_mutex_lock(&q->queuelock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 264 | if (e->id != id >> q->npw2) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 265 | equeue_mutex_unlock(&q->queuelock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 266 | return 0; |
Bogdan Marinescu |
0:a792d4bf36c2 | 267 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 268 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 269 | // clear the event and check if already in-flight |
Bogdan Marinescu |
0:a792d4bf36c2 | 270 | e->cb = 0; |
Bogdan Marinescu |
0:a792d4bf36c2 | 271 | e->period = -1; |
Bogdan Marinescu |
0:a792d4bf36c2 | 272 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 273 | int diff = equeue_tickdiff(e->target, q->tick); |
Bogdan Marinescu |
0:a792d4bf36c2 | 274 | if (diff < 0 || (diff == 0 && e->generation != q->generation)) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 275 | equeue_mutex_unlock(&q->queuelock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 276 | return 0; |
Bogdan Marinescu |
0:a792d4bf36c2 | 277 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 278 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 279 | // disentangle from queue |
Bogdan Marinescu |
0:a792d4bf36c2 | 280 | if (e->sibling) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 281 | e->sibling->next = e->next; |
Bogdan Marinescu |
0:a792d4bf36c2 | 282 | if (e->sibling->next) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 283 | e->sibling->next->ref = &e->sibling->next; |
Bogdan Marinescu |
0:a792d4bf36c2 | 284 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 285 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 286 | *e->ref = e->sibling; |
Bogdan Marinescu |
0:a792d4bf36c2 | 287 | e->sibling->ref = e->ref; |
Bogdan Marinescu |
0:a792d4bf36c2 | 288 | } else { |
Bogdan Marinescu |
0:a792d4bf36c2 | 289 | *e->ref = e->next; |
Bogdan Marinescu |
0:a792d4bf36c2 | 290 | if (e->next) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 291 | e->next->ref = e->ref; |
Bogdan Marinescu |
0:a792d4bf36c2 | 292 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 293 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 294 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 295 | equeue_incid(q, e); |
Bogdan Marinescu |
0:a792d4bf36c2 | 296 | equeue_mutex_unlock(&q->queuelock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 297 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 298 | return e; |
Bogdan Marinescu |
0:a792d4bf36c2 | 299 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 300 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 301 | static struct equeue_event *equeue_dequeue(equeue_t *q, unsigned target) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 302 | equeue_mutex_lock(&q->queuelock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 303 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 304 | // find all expired events and mark a new generation |
Bogdan Marinescu |
0:a792d4bf36c2 | 305 | q->generation += 1; |
Bogdan Marinescu |
0:a792d4bf36c2 | 306 | if (equeue_tickdiff(q->tick, target) <= 0) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 307 | q->tick = target; |
Bogdan Marinescu |
0:a792d4bf36c2 | 308 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 309 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 310 | struct equeue_event *head = q->queue; |
Bogdan Marinescu |
0:a792d4bf36c2 | 311 | struct equeue_event **p = &head; |
Bogdan Marinescu |
0:a792d4bf36c2 | 312 | while (*p && equeue_tickdiff((*p)->target, target) <= 0) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 313 | p = &(*p)->next; |
Bogdan Marinescu |
0:a792d4bf36c2 | 314 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 315 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 316 | q->queue = *p; |
Bogdan Marinescu |
0:a792d4bf36c2 | 317 | if (q->queue) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 318 | q->queue->ref = &q->queue; |
Bogdan Marinescu |
0:a792d4bf36c2 | 319 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 320 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 321 | *p = 0; |
Bogdan Marinescu |
0:a792d4bf36c2 | 322 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 323 | equeue_mutex_unlock(&q->queuelock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 324 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 325 | // reverse and flatten each slot to match insertion order |
Bogdan Marinescu |
0:a792d4bf36c2 | 326 | struct equeue_event **tail = &head; |
Bogdan Marinescu |
0:a792d4bf36c2 | 327 | struct equeue_event *ess = head; |
Bogdan Marinescu |
0:a792d4bf36c2 | 328 | while (ess) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 329 | struct equeue_event *es = ess; |
Bogdan Marinescu |
0:a792d4bf36c2 | 330 | ess = es->next; |
Bogdan Marinescu |
0:a792d4bf36c2 | 331 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 332 | struct equeue_event *prev = 0; |
Bogdan Marinescu |
0:a792d4bf36c2 | 333 | for (struct equeue_event *e = es; e; e = e->sibling) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 334 | e->next = prev; |
Bogdan Marinescu |
0:a792d4bf36c2 | 335 | prev = e; |
Bogdan Marinescu |
0:a792d4bf36c2 | 336 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 337 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 338 | *tail = prev; |
Bogdan Marinescu |
0:a792d4bf36c2 | 339 | tail = &es->next; |
Bogdan Marinescu |
0:a792d4bf36c2 | 340 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 341 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 342 | return head; |
Bogdan Marinescu |
0:a792d4bf36c2 | 343 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 344 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 345 | int equeue_post(equeue_t *q, void (*cb)(void*), void *p) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 346 | struct equeue_event *e = (struct equeue_event*)p - 1; |
Bogdan Marinescu |
0:a792d4bf36c2 | 347 | unsigned tick = equeue_tick(); |
Bogdan Marinescu |
0:a792d4bf36c2 | 348 | e->cb = cb; |
Bogdan Marinescu |
0:a792d4bf36c2 | 349 | e->target = tick + e->target; |
Bogdan Marinescu |
0:a792d4bf36c2 | 350 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 351 | int id = equeue_enqueue(q, e, tick); |
Bogdan Marinescu |
0:a792d4bf36c2 | 352 | equeue_sema_signal(&q->eventsema); |
Bogdan Marinescu |
0:a792d4bf36c2 | 353 | return id; |
Bogdan Marinescu |
0:a792d4bf36c2 | 354 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 355 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 356 | void equeue_cancel(equeue_t *q, int id) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 357 | if (!id) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 358 | return; |
Bogdan Marinescu |
0:a792d4bf36c2 | 359 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 360 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 361 | struct equeue_event *e = equeue_unqueue(q, id); |
Bogdan Marinescu |
0:a792d4bf36c2 | 362 | if (e) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 363 | equeue_dealloc(q, e + 1); |
Bogdan Marinescu |
0:a792d4bf36c2 | 364 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 365 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 366 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 367 | void equeue_break(equeue_t *q) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 368 | equeue_mutex_lock(&q->queuelock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 369 | q->breaks++; |
Bogdan Marinescu |
0:a792d4bf36c2 | 370 | equeue_mutex_unlock(&q->queuelock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 371 | equeue_sema_signal(&q->eventsema); |
Bogdan Marinescu |
0:a792d4bf36c2 | 372 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 373 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 374 | void equeue_dispatch(equeue_t *q, int ms) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 375 | unsigned tick = equeue_tick(); |
Bogdan Marinescu |
0:a792d4bf36c2 | 376 | unsigned timeout = tick + ms; |
Bogdan Marinescu |
0:a792d4bf36c2 | 377 | q->background.active = false; |
Bogdan Marinescu |
0:a792d4bf36c2 | 378 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 379 | while (1) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 380 | // collect all the available events and next deadline |
Bogdan Marinescu |
0:a792d4bf36c2 | 381 | struct equeue_event *es = equeue_dequeue(q, tick); |
Bogdan Marinescu |
0:a792d4bf36c2 | 382 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 383 | // dispatch events |
Bogdan Marinescu |
0:a792d4bf36c2 | 384 | while (es) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 385 | struct equeue_event *e = es; |
Bogdan Marinescu |
0:a792d4bf36c2 | 386 | es = e->next; |
Bogdan Marinescu |
0:a792d4bf36c2 | 387 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 388 | // actually dispatch the callbacks |
Bogdan Marinescu |
0:a792d4bf36c2 | 389 | void (*cb)(void *) = e->cb; |
Bogdan Marinescu |
0:a792d4bf36c2 | 390 | if (cb) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 391 | cb(e + 1); |
Bogdan Marinescu |
0:a792d4bf36c2 | 392 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 393 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 394 | // reenqueue periodic events or deallocate |
Bogdan Marinescu |
0:a792d4bf36c2 | 395 | if (e->period >= 0) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 396 | e->target += e->period; |
Bogdan Marinescu |
0:a792d4bf36c2 | 397 | equeue_enqueue(q, e, equeue_tick()); |
Bogdan Marinescu |
0:a792d4bf36c2 | 398 | } else { |
Bogdan Marinescu |
0:a792d4bf36c2 | 399 | equeue_incid(q, e); |
Bogdan Marinescu |
0:a792d4bf36c2 | 400 | equeue_dealloc(q, e+1); |
Bogdan Marinescu |
0:a792d4bf36c2 | 401 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 402 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 403 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 404 | int deadline = -1; |
Bogdan Marinescu |
0:a792d4bf36c2 | 405 | tick = equeue_tick(); |
Bogdan Marinescu |
0:a792d4bf36c2 | 406 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 407 | // check if we should stop dispatching soon |
Bogdan Marinescu |
0:a792d4bf36c2 | 408 | if (ms >= 0) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 409 | deadline = equeue_tickdiff(timeout, tick); |
Bogdan Marinescu |
0:a792d4bf36c2 | 410 | if (deadline <= 0) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 411 | // update background timer if necessary |
Bogdan Marinescu |
0:a792d4bf36c2 | 412 | if (q->background.update) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 413 | equeue_mutex_lock(&q->queuelock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 414 | if (q->background.update && q->queue) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 415 | q->background.update(q->background.timer, |
Bogdan Marinescu |
0:a792d4bf36c2 | 416 | equeue_clampdiff(q->queue->target, tick)); |
Bogdan Marinescu |
0:a792d4bf36c2 | 417 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 418 | q->background.active = true; |
Bogdan Marinescu |
0:a792d4bf36c2 | 419 | equeue_mutex_unlock(&q->queuelock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 420 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 421 | return; |
Bogdan Marinescu |
0:a792d4bf36c2 | 422 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 423 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 424 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 425 | // find closest deadline |
Bogdan Marinescu |
0:a792d4bf36c2 | 426 | equeue_mutex_lock(&q->queuelock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 427 | if (q->queue) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 428 | int diff = equeue_clampdiff(q->queue->target, tick); |
Bogdan Marinescu |
0:a792d4bf36c2 | 429 | if ((unsigned)diff < (unsigned)deadline) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 430 | deadline = diff; |
Bogdan Marinescu |
0:a792d4bf36c2 | 431 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 432 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 433 | equeue_mutex_unlock(&q->queuelock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 434 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 435 | // wait for events |
Bogdan Marinescu |
0:a792d4bf36c2 | 436 | equeue_sema_wait(&q->eventsema, deadline); |
Bogdan Marinescu |
0:a792d4bf36c2 | 437 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 438 | // check if we were notified to break out of dispatch |
Bogdan Marinescu |
0:a792d4bf36c2 | 439 | if (q->breaks) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 440 | equeue_mutex_lock(&q->queuelock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 441 | if (q->breaks > 0) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 442 | q->breaks--; |
Bogdan Marinescu |
0:a792d4bf36c2 | 443 | equeue_mutex_unlock(&q->queuelock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 444 | return; |
Bogdan Marinescu |
0:a792d4bf36c2 | 445 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 446 | equeue_mutex_unlock(&q->queuelock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 447 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 448 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 449 | // update tick for next iteration |
Bogdan Marinescu |
0:a792d4bf36c2 | 450 | tick = equeue_tick(); |
Bogdan Marinescu |
0:a792d4bf36c2 | 451 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 452 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 453 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 454 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 455 | // event functions |
Bogdan Marinescu |
0:a792d4bf36c2 | 456 | void equeue_event_delay(void *p, int ms) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 457 | struct equeue_event *e = (struct equeue_event*)p - 1; |
Bogdan Marinescu |
0:a792d4bf36c2 | 458 | e->target = ms; |
Bogdan Marinescu |
0:a792d4bf36c2 | 459 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 460 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 461 | void equeue_event_period(void *p, int ms) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 462 | struct equeue_event *e = (struct equeue_event*)p - 1; |
Bogdan Marinescu |
0:a792d4bf36c2 | 463 | e->period = ms; |
Bogdan Marinescu |
0:a792d4bf36c2 | 464 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 465 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 466 | void equeue_event_dtor(void *p, void (*dtor)(void *)) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 467 | struct equeue_event *e = (struct equeue_event*)p - 1; |
Bogdan Marinescu |
0:a792d4bf36c2 | 468 | e->dtor = dtor; |
Bogdan Marinescu |
0:a792d4bf36c2 | 469 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 470 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 471 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 472 | // simple callbacks |
Bogdan Marinescu |
0:a792d4bf36c2 | 473 | struct ecallback { |
Bogdan Marinescu |
0:a792d4bf36c2 | 474 | void (*cb)(void*); |
Bogdan Marinescu |
0:a792d4bf36c2 | 475 | void *data; |
Bogdan Marinescu |
0:a792d4bf36c2 | 476 | }; |
Bogdan Marinescu |
0:a792d4bf36c2 | 477 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 478 | static void ecallback_dispatch(void *p) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 479 | struct ecallback *e = (struct ecallback*)p; |
Bogdan Marinescu |
0:a792d4bf36c2 | 480 | e->cb(e->data); |
Bogdan Marinescu |
0:a792d4bf36c2 | 481 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 482 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 483 | int equeue_call(equeue_t *q, void (*cb)(void*), void *data) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 484 | struct ecallback *e = equeue_alloc(q, sizeof(struct ecallback)); |
Bogdan Marinescu |
0:a792d4bf36c2 | 485 | if (!e) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 486 | return 0; |
Bogdan Marinescu |
0:a792d4bf36c2 | 487 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 488 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 489 | e->cb = cb; |
Bogdan Marinescu |
0:a792d4bf36c2 | 490 | e->data = data; |
Bogdan Marinescu |
0:a792d4bf36c2 | 491 | return equeue_post(q, ecallback_dispatch, e); |
Bogdan Marinescu |
0:a792d4bf36c2 | 492 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 493 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 494 | int equeue_call_in(equeue_t *q, int ms, void (*cb)(void*), void *data) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 495 | struct ecallback *e = equeue_alloc(q, sizeof(struct ecallback)); |
Bogdan Marinescu |
0:a792d4bf36c2 | 496 | if (!e) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 497 | return 0; |
Bogdan Marinescu |
0:a792d4bf36c2 | 498 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 499 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 500 | equeue_event_delay(e, ms); |
Bogdan Marinescu |
0:a792d4bf36c2 | 501 | e->cb = cb; |
Bogdan Marinescu |
0:a792d4bf36c2 | 502 | e->data = data; |
Bogdan Marinescu |
0:a792d4bf36c2 | 503 | return equeue_post(q, ecallback_dispatch, e); |
Bogdan Marinescu |
0:a792d4bf36c2 | 504 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 505 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 506 | int equeue_call_every(equeue_t *q, int ms, void (*cb)(void*), void *data) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 507 | struct ecallback *e = equeue_alloc(q, sizeof(struct ecallback)); |
Bogdan Marinescu |
0:a792d4bf36c2 | 508 | if (!e) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 509 | return 0; |
Bogdan Marinescu |
0:a792d4bf36c2 | 510 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 511 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 512 | equeue_event_delay(e, ms); |
Bogdan Marinescu |
0:a792d4bf36c2 | 513 | equeue_event_period(e, ms); |
Bogdan Marinescu |
0:a792d4bf36c2 | 514 | e->cb = cb; |
Bogdan Marinescu |
0:a792d4bf36c2 | 515 | e->data = data; |
Bogdan Marinescu |
0:a792d4bf36c2 | 516 | return equeue_post(q, ecallback_dispatch, e); |
Bogdan Marinescu |
0:a792d4bf36c2 | 517 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 518 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 519 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 520 | // backgrounding |
Bogdan Marinescu |
0:a792d4bf36c2 | 521 | void equeue_background(equeue_t *q, |
Bogdan Marinescu |
0:a792d4bf36c2 | 522 | void (*update)(void *timer, int ms), void *timer) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 523 | equeue_mutex_lock(&q->queuelock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 524 | if (q->background.update) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 525 | q->background.update(q->background.timer, -1); |
Bogdan Marinescu |
0:a792d4bf36c2 | 526 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 527 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 528 | q->background.update = update; |
Bogdan Marinescu |
0:a792d4bf36c2 | 529 | q->background.timer = timer; |
Bogdan Marinescu |
0:a792d4bf36c2 | 530 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 531 | if (q->background.update && q->queue) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 532 | q->background.update(q->background.timer, |
Bogdan Marinescu |
0:a792d4bf36c2 | 533 | equeue_clampdiff(q->queue->target, equeue_tick())); |
Bogdan Marinescu |
0:a792d4bf36c2 | 534 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 535 | q->background.active = true; |
Bogdan Marinescu |
0:a792d4bf36c2 | 536 | equeue_mutex_unlock(&q->queuelock); |
Bogdan Marinescu |
0:a792d4bf36c2 | 537 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 538 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 539 | struct equeue_chain_context { |
Bogdan Marinescu |
0:a792d4bf36c2 | 540 | equeue_t *q; |
Bogdan Marinescu |
0:a792d4bf36c2 | 541 | equeue_t *target; |
Bogdan Marinescu |
0:a792d4bf36c2 | 542 | int id; |
Bogdan Marinescu |
0:a792d4bf36c2 | 543 | }; |
Bogdan Marinescu |
0:a792d4bf36c2 | 544 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 545 | static void equeue_chain_dispatch(void *p) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 546 | equeue_dispatch((equeue_t *)p, 0); |
Bogdan Marinescu |
0:a792d4bf36c2 | 547 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 548 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 549 | static void equeue_chain_update(void *p, int ms) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 550 | struct equeue_chain_context *c = (struct equeue_chain_context *)p; |
Bogdan Marinescu |
0:a792d4bf36c2 | 551 | equeue_cancel(c->target, c->id); |
Bogdan Marinescu |
0:a792d4bf36c2 | 552 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 553 | if (ms >= 0) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 554 | c->id = equeue_call_in(c->target, ms, equeue_chain_dispatch, c->q); |
Bogdan Marinescu |
0:a792d4bf36c2 | 555 | } else { |
Bogdan Marinescu |
0:a792d4bf36c2 | 556 | equeue_dealloc(c->target, c); |
Bogdan Marinescu |
0:a792d4bf36c2 | 557 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 558 | } |
Bogdan Marinescu |
0:a792d4bf36c2 | 559 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 560 | void equeue_chain(equeue_t *q, equeue_t *target) { |
Bogdan Marinescu |
0:a792d4bf36c2 | 561 | struct equeue_chain_context *c = equeue_alloc(q, |
Bogdan Marinescu |
0:a792d4bf36c2 | 562 | sizeof(struct equeue_chain_context)); |
Bogdan Marinescu |
0:a792d4bf36c2 | 563 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 564 | c->q = q; |
Bogdan Marinescu |
0:a792d4bf36c2 | 565 | c->target = target; |
Bogdan Marinescu |
0:a792d4bf36c2 | 566 | c->id = 0; |
Bogdan Marinescu |
0:a792d4bf36c2 | 567 | |
Bogdan Marinescu |
0:a792d4bf36c2 | 568 | equeue_background(q, equeue_chain_update, c); |
Bogdan Marinescu |
0:a792d4bf36c2 | 569 | } |