├── .mbedignore ├── .travis.yml ├── Event.h ├── EventQueue.cpp ├── EventQueue.h ├── LICENSE ├── README.md ├── TESTS └── events │ └── queue │ └── main.cpp ├── equeue ├── .travis.yml ├── LICENSE.md ├── Makefile ├── README.md ├── equeue.c ├── equeue.h ├── equeue_freertos.c ├── equeue_mbed.cpp ├── equeue_platform.h ├── equeue_posix.c ├── equeue_windows.c └── tests │ ├── prof.c │ └── tests.c └── mbed_events.h /.mbedignore: -------------------------------------------------------------------------------- 1 | equeue/tests/ 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | script: 2 | - cd equeue 3 | 4 | # Strict compilation of library 5 | - CFLAGS='-pedantic -Werror' make 6 | 7 | # Runtime tests 8 | - make test 9 | 10 | # Relative profiling with current master 11 | - if ( git clone https://github.com/armmbed/mbed-events tests/master && 12 | make -s -C tests/master/$(basename $(pwd)) prof | tee tests/results.txt ) ; 13 | then 14 | cat tests/results.txt | make prof ; 15 | else 16 | make prof ; 17 | fi 18 | -------------------------------------------------------------------------------- /EventQueue.cpp: -------------------------------------------------------------------------------- 1 | #include "EventQueue.h" 2 | 3 | #include "mbed_events.h" 4 | #include "mbed.h" 5 | 6 | 7 | EventQueue::EventQueue(unsigned event_size, unsigned char *event_pointer) { 8 | if (!event_pointer) { 9 | equeue_create(&_equeue, event_size); 10 | } else { 11 | equeue_create_inplace(&_equeue, event_size, event_pointer); 12 | } 13 | } 14 | 15 | EventQueue::~EventQueue() { 16 | equeue_destroy(&_equeue); 17 | } 18 | 19 | void EventQueue::dispatch(int ms) { 20 | return equeue_dispatch(&_equeue, ms); 21 | } 22 | 23 | void EventQueue::break_dispatch() { 24 | return equeue_break(&_equeue); 25 | } 26 | 27 | unsigned EventQueue::tick() { 28 | return equeue_tick(); 29 | } 30 | 31 | void EventQueue::cancel(int id) { 32 | return equeue_cancel(&_equeue, id); 33 | } 34 | 35 | void EventQueue::background(Callback update) { 36 | _update = update; 37 | 38 | if (_update) { 39 | equeue_background(&_equeue, &Callback::thunk, &_update); 40 | } else { 41 | equeue_background(&_equeue, 0, 0); 42 | } 43 | } 44 | 45 | void EventQueue::chain(EventQueue *target) { 46 | if (target) { 47 | equeue_chain(&_equeue, &target->_equeue); 48 | } else { 49 | equeue_chain(&_equeue, 0); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /EventQueue.h: -------------------------------------------------------------------------------- 1 | /* events 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef EVENT_QUEUE_H 18 | #define EVENT_QUEUE_H 19 | 20 | #include "equeue/equeue.h" 21 | #include "Callback.h" 22 | #include 23 | #include 24 | 25 | namespace events { 26 | 27 | /** EVENTS_EVENT_SIZE 28 | * Minimum size of an event 29 | * This size fits a Callback at minimum 30 | */ 31 | #define EVENTS_EVENT_SIZE \ 32 | (EQUEUE_EVENT_SIZE - 2*sizeof(void*) + sizeof(mbed::Callback)) 33 | 34 | /** EVENTS_QUEUE_SIZE 35 | * Default size of buffer for events 36 | */ 37 | #define EVENTS_QUEUE_SIZE (32*EVENTS_EVENT_SIZE) 38 | 39 | // Predeclared classes 40 | template 41 | class Event; 42 | 43 | 44 | /** EventQueue 45 | * 46 | * Flexible event queue for dispatching events 47 | */ 48 | class EventQueue { 49 | public: 50 | /** Create an EventQueue 51 | * 52 | * Create an event queue. The event queue either allocates a buffer of 53 | * the specified size with malloc or uses the user provided buffer. 54 | * 55 | * @param size Size of buffer to use for events in bytes 56 | * (default to EVENTS_QUEUE_SIZE) 57 | * @param buffer Pointer to buffer to use for events 58 | * (default to NULL) 59 | */ 60 | EventQueue(unsigned size=EVENTS_QUEUE_SIZE, unsigned char *buffer=NULL); 61 | 62 | /** Destroy an EventQueue 63 | */ 64 | ~EventQueue(); 65 | 66 | /** Dispatch events 67 | * 68 | * Executes events until the specified milliseconds have passed. 69 | * If ms is negative, the dispatch function will dispatch events 70 | * indefinitely or until break_dispatch is called on this queue. 71 | * 72 | * When called with a finite timeout, the dispatch function is guaranteed 73 | * to terminate. When called with a timeout of 0, the dispatch function 74 | * does not wait and is irq safe. 75 | * 76 | * @param ms Time to wait for events in milliseconds, a negative 77 | * value will dispatch events indefinitely 78 | * (default to -1) 79 | */ 80 | void dispatch(int ms=-1); 81 | 82 | /** Dispatch events without a timeout 83 | * 84 | * This is equivalent to EventQueue::dispatch with no arguments, but 85 | * avoids overload ambiguities when passed as a callback. 86 | * 87 | * @see EventQueue::dispatch 88 | */ 89 | void dispatch_forever() { dispatch(); } 90 | 91 | /** Break out of a running event loop 92 | * 93 | * Forces the specified event queue's dispatch loop to terminate. Pending 94 | * events may finish executing, but no new events will be executed. 95 | */ 96 | void break_dispatch(); 97 | 98 | /** Millisecond counter 99 | * 100 | * Returns the underlying tick of the event queue represented as the 101 | * number of milliseconds that have passed since an arbitrary point in 102 | * time. Intentionally overflows to 0 after 2^32-1. 103 | * 104 | * @return The underlying tick of the event queue in milliseconds 105 | */ 106 | unsigned tick(); 107 | 108 | /** Cancel an in-flight event 109 | * 110 | * Attempts to cancel an event referenced by the unique id returned from 111 | * one of the call functions. It is safe to call cancel after an event 112 | * has already been dispatched. 113 | * 114 | * The cancel function is irq safe. 115 | * 116 | * If called while the event queue's dispatch loop is active, the cancel 117 | * function does not garuntee that the event will not execute after it 118 | * returns, as the event may have already begun executing. 119 | * 120 | * @param id Unique id of the event 121 | */ 122 | void cancel(int id); 123 | 124 | /** Background an event queue onto a single-shot timer-interrupt 125 | * 126 | * When updated, the event queue will call the provided update function 127 | * with a timeout indicating when the queue should be dispatched. A 128 | * negative timeout will be passed to the update function when the 129 | * timer-interrupt is no longer needed. 130 | * 131 | * Passing a null function disables the existing update function. 132 | * 133 | * The background function allows an event queue to take advantage of 134 | * hardware timers or other event loops, allowing an event queue to be 135 | * ran in the background without consuming the foreground thread. 136 | * 137 | * @param update Function called to indicate when the queue should be 138 | * dispatched 139 | */ 140 | void background(mbed::Callback update); 141 | 142 | /** Chain an event queue onto another event queue 143 | * 144 | * After chaining a queue to a target, calling dispatch on the target 145 | * queue will also dispatch events from this queue. The queues use 146 | * their own buffers and events must be handled independently. 147 | * 148 | * A null queue as the target will unchain the existing queue. 149 | * 150 | * The chain function allows multiple event queues to be composed, 151 | * sharing the context of a dispatch loop while still being managed 152 | * independently 153 | * 154 | * @param target Queue that will dispatch this queue's events as a 155 | * part of its dispatch loop 156 | */ 157 | void chain(EventQueue *target); 158 | 159 | /** Calls an event on the queue 160 | * 161 | * The specified callback will be executed in the context of the event 162 | * queue's dispatch loop. 163 | * 164 | * The call function is irq safe and can act as a mechanism for moving 165 | * events out of irq contexts. 166 | * 167 | * @param f Function to execute in the context of the dispatch loop 168 | * @param a0..a4 Arguments to pass to the callback 169 | * @return A unique id that represents the posted event and can 170 | * be passed to cancel, or an id of 0 if there is not 171 | * enough memory to allocate the event. 172 | */ 173 | template 174 | int call(F f) { 175 | struct local { 176 | static void call(void *p) { (*static_cast(p))(); } 177 | static void dtor(void *p) { static_cast(p)->~F(); } 178 | }; 179 | 180 | void *p = equeue_alloc(&_equeue, sizeof(F)); 181 | if (!p) { 182 | return 0; 183 | } 184 | 185 | F *e = new (p) F(f); 186 | equeue_event_dtor(e, &local::dtor); 187 | return equeue_post(&_equeue, &local::call, e); 188 | } 189 | 190 | /** Calls an event on the queue 191 | * @see EventQueue::call 192 | */ 193 | template 194 | int call(F f, A0 a0) { 195 | return call(context10(f, a0)); 196 | } 197 | 198 | /** Calls an event on the queue 199 | * @see EventQueue::call 200 | */ 201 | template 202 | int call(F f, A0 a0, A1 a1) { 203 | return call(context20(f, a0, a1)); 204 | } 205 | 206 | /** Calls an event on the queue 207 | * @see EventQueue::call 208 | */ 209 | template 210 | int call(F f, A0 a0, A1 a1, A2 a2) { 211 | return call(context30(f, a0, a1, a2)); 212 | } 213 | 214 | /** Calls an event on the queue 215 | * @see EventQueue::call 216 | */ 217 | template 218 | int call(F f, A0 a0, A1 a1, A2 a2, A3 a3) { 219 | return call(context40(f, a0, a1, a2, a3)); 220 | } 221 | 222 | /** Calls an event on the queue 223 | * @see EventQueue::call 224 | */ 225 | template 226 | int call(F f, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { 227 | return call(context50(f, a0, a1, a2, a3, a4)); 228 | } 229 | 230 | /** Calls an event on the queue 231 | * @see EventQueue::call 232 | */ 233 | template 234 | int call(T *obj, R (T::*method)()) { 235 | return call(mbed::Callback(obj, method)); 236 | } 237 | 238 | /** Calls an event on the queue 239 | * @see EventQueue::call 240 | */ 241 | template 242 | int call(const T *obj, R (T::*method)() const) { 243 | return call(mbed::Callback(obj, method)); 244 | } 245 | 246 | /** Calls an event on the queue 247 | * @see EventQueue::call 248 | */ 249 | template 250 | int call(volatile T *obj, R (T::*method)() volatile) { 251 | return call(mbed::Callback(obj, method)); 252 | } 253 | 254 | /** Calls an event on the queue 255 | * @see EventQueue::call 256 | */ 257 | template 258 | int call(const volatile T *obj, R (T::*method)() const volatile) { 259 | return call(mbed::Callback(obj, method)); 260 | } 261 | 262 | /** Calls an event on the queue 263 | * @see EventQueue::call 264 | */ 265 | template 266 | int call(T *obj, R (T::*method)(A0), A0 a0) { 267 | return call(mbed::Callback(obj, method), a0); 268 | } 269 | 270 | /** Calls an event on the queue 271 | * @see EventQueue::call 272 | */ 273 | template 274 | int call(const T *obj, R (T::*method)(A0) const, A0 a0) { 275 | return call(mbed::Callback(obj, method), a0); 276 | } 277 | 278 | /** Calls an event on the queue 279 | * @see EventQueue::call 280 | */ 281 | template 282 | int call(volatile T *obj, R (T::*method)(A0) volatile, A0 a0) { 283 | return call(mbed::Callback(obj, method), a0); 284 | } 285 | 286 | /** Calls an event on the queue 287 | * @see EventQueue::call 288 | */ 289 | template 290 | int call(const volatile T *obj, R (T::*method)(A0) const volatile, A0 a0) { 291 | return call(mbed::Callback(obj, method), a0); 292 | } 293 | 294 | /** Calls an event on the queue 295 | * @see EventQueue::call 296 | */ 297 | template 298 | int call(T *obj, R (T::*method)(A0, A1), A0 a0, A1 a1) { 299 | return call(mbed::Callback(obj, method), a0, a1); 300 | } 301 | 302 | /** Calls an event on the queue 303 | * @see EventQueue::call 304 | */ 305 | template 306 | int call(const T *obj, R (T::*method)(A0, A1) const, A0 a0, A1 a1) { 307 | return call(mbed::Callback(obj, method), a0, a1); 308 | } 309 | 310 | /** Calls an event on the queue 311 | * @see EventQueue::call 312 | */ 313 | template 314 | int call(volatile T *obj, R (T::*method)(A0, A1) volatile, A0 a0, A1 a1) { 315 | return call(mbed::Callback(obj, method), a0, a1); 316 | } 317 | 318 | /** Calls an event on the queue 319 | * @see EventQueue::call 320 | */ 321 | template 322 | int call(const volatile T *obj, R (T::*method)(A0, A1) const volatile, A0 a0, A1 a1) { 323 | return call(mbed::Callback(obj, method), a0, a1); 324 | } 325 | 326 | /** Calls an event on the queue 327 | * @see EventQueue::call 328 | */ 329 | template 330 | int call(T *obj, R (T::*method)(A0, A1, A2), A0 a0, A1 a1, A2 a2) { 331 | return call(mbed::Callback(obj, method), a0, a1, a2); 332 | } 333 | 334 | /** Calls an event on the queue 335 | * @see EventQueue::call 336 | */ 337 | template 338 | int call(const T *obj, R (T::*method)(A0, A1, A2) const, A0 a0, A1 a1, A2 a2) { 339 | return call(mbed::Callback(obj, method), a0, a1, a2); 340 | } 341 | 342 | /** Calls an event on the queue 343 | * @see EventQueue::call 344 | */ 345 | template 346 | int call(volatile T *obj, R (T::*method)(A0, A1, A2) volatile, A0 a0, A1 a1, A2 a2) { 347 | return call(mbed::Callback(obj, method), a0, a1, a2); 348 | } 349 | 350 | /** Calls an event on the queue 351 | * @see EventQueue::call 352 | */ 353 | template 354 | int call(const volatile T *obj, R (T::*method)(A0, A1, A2) const volatile, A0 a0, A1 a1, A2 a2) { 355 | return call(mbed::Callback(obj, method), a0, a1, a2); 356 | } 357 | 358 | /** Calls an event on the queue 359 | * @see EventQueue::call 360 | */ 361 | template 362 | int call(T *obj, R (T::*method)(A0, A1, A2, A3), A0 a0, A1 a1, A2 a2, A3 a3) { 363 | return call(mbed::Callback(obj, method), a0, a1, a2, a3); 364 | } 365 | 366 | /** Calls an event on the queue 367 | * @see EventQueue::call 368 | */ 369 | template 370 | int call(const T *obj, R (T::*method)(A0, A1, A2, A3) const, A0 a0, A1 a1, A2 a2, A3 a3) { 371 | return call(mbed::Callback(obj, method), a0, a1, a2, a3); 372 | } 373 | 374 | /** Calls an event on the queue 375 | * @see EventQueue::call 376 | */ 377 | template 378 | int call(volatile T *obj, R (T::*method)(A0, A1, A2, A3) volatile, A0 a0, A1 a1, A2 a2, A3 a3) { 379 | return call(mbed::Callback(obj, method), a0, a1, a2, a3); 380 | } 381 | 382 | /** Calls an event on the queue 383 | * @see EventQueue::call 384 | */ 385 | template 386 | int call(const volatile T *obj, R (T::*method)(A0, A1, A2, A3) const volatile, A0 a0, A1 a1, A2 a2, A3 a3) { 387 | return call(mbed::Callback(obj, method), a0, a1, a2, a3); 388 | } 389 | 390 | /** Calls an event on the queue 391 | * @see EventQueue::call 392 | */ 393 | template 394 | int call(T *obj, R (T::*method)(A0, A1, A2, A3, A4), A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { 395 | return call(mbed::Callback(obj, method), a0, a1, a2, a3, a4); 396 | } 397 | 398 | /** Calls an event on the queue 399 | * @see EventQueue::call 400 | */ 401 | template 402 | int call(const T *obj, R (T::*method)(A0, A1, A2, A3, A4) const, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { 403 | return call(mbed::Callback(obj, method), a0, a1, a2, a3, a4); 404 | } 405 | 406 | /** Calls an event on the queue 407 | * @see EventQueue::call 408 | */ 409 | template 410 | int call(volatile T *obj, R (T::*method)(A0, A1, A2, A3, A4) volatile, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { 411 | return call(mbed::Callback(obj, method), a0, a1, a2, a3, a4); 412 | } 413 | 414 | /** Calls an event on the queue 415 | * @see EventQueue::call 416 | */ 417 | template 418 | int call(const volatile T *obj, R (T::*method)(A0, A1, A2, A3, A4) const volatile, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { 419 | return call(mbed::Callback(obj, method), a0, a1, a2, a3, a4); 420 | } 421 | 422 | /** Calls an event on the queue after a specified delay 423 | * 424 | * The specified callback will be executed in the context of the event 425 | * queue's dispatch loop. 426 | * 427 | * The call_in function is irq safe and can act as a mechanism for moving 428 | * events out of irq contexts. 429 | * 430 | * @param f Function to execute in the context of the dispatch loop 431 | * @param a0..a4 Arguments to pass to the callback 432 | * @param ms Time to delay in milliseconds 433 | * @return A unique id that represents the posted event and can 434 | * be passed to cancel, or an id of 0 if there is not 435 | * enough memory to allocate the event. 436 | */ 437 | template 438 | int call_in(int ms, F f) { 439 | struct local { 440 | static void call(void *p) { (*static_cast(p))(); } 441 | static void dtor(void *p) { static_cast(p)->~F(); } 442 | }; 443 | 444 | void *p = equeue_alloc(&_equeue, sizeof(F)); 445 | if (!p) { 446 | return 0; 447 | } 448 | 449 | F *e = new (p) F(f); 450 | equeue_event_delay(e, ms); 451 | equeue_event_dtor(e, &local::dtor); 452 | return equeue_post(&_equeue, &local::call, e); 453 | } 454 | 455 | /** Calls an event on the queue after a specified delay 456 | * @see EventQueue::call_in 457 | */ 458 | template 459 | int call_in(int ms, F f, A0 a0) { 460 | return call_in(ms, context10(f, a0)); 461 | } 462 | 463 | /** Calls an event on the queue after a specified delay 464 | * @see EventQueue::call_in 465 | */ 466 | template 467 | int call_in(int ms, F f, A0 a0, A1 a1) { 468 | return call_in(ms, context20(f, a0, a1)); 469 | } 470 | 471 | /** Calls an event on the queue after a specified delay 472 | * @see EventQueue::call_in 473 | */ 474 | template 475 | int call_in(int ms, F f, A0 a0, A1 a1, A2 a2) { 476 | return call_in(ms, context30(f, a0, a1, a2)); 477 | } 478 | 479 | /** Calls an event on the queue after a specified delay 480 | * @see EventQueue::call_in 481 | */ 482 | template 483 | int call_in(int ms, F f, A0 a0, A1 a1, A2 a2, A3 a3) { 484 | return call_in(ms, context40(f, a0, a1, a2, a3)); 485 | } 486 | 487 | /** Calls an event on the queue after a specified delay 488 | * @see EventQueue::call_in 489 | */ 490 | template 491 | int call_in(int ms, F f, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { 492 | return call_in(ms, context50(f, a0, a1, a2, a3, a4)); 493 | } 494 | 495 | /** Calls an event on the queue after a specified delay 496 | * @see EventQueue::call_in 497 | */ 498 | template 499 | int call_in(int ms, T *obj, R (T::*method)()) { 500 | return call_in(ms, mbed::Callback(obj, method)); 501 | } 502 | 503 | /** Calls an event on the queue after a specified delay 504 | * @see EventQueue::call_in 505 | */ 506 | template 507 | int call_in(int ms, const T *obj, R (T::*method)() const) { 508 | return call_in(ms, mbed::Callback(obj, method)); 509 | } 510 | 511 | /** Calls an event on the queue after a specified delay 512 | * @see EventQueue::call_in 513 | */ 514 | template 515 | int call_in(int ms, volatile T *obj, R (T::*method)() volatile) { 516 | return call_in(ms, mbed::Callback(obj, method)); 517 | } 518 | 519 | /** Calls an event on the queue after a specified delay 520 | * @see EventQueue::call_in 521 | */ 522 | template 523 | int call_in(int ms, const volatile T *obj, R (T::*method)() const volatile) { 524 | return call_in(ms, mbed::Callback(obj, method)); 525 | } 526 | 527 | /** Calls an event on the queue after a specified delay 528 | * @see EventQueue::call_in 529 | */ 530 | template 531 | int call_in(int ms, T *obj, R (T::*method)(A0), A0 a0) { 532 | return call_in(ms, mbed::Callback(obj, method), a0); 533 | } 534 | 535 | /** Calls an event on the queue after a specified delay 536 | * @see EventQueue::call_in 537 | */ 538 | template 539 | int call_in(int ms, const T *obj, R (T::*method)(A0) const, A0 a0) { 540 | return call_in(ms, mbed::Callback(obj, method), a0); 541 | } 542 | 543 | /** Calls an event on the queue after a specified delay 544 | * @see EventQueue::call_in 545 | */ 546 | template 547 | int call_in(int ms, volatile T *obj, R (T::*method)(A0) volatile, A0 a0) { 548 | return call_in(ms, mbed::Callback(obj, method), a0); 549 | } 550 | 551 | /** Calls an event on the queue after a specified delay 552 | * @see EventQueue::call_in 553 | */ 554 | template 555 | int call_in(int ms, const volatile T *obj, R (T::*method)(A0) const volatile, A0 a0) { 556 | return call_in(ms, mbed::Callback(obj, method), a0); 557 | } 558 | 559 | /** Calls an event on the queue after a specified delay 560 | * @see EventQueue::call_in 561 | */ 562 | template 563 | int call_in(int ms, T *obj, R (T::*method)(A0, A1), A0 a0, A1 a1) { 564 | return call_in(ms, mbed::Callback(obj, method), a0, a1); 565 | } 566 | 567 | /** Calls an event on the queue after a specified delay 568 | * @see EventQueue::call_in 569 | */ 570 | template 571 | int call_in(int ms, const T *obj, R (T::*method)(A0, A1) const, A0 a0, A1 a1) { 572 | return call_in(ms, mbed::Callback(obj, method), a0, a1); 573 | } 574 | 575 | /** Calls an event on the queue after a specified delay 576 | * @see EventQueue::call_in 577 | */ 578 | template 579 | int call_in(int ms, volatile T *obj, R (T::*method)(A0, A1) volatile, A0 a0, A1 a1) { 580 | return call_in(ms, mbed::Callback(obj, method), a0, a1); 581 | } 582 | 583 | /** Calls an event on the queue after a specified delay 584 | * @see EventQueue::call_in 585 | */ 586 | template 587 | int call_in(int ms, const volatile T *obj, R (T::*method)(A0, A1) const volatile, A0 a0, A1 a1) { 588 | return call_in(ms, mbed::Callback(obj, method), a0, a1); 589 | } 590 | 591 | /** Calls an event on the queue after a specified delay 592 | * @see EventQueue::call_in 593 | */ 594 | template 595 | int call_in(int ms, T *obj, R (T::*method)(A0, A1, A2), A0 a0, A1 a1, A2 a2) { 596 | return call_in(ms, mbed::Callback(obj, method), a0, a1, a2); 597 | } 598 | 599 | /** Calls an event on the queue after a specified delay 600 | * @see EventQueue::call_in 601 | */ 602 | template 603 | int call_in(int ms, const T *obj, R (T::*method)(A0, A1, A2) const, A0 a0, A1 a1, A2 a2) { 604 | return call_in(ms, mbed::Callback(obj, method), a0, a1, a2); 605 | } 606 | 607 | /** Calls an event on the queue after a specified delay 608 | * @see EventQueue::call_in 609 | */ 610 | template 611 | int call_in(int ms, volatile T *obj, R (T::*method)(A0, A1, A2) volatile, A0 a0, A1 a1, A2 a2) { 612 | return call_in(ms, mbed::Callback(obj, method), a0, a1, a2); 613 | } 614 | 615 | /** Calls an event on the queue after a specified delay 616 | * @see EventQueue::call_in 617 | */ 618 | template 619 | int call_in(int ms, const volatile T *obj, R (T::*method)(A0, A1, A2) const volatile, A0 a0, A1 a1, A2 a2) { 620 | return call_in(ms, mbed::Callback(obj, method), a0, a1, a2); 621 | } 622 | 623 | /** Calls an event on the queue after a specified delay 624 | * @see EventQueue::call_in 625 | */ 626 | template 627 | int call_in(int ms, T *obj, R (T::*method)(A0, A1, A2, A3), A0 a0, A1 a1, A2 a2, A3 a3) { 628 | return call_in(ms, mbed::Callback(obj, method), a0, a1, a2, a3); 629 | } 630 | 631 | /** Calls an event on the queue after a specified delay 632 | * @see EventQueue::call_in 633 | */ 634 | template 635 | int call_in(int ms, const T *obj, R (T::*method)(A0, A1, A2, A3) const, A0 a0, A1 a1, A2 a2, A3 a3) { 636 | return call_in(ms, mbed::Callback(obj, method), a0, a1, a2, a3); 637 | } 638 | 639 | /** Calls an event on the queue after a specified delay 640 | * @see EventQueue::call_in 641 | */ 642 | template 643 | int call_in(int ms, volatile T *obj, R (T::*method)(A0, A1, A2, A3) volatile, A0 a0, A1 a1, A2 a2, A3 a3) { 644 | return call_in(ms, mbed::Callback(obj, method), a0, a1, a2, a3); 645 | } 646 | 647 | /** Calls an event on the queue after a specified delay 648 | * @see EventQueue::call_in 649 | */ 650 | template 651 | int call_in(int ms, const volatile T *obj, R (T::*method)(A0, A1, A2, A3) const volatile, A0 a0, A1 a1, A2 a2, A3 a3) { 652 | return call_in(ms, mbed::Callback(obj, method), a0, a1, a2, a3); 653 | } 654 | 655 | /** Calls an event on the queue after a specified delay 656 | * @see EventQueue::call_in 657 | */ 658 | template 659 | int call_in(int ms, T *obj, R (T::*method)(A0, A1, A2, A3, A4), A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { 660 | return call_in(ms, mbed::Callback(obj, method), a0, a1, a2, a3, a4); 661 | } 662 | 663 | /** Calls an event on the queue after a specified delay 664 | * @see EventQueue::call_in 665 | */ 666 | template 667 | int call_in(int ms, const T *obj, R (T::*method)(A0, A1, A2, A3, A4) const, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { 668 | return call_in(ms, mbed::Callback(obj, method), a0, a1, a2, a3, a4); 669 | } 670 | 671 | /** Calls an event on the queue after a specified delay 672 | * @see EventQueue::call_in 673 | */ 674 | template 675 | int call_in(int ms, volatile T *obj, R (T::*method)(A0, A1, A2, A3, A4) volatile, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { 676 | return call_in(ms, mbed::Callback(obj, method), a0, a1, a2, a3, a4); 677 | } 678 | 679 | /** Calls an event on the queue after a specified delay 680 | * @see EventQueue::call_in 681 | */ 682 | template 683 | int call_in(int ms, const volatile T *obj, R (T::*method)(A0, A1, A2, A3, A4) const volatile, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { 684 | return call_in(ms, mbed::Callback(obj, method), a0, a1, a2, a3, a4); 685 | } 686 | 687 | /** Calls an event on the queue periodically 688 | * 689 | * The specified callback will be executed in the context of the event 690 | * queue's dispatch loop. 691 | * 692 | * The call_every function is irq safe and can act as a mechanism for 693 | * moving events out of irq contexts. 694 | * 695 | * @param f Function to execute in the context of the dispatch loop 696 | * @param a0..a4 Arguments to pass to the callback 697 | * @param ms Period of the event in milliseconds 698 | * @return A unique id that represents the posted event and can 699 | * be passed to cancel, or an id of 0 if there is not 700 | * enough memory to allocate the event. 701 | */ 702 | template 703 | int call_every(int ms, F f) { 704 | struct local { 705 | static void call(void *p) { (*static_cast(p))(); } 706 | static void dtor(void *p) { static_cast(p)->~F(); } 707 | }; 708 | 709 | void *p = equeue_alloc(&_equeue, sizeof(F)); 710 | if (!p) { 711 | return 0; 712 | } 713 | 714 | F *e = new (p) F(f); 715 | equeue_event_delay(e, ms); 716 | equeue_event_period(e, ms); 717 | equeue_event_dtor(e, &local::dtor); 718 | return equeue_post(&_equeue, &local::call, e); 719 | } 720 | 721 | /** Calls an event on the queue periodically 722 | * @see EventQueue::call_every 723 | */ 724 | template 725 | int call_every(int ms, F f, A0 a0) { 726 | return call_every(ms, context10(f, a0)); 727 | } 728 | 729 | /** Calls an event on the queue periodically 730 | * @see EventQueue::call_every 731 | */ 732 | template 733 | int call_every(int ms, F f, A0 a0, A1 a1) { 734 | return call_every(ms, context20(f, a0, a1)); 735 | } 736 | 737 | /** Calls an event on the queue periodically 738 | * @see EventQueue::call_every 739 | */ 740 | template 741 | int call_every(int ms, F f, A0 a0, A1 a1, A2 a2) { 742 | return call_every(ms, context30(f, a0, a1, a2)); 743 | } 744 | 745 | /** Calls an event on the queue periodically 746 | * @see EventQueue::call_every 747 | */ 748 | template 749 | int call_every(int ms, F f, A0 a0, A1 a1, A2 a2, A3 a3) { 750 | return call_every(ms, context40(f, a0, a1, a2, a3)); 751 | } 752 | 753 | /** Calls an event on the queue periodically 754 | * @see EventQueue::call_every 755 | */ 756 | template 757 | int call_every(int ms, F f, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { 758 | return call_every(ms, context50(f, a0, a1, a2, a3, a4)); 759 | } 760 | 761 | /** Calls an event on the queue periodically 762 | * @see EventQueue::call_every 763 | */ 764 | template 765 | int call_every(int ms, T *obj, R (T::*method)()) { 766 | return call_every(ms, mbed::Callback(obj, method)); 767 | } 768 | 769 | /** Calls an event on the queue periodically 770 | * @see EventQueue::call_every 771 | */ 772 | template 773 | int call_every(int ms, const T *obj, R (T::*method)() const) { 774 | return call_every(ms, mbed::Callback(obj, method)); 775 | } 776 | 777 | /** Calls an event on the queue periodically 778 | * @see EventQueue::call_every 779 | */ 780 | template 781 | int call_every(int ms, volatile T *obj, R (T::*method)() volatile) { 782 | return call_every(ms, mbed::Callback(obj, method)); 783 | } 784 | 785 | /** Calls an event on the queue periodically 786 | * @see EventQueue::call_every 787 | */ 788 | template 789 | int call_every(int ms, const volatile T *obj, R (T::*method)() const volatile) { 790 | return call_every(ms, mbed::Callback(obj, method)); 791 | } 792 | 793 | /** Calls an event on the queue periodically 794 | * @see EventQueue::call_every 795 | */ 796 | template 797 | int call_every(int ms, T *obj, R (T::*method)(A0), A0 a0) { 798 | return call_every(ms, mbed::Callback(obj, method), a0); 799 | } 800 | 801 | /** Calls an event on the queue periodically 802 | * @see EventQueue::call_every 803 | */ 804 | template 805 | int call_every(int ms, const T *obj, R (T::*method)(A0) const, A0 a0) { 806 | return call_every(ms, mbed::Callback(obj, method), a0); 807 | } 808 | 809 | /** Calls an event on the queue periodically 810 | * @see EventQueue::call_every 811 | */ 812 | template 813 | int call_every(int ms, volatile T *obj, R (T::*method)(A0) volatile, A0 a0) { 814 | return call_every(ms, mbed::Callback(obj, method), a0); 815 | } 816 | 817 | /** Calls an event on the queue periodically 818 | * @see EventQueue::call_every 819 | */ 820 | template 821 | int call_every(int ms, const volatile T *obj, R (T::*method)(A0) const volatile, A0 a0) { 822 | return call_every(ms, mbed::Callback(obj, method), a0); 823 | } 824 | 825 | /** Calls an event on the queue periodically 826 | * @see EventQueue::call_every 827 | */ 828 | template 829 | int call_every(int ms, T *obj, R (T::*method)(A0, A1), A0 a0, A1 a1) { 830 | return call_every(ms, mbed::Callback(obj, method), a0, a1); 831 | } 832 | 833 | /** Calls an event on the queue periodically 834 | * @see EventQueue::call_every 835 | */ 836 | template 837 | int call_every(int ms, const T *obj, R (T::*method)(A0, A1) const, A0 a0, A1 a1) { 838 | return call_every(ms, mbed::Callback(obj, method), a0, a1); 839 | } 840 | 841 | /** Calls an event on the queue periodically 842 | * @see EventQueue::call_every 843 | */ 844 | template 845 | int call_every(int ms, volatile T *obj, R (T::*method)(A0, A1) volatile, A0 a0, A1 a1) { 846 | return call_every(ms, mbed::Callback(obj, method), a0, a1); 847 | } 848 | 849 | /** Calls an event on the queue periodically 850 | * @see EventQueue::call_every 851 | */ 852 | template 853 | int call_every(int ms, const volatile T *obj, R (T::*method)(A0, A1) const volatile, A0 a0, A1 a1) { 854 | return call_every(ms, mbed::Callback(obj, method), a0, a1); 855 | } 856 | 857 | /** Calls an event on the queue periodically 858 | * @see EventQueue::call_every 859 | */ 860 | template 861 | int call_every(int ms, T *obj, R (T::*method)(A0, A1, A2), A0 a0, A1 a1, A2 a2) { 862 | return call_every(ms, mbed::Callback(obj, method), a0, a1, a2); 863 | } 864 | 865 | /** Calls an event on the queue periodically 866 | * @see EventQueue::call_every 867 | */ 868 | template 869 | int call_every(int ms, const T *obj, R (T::*method)(A0, A1, A2) const, A0 a0, A1 a1, A2 a2) { 870 | return call_every(ms, mbed::Callback(obj, method), a0, a1, a2); 871 | } 872 | 873 | /** Calls an event on the queue periodically 874 | * @see EventQueue::call_every 875 | */ 876 | template 877 | int call_every(int ms, volatile T *obj, R (T::*method)(A0, A1, A2) volatile, A0 a0, A1 a1, A2 a2) { 878 | return call_every(ms, mbed::Callback(obj, method), a0, a1, a2); 879 | } 880 | 881 | /** Calls an event on the queue periodically 882 | * @see EventQueue::call_every 883 | */ 884 | template 885 | int call_every(int ms, const volatile T *obj, R (T::*method)(A0, A1, A2) const volatile, A0 a0, A1 a1, A2 a2) { 886 | return call_every(ms, mbed::Callback(obj, method), a0, a1, a2); 887 | } 888 | 889 | /** Calls an event on the queue periodically 890 | * @see EventQueue::call_every 891 | */ 892 | template 893 | int call_every(int ms, T *obj, R (T::*method)(A0, A1, A2, A3), A0 a0, A1 a1, A2 a2, A3 a3) { 894 | return call_every(ms, mbed::Callback(obj, method), a0, a1, a2, a3); 895 | } 896 | 897 | /** Calls an event on the queue periodically 898 | * @see EventQueue::call_every 899 | */ 900 | template 901 | int call_every(int ms, const T *obj, R (T::*method)(A0, A1, A2, A3) const, A0 a0, A1 a1, A2 a2, A3 a3) { 902 | return call_every(ms, mbed::Callback(obj, method), a0, a1, a2, a3); 903 | } 904 | 905 | /** Calls an event on the queue periodically 906 | * @see EventQueue::call_every 907 | */ 908 | template 909 | int call_every(int ms, volatile T *obj, R (T::*method)(A0, A1, A2, A3) volatile, A0 a0, A1 a1, A2 a2, A3 a3) { 910 | return call_every(ms, mbed::Callback(obj, method), a0, a1, a2, a3); 911 | } 912 | 913 | /** Calls an event on the queue periodically 914 | * @see EventQueue::call_every 915 | */ 916 | template 917 | int call_every(int ms, const volatile T *obj, R (T::*method)(A0, A1, A2, A3) const volatile, A0 a0, A1 a1, A2 a2, A3 a3) { 918 | return call_every(ms, mbed::Callback(obj, method), a0, a1, a2, a3); 919 | } 920 | 921 | /** Calls an event on the queue periodically 922 | * @see EventQueue::call_every 923 | */ 924 | template 925 | int call_every(int ms, T *obj, R (T::*method)(A0, A1, A2, A3, A4), A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { 926 | return call_every(ms, mbed::Callback(obj, method), a0, a1, a2, a3, a4); 927 | } 928 | 929 | /** Calls an event on the queue periodically 930 | * @see EventQueue::call_every 931 | */ 932 | template 933 | int call_every(int ms, const T *obj, R (T::*method)(A0, A1, A2, A3, A4) const, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { 934 | return call_every(ms, mbed::Callback(obj, method), a0, a1, a2, a3, a4); 935 | } 936 | 937 | /** Calls an event on the queue periodically 938 | * @see EventQueue::call_every 939 | */ 940 | template 941 | int call_every(int ms, volatile T *obj, R (T::*method)(A0, A1, A2, A3, A4) volatile, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { 942 | return call_every(ms, mbed::Callback(obj, method), a0, a1, a2, a3, a4); 943 | } 944 | 945 | /** Calls an event on the queue periodically 946 | * @see EventQueue::call_every 947 | */ 948 | template 949 | int call_every(int ms, const volatile T *obj, R (T::*method)(A0, A1, A2, A3, A4) const volatile, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { 950 | return call_every(ms, mbed::Callback(obj, method), a0, a1, a2, a3, a4); 951 | } 952 | 953 | /** Creates an event bound to the event queue 954 | * 955 | * Constructs an event bound to the specified event queue. The specified 956 | * callback acts as the target for the event and is executed in the 957 | * context of the event queue's dispatch loop once posted. 958 | * 959 | * @param f Function to execute when the event is dispatched 960 | * @param a0..a4 Arguments to pass to the callback 961 | * @return Event that will dispatch on the specific queue 962 | */ 963 | template 964 | Event event(R (*func)()); 965 | 966 | /** Creates an event bound to the event queue 967 | * @see EventQueue::event 968 | */ 969 | template 970 | Event event(T *obj, R (T::*method)()); 971 | 972 | /** Creates an event bound to the event queue 973 | * @see EventQueue::event 974 | */ 975 | template 976 | Event event(const T *obj, R (T::*method)() const); 977 | 978 | /** Creates an event bound to the event queue 979 | * @see EventQueue::event 980 | */ 981 | template 982 | Event event(volatile T *obj, R (T::*method)() volatile); 983 | 984 | /** Creates an event bound to the event queue 985 | * @see EventQueue::event 986 | */ 987 | template 988 | Event event(const volatile T *obj, R (T::*method)() const volatile); 989 | 990 | /** Creates an event bound to the event queue 991 | * @see EventQueue::event 992 | */ 993 | template 994 | Event event(R (*func)(B0), C0 c0); 995 | 996 | /** Creates an event bound to the event queue 997 | * @see EventQueue::event 998 | */ 999 | template 1000 | Event event(T *obj, R (T::*method)(B0), C0 c0); 1001 | 1002 | /** Creates an event bound to the event queue 1003 | * @see EventQueue::event 1004 | */ 1005 | template 1006 | Event event(const T *obj, R (T::*method)(B0) const, C0 c0); 1007 | 1008 | /** Creates an event bound to the event queue 1009 | * @see EventQueue::event 1010 | */ 1011 | template 1012 | Event event(volatile T *obj, R (T::*method)(B0) volatile, C0 c0); 1013 | 1014 | /** Creates an event bound to the event queue 1015 | * @see EventQueue::event 1016 | */ 1017 | template 1018 | Event event(const volatile T *obj, R (T::*method)(B0) const volatile, C0 c0); 1019 | 1020 | /** Creates an event bound to the event queue 1021 | * @see EventQueue::event 1022 | */ 1023 | template 1024 | Event event(R (*func)(B0, B1), C0 c0, C1 c1); 1025 | 1026 | /** Creates an event bound to the event queue 1027 | * @see EventQueue::event 1028 | */ 1029 | template 1030 | Event event(T *obj, R (T::*method)(B0, B1), C0 c0, C1 c1); 1031 | 1032 | /** Creates an event bound to the event queue 1033 | * @see EventQueue::event 1034 | */ 1035 | template 1036 | Event event(const T *obj, R (T::*method)(B0, B1) const, C0 c0, C1 c1); 1037 | 1038 | /** Creates an event bound to the event queue 1039 | * @see EventQueue::event 1040 | */ 1041 | template 1042 | Event event(volatile T *obj, R (T::*method)(B0, B1) volatile, C0 c0, C1 c1); 1043 | 1044 | /** Creates an event bound to the event queue 1045 | * @see EventQueue::event 1046 | */ 1047 | template 1048 | Event event(const volatile T *obj, R (T::*method)(B0, B1) const volatile, C0 c0, C1 c1); 1049 | 1050 | /** Creates an event bound to the event queue 1051 | * @see EventQueue::event 1052 | */ 1053 | template 1054 | Event event(R (*func)(B0, B1, B2), C0 c0, C1 c1, C2 c2); 1055 | 1056 | /** Creates an event bound to the event queue 1057 | * @see EventQueue::event 1058 | */ 1059 | template 1060 | Event event(T *obj, R (T::*method)(B0, B1, B2), C0 c0, C1 c1, C2 c2); 1061 | 1062 | /** Creates an event bound to the event queue 1063 | * @see EventQueue::event 1064 | */ 1065 | template 1066 | Event event(const T *obj, R (T::*method)(B0, B1, B2) const, C0 c0, C1 c1, C2 c2); 1067 | 1068 | /** Creates an event bound to the event queue 1069 | * @see EventQueue::event 1070 | */ 1071 | template 1072 | Event event(volatile T *obj, R (T::*method)(B0, B1, B2) volatile, C0 c0, C1 c1, C2 c2); 1073 | 1074 | /** Creates an event bound to the event queue 1075 | * @see EventQueue::event 1076 | */ 1077 | template 1078 | Event event(const volatile T *obj, R (T::*method)(B0, B1, B2) const volatile, C0 c0, C1 c1, C2 c2); 1079 | 1080 | /** Creates an event bound to the event queue 1081 | * @see EventQueue::event 1082 | */ 1083 | template 1084 | Event event(R (*func)(B0, B1, B2, B3), C0 c0, C1 c1, C2 c2, C3 c3); 1085 | 1086 | /** Creates an event bound to the event queue 1087 | * @see EventQueue::event 1088 | */ 1089 | template 1090 | Event event(T *obj, R (T::*method)(B0, B1, B2, B3), C0 c0, C1 c1, C2 c2, C3 c3); 1091 | 1092 | /** Creates an event bound to the event queue 1093 | * @see EventQueue::event 1094 | */ 1095 | template 1096 | Event event(const T *obj, R (T::*method)(B0, B1, B2, B3) const, C0 c0, C1 c1, C2 c2, C3 c3); 1097 | 1098 | /** Creates an event bound to the event queue 1099 | * @see EventQueue::event 1100 | */ 1101 | template 1102 | Event event(volatile T *obj, R (T::*method)(B0, B1, B2, B3) volatile, C0 c0, C1 c1, C2 c2, C3 c3); 1103 | 1104 | /** Creates an event bound to the event queue 1105 | * @see EventQueue::event 1106 | */ 1107 | template 1108 | Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3) const volatile, C0 c0, C1 c1, C2 c2, C3 c3); 1109 | 1110 | /** Creates an event bound to the event queue 1111 | * @see EventQueue::event 1112 | */ 1113 | template 1114 | Event event(R (*func)(B0, B1, B2, B3, B4), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 1115 | 1116 | /** Creates an event bound to the event queue 1117 | * @see EventQueue::event 1118 | */ 1119 | template 1120 | Event event(T *obj, R (T::*method)(B0, B1, B2, B3, B4), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 1121 | 1122 | /** Creates an event bound to the event queue 1123 | * @see EventQueue::event 1124 | */ 1125 | template 1126 | Event event(const T *obj, R (T::*method)(B0, B1, B2, B3, B4) const, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 1127 | 1128 | /** Creates an event bound to the event queue 1129 | * @see EventQueue::event 1130 | */ 1131 | template 1132 | Event event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4) volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 1133 | 1134 | /** Creates an event bound to the event queue 1135 | * @see EventQueue::event 1136 | */ 1137 | template 1138 | Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4) const volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 1139 | 1140 | /** Creates an event bound to the event queue 1141 | * @see EventQueue::event 1142 | */ 1143 | template 1144 | Event event(R (*func)(A0)); 1145 | 1146 | /** Creates an event bound to the event queue 1147 | * @see EventQueue::event 1148 | */ 1149 | template 1150 | Event event(T *obj, R (T::*method)(A0)); 1151 | 1152 | /** Creates an event bound to the event queue 1153 | * @see EventQueue::event 1154 | */ 1155 | template 1156 | Event event(const T *obj, R (T::*method)(A0) const); 1157 | 1158 | /** Creates an event bound to the event queue 1159 | * @see EventQueue::event 1160 | */ 1161 | template 1162 | Event event(volatile T *obj, R (T::*method)(A0) volatile); 1163 | 1164 | /** Creates an event bound to the event queue 1165 | * @see EventQueue::event 1166 | */ 1167 | template 1168 | Event event(const volatile T *obj, R (T::*method)(A0) const volatile); 1169 | 1170 | /** Creates an event bound to the event queue 1171 | * @see EventQueue::event 1172 | */ 1173 | template 1174 | Event event(R (*func)(B0, A0), C0 c0); 1175 | 1176 | /** Creates an event bound to the event queue 1177 | * @see EventQueue::event 1178 | */ 1179 | template 1180 | Event event(T *obj, R (T::*method)(B0, A0), C0 c0); 1181 | 1182 | /** Creates an event bound to the event queue 1183 | * @see EventQueue::event 1184 | */ 1185 | template 1186 | Event event(const T *obj, R (T::*method)(B0, A0) const, C0 c0); 1187 | 1188 | /** Creates an event bound to the event queue 1189 | * @see EventQueue::event 1190 | */ 1191 | template 1192 | Event event(volatile T *obj, R (T::*method)(B0, A0) volatile, C0 c0); 1193 | 1194 | /** Creates an event bound to the event queue 1195 | * @see EventQueue::event 1196 | */ 1197 | template 1198 | Event event(const volatile T *obj, R (T::*method)(B0, A0) const volatile, C0 c0); 1199 | 1200 | /** Creates an event bound to the event queue 1201 | * @see EventQueue::event 1202 | */ 1203 | template 1204 | Event event(R (*func)(B0, B1, A0), C0 c0, C1 c1); 1205 | 1206 | /** Creates an event bound to the event queue 1207 | * @see EventQueue::event 1208 | */ 1209 | template 1210 | Event event(T *obj, R (T::*method)(B0, B1, A0), C0 c0, C1 c1); 1211 | 1212 | /** Creates an event bound to the event queue 1213 | * @see EventQueue::event 1214 | */ 1215 | template 1216 | Event event(const T *obj, R (T::*method)(B0, B1, A0) const, C0 c0, C1 c1); 1217 | 1218 | /** Creates an event bound to the event queue 1219 | * @see EventQueue::event 1220 | */ 1221 | template 1222 | Event event(volatile T *obj, R (T::*method)(B0, B1, A0) volatile, C0 c0, C1 c1); 1223 | 1224 | /** Creates an event bound to the event queue 1225 | * @see EventQueue::event 1226 | */ 1227 | template 1228 | Event event(const volatile T *obj, R (T::*method)(B0, B1, A0) const volatile, C0 c0, C1 c1); 1229 | 1230 | /** Creates an event bound to the event queue 1231 | * @see EventQueue::event 1232 | */ 1233 | template 1234 | Event event(R (*func)(B0, B1, B2, A0), C0 c0, C1 c1, C2 c2); 1235 | 1236 | /** Creates an event bound to the event queue 1237 | * @see EventQueue::event 1238 | */ 1239 | template 1240 | Event event(T *obj, R (T::*method)(B0, B1, B2, A0), C0 c0, C1 c1, C2 c2); 1241 | 1242 | /** Creates an event bound to the event queue 1243 | * @see EventQueue::event 1244 | */ 1245 | template 1246 | Event event(const T *obj, R (T::*method)(B0, B1, B2, A0) const, C0 c0, C1 c1, C2 c2); 1247 | 1248 | /** Creates an event bound to the event queue 1249 | * @see EventQueue::event 1250 | */ 1251 | template 1252 | Event event(volatile T *obj, R (T::*method)(B0, B1, B2, A0) volatile, C0 c0, C1 c1, C2 c2); 1253 | 1254 | /** Creates an event bound to the event queue 1255 | * @see EventQueue::event 1256 | */ 1257 | template 1258 | Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, A0) const volatile, C0 c0, C1 c1, C2 c2); 1259 | 1260 | /** Creates an event bound to the event queue 1261 | * @see EventQueue::event 1262 | */ 1263 | template 1264 | Event event(R (*func)(B0, B1, B2, B3, A0), C0 c0, C1 c1, C2 c2, C3 c3); 1265 | 1266 | /** Creates an event bound to the event queue 1267 | * @see EventQueue::event 1268 | */ 1269 | template 1270 | Event event(T *obj, R (T::*method)(B0, B1, B2, B3, A0), C0 c0, C1 c1, C2 c2, C3 c3); 1271 | 1272 | /** Creates an event bound to the event queue 1273 | * @see EventQueue::event 1274 | */ 1275 | template 1276 | Event event(const T *obj, R (T::*method)(B0, B1, B2, B3, A0) const, C0 c0, C1 c1, C2 c2, C3 c3); 1277 | 1278 | /** Creates an event bound to the event queue 1279 | * @see EventQueue::event 1280 | */ 1281 | template 1282 | Event event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0) volatile, C0 c0, C1 c1, C2 c2, C3 c3); 1283 | 1284 | /** Creates an event bound to the event queue 1285 | * @see EventQueue::event 1286 | */ 1287 | template 1288 | Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0) const volatile, C0 c0, C1 c1, C2 c2, C3 c3); 1289 | 1290 | /** Creates an event bound to the event queue 1291 | * @see EventQueue::event 1292 | */ 1293 | template 1294 | Event event(R (*func)(B0, B1, B2, B3, B4, A0), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 1295 | 1296 | /** Creates an event bound to the event queue 1297 | * @see EventQueue::event 1298 | */ 1299 | template 1300 | Event event(T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 1301 | 1302 | /** Creates an event bound to the event queue 1303 | * @see EventQueue::event 1304 | */ 1305 | template 1306 | Event event(const T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0) const, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 1307 | 1308 | /** Creates an event bound to the event queue 1309 | * @see EventQueue::event 1310 | */ 1311 | template 1312 | Event event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0) volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 1313 | 1314 | /** Creates an event bound to the event queue 1315 | * @see EventQueue::event 1316 | */ 1317 | template 1318 | Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0) const volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 1319 | 1320 | /** Creates an event bound to the event queue 1321 | * @see EventQueue::event 1322 | */ 1323 | template 1324 | Event event(R (*func)(A0, A1)); 1325 | 1326 | /** Creates an event bound to the event queue 1327 | * @see EventQueue::event 1328 | */ 1329 | template 1330 | Event event(T *obj, R (T::*method)(A0, A1)); 1331 | 1332 | /** Creates an event bound to the event queue 1333 | * @see EventQueue::event 1334 | */ 1335 | template 1336 | Event event(const T *obj, R (T::*method)(A0, A1) const); 1337 | 1338 | /** Creates an event bound to the event queue 1339 | * @see EventQueue::event 1340 | */ 1341 | template 1342 | Event event(volatile T *obj, R (T::*method)(A0, A1) volatile); 1343 | 1344 | /** Creates an event bound to the event queue 1345 | * @see EventQueue::event 1346 | */ 1347 | template 1348 | Event event(const volatile T *obj, R (T::*method)(A0, A1) const volatile); 1349 | 1350 | /** Creates an event bound to the event queue 1351 | * @see EventQueue::event 1352 | */ 1353 | template 1354 | Event event(R (*func)(B0, A0, A1), C0 c0); 1355 | 1356 | /** Creates an event bound to the event queue 1357 | * @see EventQueue::event 1358 | */ 1359 | template 1360 | Event event(T *obj, R (T::*method)(B0, A0, A1), C0 c0); 1361 | 1362 | /** Creates an event bound to the event queue 1363 | * @see EventQueue::event 1364 | */ 1365 | template 1366 | Event event(const T *obj, R (T::*method)(B0, A0, A1) const, C0 c0); 1367 | 1368 | /** Creates an event bound to the event queue 1369 | * @see EventQueue::event 1370 | */ 1371 | template 1372 | Event event(volatile T *obj, R (T::*method)(B0, A0, A1) volatile, C0 c0); 1373 | 1374 | /** Creates an event bound to the event queue 1375 | * @see EventQueue::event 1376 | */ 1377 | template 1378 | Event event(const volatile T *obj, R (T::*method)(B0, A0, A1) const volatile, C0 c0); 1379 | 1380 | /** Creates an event bound to the event queue 1381 | * @see EventQueue::event 1382 | */ 1383 | template 1384 | Event event(R (*func)(B0, B1, A0, A1), C0 c0, C1 c1); 1385 | 1386 | /** Creates an event bound to the event queue 1387 | * @see EventQueue::event 1388 | */ 1389 | template 1390 | Event event(T *obj, R (T::*method)(B0, B1, A0, A1), C0 c0, C1 c1); 1391 | 1392 | /** Creates an event bound to the event queue 1393 | * @see EventQueue::event 1394 | */ 1395 | template 1396 | Event event(const T *obj, R (T::*method)(B0, B1, A0, A1) const, C0 c0, C1 c1); 1397 | 1398 | /** Creates an event bound to the event queue 1399 | * @see EventQueue::event 1400 | */ 1401 | template 1402 | Event event(volatile T *obj, R (T::*method)(B0, B1, A0, A1) volatile, C0 c0, C1 c1); 1403 | 1404 | /** Creates an event bound to the event queue 1405 | * @see EventQueue::event 1406 | */ 1407 | template 1408 | Event event(const volatile T *obj, R (T::*method)(B0, B1, A0, A1) const volatile, C0 c0, C1 c1); 1409 | 1410 | /** Creates an event bound to the event queue 1411 | * @see EventQueue::event 1412 | */ 1413 | template 1414 | Event event(R (*func)(B0, B1, B2, A0, A1), C0 c0, C1 c1, C2 c2); 1415 | 1416 | /** Creates an event bound to the event queue 1417 | * @see EventQueue::event 1418 | */ 1419 | template 1420 | Event event(T *obj, R (T::*method)(B0, B1, B2, A0, A1), C0 c0, C1 c1, C2 c2); 1421 | 1422 | /** Creates an event bound to the event queue 1423 | * @see EventQueue::event 1424 | */ 1425 | template 1426 | Event event(const T *obj, R (T::*method)(B0, B1, B2, A0, A1) const, C0 c0, C1 c1, C2 c2); 1427 | 1428 | /** Creates an event bound to the event queue 1429 | * @see EventQueue::event 1430 | */ 1431 | template 1432 | Event event(volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1) volatile, C0 c0, C1 c1, C2 c2); 1433 | 1434 | /** Creates an event bound to the event queue 1435 | * @see EventQueue::event 1436 | */ 1437 | template 1438 | Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1) const volatile, C0 c0, C1 c1, C2 c2); 1439 | 1440 | /** Creates an event bound to the event queue 1441 | * @see EventQueue::event 1442 | */ 1443 | template 1444 | Event event(R (*func)(B0, B1, B2, B3, A0, A1), C0 c0, C1 c1, C2 c2, C3 c3); 1445 | 1446 | /** Creates an event bound to the event queue 1447 | * @see EventQueue::event 1448 | */ 1449 | template 1450 | Event event(T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1), C0 c0, C1 c1, C2 c2, C3 c3); 1451 | 1452 | /** Creates an event bound to the event queue 1453 | * @see EventQueue::event 1454 | */ 1455 | template 1456 | Event event(const T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1) const, C0 c0, C1 c1, C2 c2, C3 c3); 1457 | 1458 | /** Creates an event bound to the event queue 1459 | * @see EventQueue::event 1460 | */ 1461 | template 1462 | Event event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1) volatile, C0 c0, C1 c1, C2 c2, C3 c3); 1463 | 1464 | /** Creates an event bound to the event queue 1465 | * @see EventQueue::event 1466 | */ 1467 | template 1468 | Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1) const volatile, C0 c0, C1 c1, C2 c2, C3 c3); 1469 | 1470 | /** Creates an event bound to the event queue 1471 | * @see EventQueue::event 1472 | */ 1473 | template 1474 | Event event(R (*func)(B0, B1, B2, B3, B4, A0, A1), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 1475 | 1476 | /** Creates an event bound to the event queue 1477 | * @see EventQueue::event 1478 | */ 1479 | template 1480 | Event event(T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 1481 | 1482 | /** Creates an event bound to the event queue 1483 | * @see EventQueue::event 1484 | */ 1485 | template 1486 | Event event(const T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1) const, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 1487 | 1488 | /** Creates an event bound to the event queue 1489 | * @see EventQueue::event 1490 | */ 1491 | template 1492 | Event event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1) volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 1493 | 1494 | /** Creates an event bound to the event queue 1495 | * @see EventQueue::event 1496 | */ 1497 | template 1498 | Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1) const volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 1499 | 1500 | /** Creates an event bound to the event queue 1501 | * @see EventQueue::event 1502 | */ 1503 | template 1504 | Event event(R (*func)(A0, A1, A2)); 1505 | 1506 | /** Creates an event bound to the event queue 1507 | * @see EventQueue::event 1508 | */ 1509 | template 1510 | Event event(T *obj, R (T::*method)(A0, A1, A2)); 1511 | 1512 | /** Creates an event bound to the event queue 1513 | * @see EventQueue::event 1514 | */ 1515 | template 1516 | Event event(const T *obj, R (T::*method)(A0, A1, A2) const); 1517 | 1518 | /** Creates an event bound to the event queue 1519 | * @see EventQueue::event 1520 | */ 1521 | template 1522 | Event event(volatile T *obj, R (T::*method)(A0, A1, A2) volatile); 1523 | 1524 | /** Creates an event bound to the event queue 1525 | * @see EventQueue::event 1526 | */ 1527 | template 1528 | Event event(const volatile T *obj, R (T::*method)(A0, A1, A2) const volatile); 1529 | 1530 | /** Creates an event bound to the event queue 1531 | * @see EventQueue::event 1532 | */ 1533 | template 1534 | Event event(R (*func)(B0, A0, A1, A2), C0 c0); 1535 | 1536 | /** Creates an event bound to the event queue 1537 | * @see EventQueue::event 1538 | */ 1539 | template 1540 | Event event(T *obj, R (T::*method)(B0, A0, A1, A2), C0 c0); 1541 | 1542 | /** Creates an event bound to the event queue 1543 | * @see EventQueue::event 1544 | */ 1545 | template 1546 | Event event(const T *obj, R (T::*method)(B0, A0, A1, A2) const, C0 c0); 1547 | 1548 | /** Creates an event bound to the event queue 1549 | * @see EventQueue::event 1550 | */ 1551 | template 1552 | Event event(volatile T *obj, R (T::*method)(B0, A0, A1, A2) volatile, C0 c0); 1553 | 1554 | /** Creates an event bound to the event queue 1555 | * @see EventQueue::event 1556 | */ 1557 | template 1558 | Event event(const volatile T *obj, R (T::*method)(B0, A0, A1, A2) const volatile, C0 c0); 1559 | 1560 | /** Creates an event bound to the event queue 1561 | * @see EventQueue::event 1562 | */ 1563 | template 1564 | Event event(R (*func)(B0, B1, A0, A1, A2), C0 c0, C1 c1); 1565 | 1566 | /** Creates an event bound to the event queue 1567 | * @see EventQueue::event 1568 | */ 1569 | template 1570 | Event event(T *obj, R (T::*method)(B0, B1, A0, A1, A2), C0 c0, C1 c1); 1571 | 1572 | /** Creates an event bound to the event queue 1573 | * @see EventQueue::event 1574 | */ 1575 | template 1576 | Event event(const T *obj, R (T::*method)(B0, B1, A0, A1, A2) const, C0 c0, C1 c1); 1577 | 1578 | /** Creates an event bound to the event queue 1579 | * @see EventQueue::event 1580 | */ 1581 | template 1582 | Event event(volatile T *obj, R (T::*method)(B0, B1, A0, A1, A2) volatile, C0 c0, C1 c1); 1583 | 1584 | /** Creates an event bound to the event queue 1585 | * @see EventQueue::event 1586 | */ 1587 | template 1588 | Event event(const volatile T *obj, R (T::*method)(B0, B1, A0, A1, A2) const volatile, C0 c0, C1 c1); 1589 | 1590 | /** Creates an event bound to the event queue 1591 | * @see EventQueue::event 1592 | */ 1593 | template 1594 | Event event(R (*func)(B0, B1, B2, A0, A1, A2), C0 c0, C1 c1, C2 c2); 1595 | 1596 | /** Creates an event bound to the event queue 1597 | * @see EventQueue::event 1598 | */ 1599 | template 1600 | Event event(T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2), C0 c0, C1 c1, C2 c2); 1601 | 1602 | /** Creates an event bound to the event queue 1603 | * @see EventQueue::event 1604 | */ 1605 | template 1606 | Event event(const T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2) const, C0 c0, C1 c1, C2 c2); 1607 | 1608 | /** Creates an event bound to the event queue 1609 | * @see EventQueue::event 1610 | */ 1611 | template 1612 | Event event(volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2) volatile, C0 c0, C1 c1, C2 c2); 1613 | 1614 | /** Creates an event bound to the event queue 1615 | * @see EventQueue::event 1616 | */ 1617 | template 1618 | Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2) const volatile, C0 c0, C1 c1, C2 c2); 1619 | 1620 | /** Creates an event bound to the event queue 1621 | * @see EventQueue::event 1622 | */ 1623 | template 1624 | Event event(R (*func)(B0, B1, B2, B3, A0, A1, A2), C0 c0, C1 c1, C2 c2, C3 c3); 1625 | 1626 | /** Creates an event bound to the event queue 1627 | * @see EventQueue::event 1628 | */ 1629 | template 1630 | Event event(T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2), C0 c0, C1 c1, C2 c2, C3 c3); 1631 | 1632 | /** Creates an event bound to the event queue 1633 | * @see EventQueue::event 1634 | */ 1635 | template 1636 | Event event(const T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2) const, C0 c0, C1 c1, C2 c2, C3 c3); 1637 | 1638 | /** Creates an event bound to the event queue 1639 | * @see EventQueue::event 1640 | */ 1641 | template 1642 | Event event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2) volatile, C0 c0, C1 c1, C2 c2, C3 c3); 1643 | 1644 | /** Creates an event bound to the event queue 1645 | * @see EventQueue::event 1646 | */ 1647 | template 1648 | Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2) const volatile, C0 c0, C1 c1, C2 c2, C3 c3); 1649 | 1650 | /** Creates an event bound to the event queue 1651 | * @see EventQueue::event 1652 | */ 1653 | template 1654 | Event event(R (*func)(B0, B1, B2, B3, B4, A0, A1, A2), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 1655 | 1656 | /** Creates an event bound to the event queue 1657 | * @see EventQueue::event 1658 | */ 1659 | template 1660 | Event event(T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 1661 | 1662 | /** Creates an event bound to the event queue 1663 | * @see EventQueue::event 1664 | */ 1665 | template 1666 | Event event(const T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2) const, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 1667 | 1668 | /** Creates an event bound to the event queue 1669 | * @see EventQueue::event 1670 | */ 1671 | template 1672 | Event event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2) volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 1673 | 1674 | /** Creates an event bound to the event queue 1675 | * @see EventQueue::event 1676 | */ 1677 | template 1678 | Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2) const volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 1679 | 1680 | /** Creates an event bound to the event queue 1681 | * @see EventQueue::event 1682 | */ 1683 | template 1684 | Event event(R (*func)(A0, A1, A2, A3)); 1685 | 1686 | /** Creates an event bound to the event queue 1687 | * @see EventQueue::event 1688 | */ 1689 | template 1690 | Event event(T *obj, R (T::*method)(A0, A1, A2, A3)); 1691 | 1692 | /** Creates an event bound to the event queue 1693 | * @see EventQueue::event 1694 | */ 1695 | template 1696 | Event event(const T *obj, R (T::*method)(A0, A1, A2, A3) const); 1697 | 1698 | /** Creates an event bound to the event queue 1699 | * @see EventQueue::event 1700 | */ 1701 | template 1702 | Event event(volatile T *obj, R (T::*method)(A0, A1, A2, A3) volatile); 1703 | 1704 | /** Creates an event bound to the event queue 1705 | * @see EventQueue::event 1706 | */ 1707 | template 1708 | Event event(const volatile T *obj, R (T::*method)(A0, A1, A2, A3) const volatile); 1709 | 1710 | /** Creates an event bound to the event queue 1711 | * @see EventQueue::event 1712 | */ 1713 | template 1714 | Event event(R (*func)(B0, A0, A1, A2, A3), C0 c0); 1715 | 1716 | /** Creates an event bound to the event queue 1717 | * @see EventQueue::event 1718 | */ 1719 | template 1720 | Event event(T *obj, R (T::*method)(B0, A0, A1, A2, A3), C0 c0); 1721 | 1722 | /** Creates an event bound to the event queue 1723 | * @see EventQueue::event 1724 | */ 1725 | template 1726 | Event event(const T *obj, R (T::*method)(B0, A0, A1, A2, A3) const, C0 c0); 1727 | 1728 | /** Creates an event bound to the event queue 1729 | * @see EventQueue::event 1730 | */ 1731 | template 1732 | Event event(volatile T *obj, R (T::*method)(B0, A0, A1, A2, A3) volatile, C0 c0); 1733 | 1734 | /** Creates an event bound to the event queue 1735 | * @see EventQueue::event 1736 | */ 1737 | template 1738 | Event event(const volatile T *obj, R (T::*method)(B0, A0, A1, A2, A3) const volatile, C0 c0); 1739 | 1740 | /** Creates an event bound to the event queue 1741 | * @see EventQueue::event 1742 | */ 1743 | template 1744 | Event event(R (*func)(B0, B1, A0, A1, A2, A3), C0 c0, C1 c1); 1745 | 1746 | /** Creates an event bound to the event queue 1747 | * @see EventQueue::event 1748 | */ 1749 | template 1750 | Event event(T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3), C0 c0, C1 c1); 1751 | 1752 | /** Creates an event bound to the event queue 1753 | * @see EventQueue::event 1754 | */ 1755 | template 1756 | Event event(const T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3) const, C0 c0, C1 c1); 1757 | 1758 | /** Creates an event bound to the event queue 1759 | * @see EventQueue::event 1760 | */ 1761 | template 1762 | Event event(volatile T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3) volatile, C0 c0, C1 c1); 1763 | 1764 | /** Creates an event bound to the event queue 1765 | * @see EventQueue::event 1766 | */ 1767 | template 1768 | Event event(const volatile T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3) const volatile, C0 c0, C1 c1); 1769 | 1770 | /** Creates an event bound to the event queue 1771 | * @see EventQueue::event 1772 | */ 1773 | template 1774 | Event event(R (*func)(B0, B1, B2, A0, A1, A2, A3), C0 c0, C1 c1, C2 c2); 1775 | 1776 | /** Creates an event bound to the event queue 1777 | * @see EventQueue::event 1778 | */ 1779 | template 1780 | Event event(T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3), C0 c0, C1 c1, C2 c2); 1781 | 1782 | /** Creates an event bound to the event queue 1783 | * @see EventQueue::event 1784 | */ 1785 | template 1786 | Event event(const T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3) const, C0 c0, C1 c1, C2 c2); 1787 | 1788 | /** Creates an event bound to the event queue 1789 | * @see EventQueue::event 1790 | */ 1791 | template 1792 | Event event(volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3) volatile, C0 c0, C1 c1, C2 c2); 1793 | 1794 | /** Creates an event bound to the event queue 1795 | * @see EventQueue::event 1796 | */ 1797 | template 1798 | Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3) const volatile, C0 c0, C1 c1, C2 c2); 1799 | 1800 | /** Creates an event bound to the event queue 1801 | * @see EventQueue::event 1802 | */ 1803 | template 1804 | Event event(R (*func)(B0, B1, B2, B3, A0, A1, A2, A3), C0 c0, C1 c1, C2 c2, C3 c3); 1805 | 1806 | /** Creates an event bound to the event queue 1807 | * @see EventQueue::event 1808 | */ 1809 | template 1810 | Event event(T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3), C0 c0, C1 c1, C2 c2, C3 c3); 1811 | 1812 | /** Creates an event bound to the event queue 1813 | * @see EventQueue::event 1814 | */ 1815 | template 1816 | Event event(const T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3) const, C0 c0, C1 c1, C2 c2, C3 c3); 1817 | 1818 | /** Creates an event bound to the event queue 1819 | * @see EventQueue::event 1820 | */ 1821 | template 1822 | Event event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3) volatile, C0 c0, C1 c1, C2 c2, C3 c3); 1823 | 1824 | /** Creates an event bound to the event queue 1825 | * @see EventQueue::event 1826 | */ 1827 | template 1828 | Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3) const volatile, C0 c0, C1 c1, C2 c2, C3 c3); 1829 | 1830 | /** Creates an event bound to the event queue 1831 | * @see EventQueue::event 1832 | */ 1833 | template 1834 | Event event(R (*func)(B0, B1, B2, B3, B4, A0, A1, A2, A3), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 1835 | 1836 | /** Creates an event bound to the event queue 1837 | * @see EventQueue::event 1838 | */ 1839 | template 1840 | Event event(T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 1841 | 1842 | /** Creates an event bound to the event queue 1843 | * @see EventQueue::event 1844 | */ 1845 | template 1846 | Event event(const T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3) const, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 1847 | 1848 | /** Creates an event bound to the event queue 1849 | * @see EventQueue::event 1850 | */ 1851 | template 1852 | Event event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3) volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 1853 | 1854 | /** Creates an event bound to the event queue 1855 | * @see EventQueue::event 1856 | */ 1857 | template 1858 | Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3) const volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 1859 | 1860 | /** Creates an event bound to the event queue 1861 | * @see EventQueue::event 1862 | */ 1863 | template 1864 | Event event(R (*func)(A0, A1, A2, A3, A4)); 1865 | 1866 | /** Creates an event bound to the event queue 1867 | * @see EventQueue::event 1868 | */ 1869 | template 1870 | Event event(T *obj, R (T::*method)(A0, A1, A2, A3, A4)); 1871 | 1872 | /** Creates an event bound to the event queue 1873 | * @see EventQueue::event 1874 | */ 1875 | template 1876 | Event event(const T *obj, R (T::*method)(A0, A1, A2, A3, A4) const); 1877 | 1878 | /** Creates an event bound to the event queue 1879 | * @see EventQueue::event 1880 | */ 1881 | template 1882 | Event event(volatile T *obj, R (T::*method)(A0, A1, A2, A3, A4) volatile); 1883 | 1884 | /** Creates an event bound to the event queue 1885 | * @see EventQueue::event 1886 | */ 1887 | template 1888 | Event event(const volatile T *obj, R (T::*method)(A0, A1, A2, A3, A4) const volatile); 1889 | 1890 | /** Creates an event bound to the event queue 1891 | * @see EventQueue::event 1892 | */ 1893 | template 1894 | Event event(R (*func)(B0, A0, A1, A2, A3, A4), C0 c0); 1895 | 1896 | /** Creates an event bound to the event queue 1897 | * @see EventQueue::event 1898 | */ 1899 | template 1900 | Event event(T *obj, R (T::*method)(B0, A0, A1, A2, A3, A4), C0 c0); 1901 | 1902 | /** Creates an event bound to the event queue 1903 | * @see EventQueue::event 1904 | */ 1905 | template 1906 | Event event(const T *obj, R (T::*method)(B0, A0, A1, A2, A3, A4) const, C0 c0); 1907 | 1908 | /** Creates an event bound to the event queue 1909 | * @see EventQueue::event 1910 | */ 1911 | template 1912 | Event event(volatile T *obj, R (T::*method)(B0, A0, A1, A2, A3, A4) volatile, C0 c0); 1913 | 1914 | /** Creates an event bound to the event queue 1915 | * @see EventQueue::event 1916 | */ 1917 | template 1918 | Event event(const volatile T *obj, R (T::*method)(B0, A0, A1, A2, A3, A4) const volatile, C0 c0); 1919 | 1920 | /** Creates an event bound to the event queue 1921 | * @see EventQueue::event 1922 | */ 1923 | template 1924 | Event event(R (*func)(B0, B1, A0, A1, A2, A3, A4), C0 c0, C1 c1); 1925 | 1926 | /** Creates an event bound to the event queue 1927 | * @see EventQueue::event 1928 | */ 1929 | template 1930 | Event event(T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3, A4), C0 c0, C1 c1); 1931 | 1932 | /** Creates an event bound to the event queue 1933 | * @see EventQueue::event 1934 | */ 1935 | template 1936 | Event event(const T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3, A4) const, C0 c0, C1 c1); 1937 | 1938 | /** Creates an event bound to the event queue 1939 | * @see EventQueue::event 1940 | */ 1941 | template 1942 | Event event(volatile T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3, A4) volatile, C0 c0, C1 c1); 1943 | 1944 | /** Creates an event bound to the event queue 1945 | * @see EventQueue::event 1946 | */ 1947 | template 1948 | Event event(const volatile T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3, A4) const volatile, C0 c0, C1 c1); 1949 | 1950 | /** Creates an event bound to the event queue 1951 | * @see EventQueue::event 1952 | */ 1953 | template 1954 | Event event(R (*func)(B0, B1, B2, A0, A1, A2, A3, A4), C0 c0, C1 c1, C2 c2); 1955 | 1956 | /** Creates an event bound to the event queue 1957 | * @see EventQueue::event 1958 | */ 1959 | template 1960 | Event event(T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3, A4), C0 c0, C1 c1, C2 c2); 1961 | 1962 | /** Creates an event bound to the event queue 1963 | * @see EventQueue::event 1964 | */ 1965 | template 1966 | Event event(const T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3, A4) const, C0 c0, C1 c1, C2 c2); 1967 | 1968 | /** Creates an event bound to the event queue 1969 | * @see EventQueue::event 1970 | */ 1971 | template 1972 | Event event(volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3, A4) volatile, C0 c0, C1 c1, C2 c2); 1973 | 1974 | /** Creates an event bound to the event queue 1975 | * @see EventQueue::event 1976 | */ 1977 | template 1978 | Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3, A4) const volatile, C0 c0, C1 c1, C2 c2); 1979 | 1980 | /** Creates an event bound to the event queue 1981 | * @see EventQueue::event 1982 | */ 1983 | template 1984 | Event event(R (*func)(B0, B1, B2, B3, A0, A1, A2, A3, A4), C0 c0, C1 c1, C2 c2, C3 c3); 1985 | 1986 | /** Creates an event bound to the event queue 1987 | * @see EventQueue::event 1988 | */ 1989 | template 1990 | Event event(T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3, A4), C0 c0, C1 c1, C2 c2, C3 c3); 1991 | 1992 | /** Creates an event bound to the event queue 1993 | * @see EventQueue::event 1994 | */ 1995 | template 1996 | Event event(const T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3, A4) const, C0 c0, C1 c1, C2 c2, C3 c3); 1997 | 1998 | /** Creates an event bound to the event queue 1999 | * @see EventQueue::event 2000 | */ 2001 | template 2002 | Event event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3, A4) volatile, C0 c0, C1 c1, C2 c2, C3 c3); 2003 | 2004 | /** Creates an event bound to the event queue 2005 | * @see EventQueue::event 2006 | */ 2007 | template 2008 | Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3, A4) const volatile, C0 c0, C1 c1, C2 c2, C3 c3); 2009 | 2010 | /** Creates an event bound to the event queue 2011 | * @see EventQueue::event 2012 | */ 2013 | template 2014 | Event event(R (*func)(B0, B1, B2, B3, B4, A0, A1, A2, A3, A4), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 2015 | 2016 | /** Creates an event bound to the event queue 2017 | * @see EventQueue::event 2018 | */ 2019 | template 2020 | Event event(T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3, A4), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 2021 | 2022 | /** Creates an event bound to the event queue 2023 | * @see EventQueue::event 2024 | */ 2025 | template 2026 | Event event(const T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3, A4) const, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 2027 | 2028 | /** Creates an event bound to the event queue 2029 | * @see EventQueue::event 2030 | */ 2031 | template 2032 | Event event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3, A4) volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 2033 | 2034 | /** Creates an event bound to the event queue 2035 | * @see EventQueue::event 2036 | */ 2037 | template 2038 | Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3, A4) const volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); 2039 | 2040 | protected: 2041 | template 2042 | friend class Event; 2043 | struct equeue _equeue; 2044 | mbed::Callback _update; 2045 | 2046 | template 2047 | struct context00 { 2048 | F f; 2049 | 2050 | context00(F f) 2051 | : f(f) {} 2052 | 2053 | void operator()() { 2054 | f(); 2055 | } 2056 | }; 2057 | 2058 | template 2059 | struct context10 { 2060 | F f; C0 c0; 2061 | 2062 | context10(F f, C0 c0) 2063 | : f(f), c0(c0) {} 2064 | 2065 | void operator()() { 2066 | f(c0); 2067 | } 2068 | }; 2069 | 2070 | template 2071 | struct context20 { 2072 | F f; C0 c0; C1 c1; 2073 | 2074 | context20(F f, C0 c0, C1 c1) 2075 | : f(f), c0(c0), c1(c1) {} 2076 | 2077 | void operator()() { 2078 | f(c0, c1); 2079 | } 2080 | }; 2081 | 2082 | template 2083 | struct context30 { 2084 | F f; C0 c0; C1 c1; C2 c2; 2085 | 2086 | context30(F f, C0 c0, C1 c1, C2 c2) 2087 | : f(f), c0(c0), c1(c1), c2(c2) {} 2088 | 2089 | void operator()() { 2090 | f(c0, c1, c2); 2091 | } 2092 | }; 2093 | 2094 | template 2095 | struct context40 { 2096 | F f; C0 c0; C1 c1; C2 c2; C3 c3; 2097 | 2098 | context40(F f, C0 c0, C1 c1, C2 c2, C3 c3) 2099 | : f(f), c0(c0), c1(c1), c2(c2), c3(c3) {} 2100 | 2101 | void operator()() { 2102 | f(c0, c1, c2, c3); 2103 | } 2104 | }; 2105 | 2106 | template 2107 | struct context50 { 2108 | F f; C0 c0; C1 c1; C2 c2; C3 c3; C4 c4; 2109 | 2110 | context50(F f, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) 2111 | : f(f), c0(c0), c1(c1), c2(c2), c3(c3), c4(c4) {} 2112 | 2113 | void operator()() { 2114 | f(c0, c1, c2, c3, c4); 2115 | } 2116 | }; 2117 | 2118 | template 2119 | struct context01 { 2120 | F f; 2121 | 2122 | context01(F f) 2123 | : f(f) {} 2124 | 2125 | void operator()(A0 a0) { 2126 | f(a0); 2127 | } 2128 | }; 2129 | 2130 | template 2131 | struct context11 { 2132 | F f; C0 c0; 2133 | 2134 | context11(F f, C0 c0) 2135 | : f(f), c0(c0) {} 2136 | 2137 | void operator()(A0 a0) { 2138 | f(c0, a0); 2139 | } 2140 | }; 2141 | 2142 | template 2143 | struct context21 { 2144 | F f; C0 c0; C1 c1; 2145 | 2146 | context21(F f, C0 c0, C1 c1) 2147 | : f(f), c0(c0), c1(c1) {} 2148 | 2149 | void operator()(A0 a0) { 2150 | f(c0, c1, a0); 2151 | } 2152 | }; 2153 | 2154 | template 2155 | struct context31 { 2156 | F f; C0 c0; C1 c1; C2 c2; 2157 | 2158 | context31(F f, C0 c0, C1 c1, C2 c2) 2159 | : f(f), c0(c0), c1(c1), c2(c2) {} 2160 | 2161 | void operator()(A0 a0) { 2162 | f(c0, c1, c2, a0); 2163 | } 2164 | }; 2165 | 2166 | template 2167 | struct context41 { 2168 | F f; C0 c0; C1 c1; C2 c2; C3 c3; 2169 | 2170 | context41(F f, C0 c0, C1 c1, C2 c2, C3 c3) 2171 | : f(f), c0(c0), c1(c1), c2(c2), c3(c3) {} 2172 | 2173 | void operator()(A0 a0) { 2174 | f(c0, c1, c2, c3, a0); 2175 | } 2176 | }; 2177 | 2178 | template 2179 | struct context51 { 2180 | F f; C0 c0; C1 c1; C2 c2; C3 c3; C4 c4; 2181 | 2182 | context51(F f, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) 2183 | : f(f), c0(c0), c1(c1), c2(c2), c3(c3), c4(c4) {} 2184 | 2185 | void operator()(A0 a0) { 2186 | f(c0, c1, c2, c3, c4, a0); 2187 | } 2188 | }; 2189 | 2190 | template 2191 | struct context02 { 2192 | F f; 2193 | 2194 | context02(F f) 2195 | : f(f) {} 2196 | 2197 | void operator()(A0 a0, A1 a1) { 2198 | f(a0, a1); 2199 | } 2200 | }; 2201 | 2202 | template 2203 | struct context12 { 2204 | F f; C0 c0; 2205 | 2206 | context12(F f, C0 c0) 2207 | : f(f), c0(c0) {} 2208 | 2209 | void operator()(A0 a0, A1 a1) { 2210 | f(c0, a0, a1); 2211 | } 2212 | }; 2213 | 2214 | template 2215 | struct context22 { 2216 | F f; C0 c0; C1 c1; 2217 | 2218 | context22(F f, C0 c0, C1 c1) 2219 | : f(f), c0(c0), c1(c1) {} 2220 | 2221 | void operator()(A0 a0, A1 a1) { 2222 | f(c0, c1, a0, a1); 2223 | } 2224 | }; 2225 | 2226 | template 2227 | struct context32 { 2228 | F f; C0 c0; C1 c1; C2 c2; 2229 | 2230 | context32(F f, C0 c0, C1 c1, C2 c2) 2231 | : f(f), c0(c0), c1(c1), c2(c2) {} 2232 | 2233 | void operator()(A0 a0, A1 a1) { 2234 | f(c0, c1, c2, a0, a1); 2235 | } 2236 | }; 2237 | 2238 | template 2239 | struct context42 { 2240 | F f; C0 c0; C1 c1; C2 c2; C3 c3; 2241 | 2242 | context42(F f, C0 c0, C1 c1, C2 c2, C3 c3) 2243 | : f(f), c0(c0), c1(c1), c2(c2), c3(c3) {} 2244 | 2245 | void operator()(A0 a0, A1 a1) { 2246 | f(c0, c1, c2, c3, a0, a1); 2247 | } 2248 | }; 2249 | 2250 | template 2251 | struct context52 { 2252 | F f; C0 c0; C1 c1; C2 c2; C3 c3; C4 c4; 2253 | 2254 | context52(F f, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) 2255 | : f(f), c0(c0), c1(c1), c2(c2), c3(c3), c4(c4) {} 2256 | 2257 | void operator()(A0 a0, A1 a1) { 2258 | f(c0, c1, c2, c3, c4, a0, a1); 2259 | } 2260 | }; 2261 | 2262 | template 2263 | struct context03 { 2264 | F f; 2265 | 2266 | context03(F f) 2267 | : f(f) {} 2268 | 2269 | void operator()(A0 a0, A1 a1, A2 a2) { 2270 | f(a0, a1, a2); 2271 | } 2272 | }; 2273 | 2274 | template 2275 | struct context13 { 2276 | F f; C0 c0; 2277 | 2278 | context13(F f, C0 c0) 2279 | : f(f), c0(c0) {} 2280 | 2281 | void operator()(A0 a0, A1 a1, A2 a2) { 2282 | f(c0, a0, a1, a2); 2283 | } 2284 | }; 2285 | 2286 | template 2287 | struct context23 { 2288 | F f; C0 c0; C1 c1; 2289 | 2290 | context23(F f, C0 c0, C1 c1) 2291 | : f(f), c0(c0), c1(c1) {} 2292 | 2293 | void operator()(A0 a0, A1 a1, A2 a2) { 2294 | f(c0, c1, a0, a1, a2); 2295 | } 2296 | }; 2297 | 2298 | template 2299 | struct context33 { 2300 | F f; C0 c0; C1 c1; C2 c2; 2301 | 2302 | context33(F f, C0 c0, C1 c1, C2 c2) 2303 | : f(f), c0(c0), c1(c1), c2(c2) {} 2304 | 2305 | void operator()(A0 a0, A1 a1, A2 a2) { 2306 | f(c0, c1, c2, a0, a1, a2); 2307 | } 2308 | }; 2309 | 2310 | template 2311 | struct context43 { 2312 | F f; C0 c0; C1 c1; C2 c2; C3 c3; 2313 | 2314 | context43(F f, C0 c0, C1 c1, C2 c2, C3 c3) 2315 | : f(f), c0(c0), c1(c1), c2(c2), c3(c3) {} 2316 | 2317 | void operator()(A0 a0, A1 a1, A2 a2) { 2318 | f(c0, c1, c2, c3, a0, a1, a2); 2319 | } 2320 | }; 2321 | 2322 | template 2323 | struct context53 { 2324 | F f; C0 c0; C1 c1; C2 c2; C3 c3; C4 c4; 2325 | 2326 | context53(F f, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) 2327 | : f(f), c0(c0), c1(c1), c2(c2), c3(c3), c4(c4) {} 2328 | 2329 | void operator()(A0 a0, A1 a1, A2 a2) { 2330 | f(c0, c1, c2, c3, c4, a0, a1, a2); 2331 | } 2332 | }; 2333 | 2334 | template 2335 | struct context04 { 2336 | F f; 2337 | 2338 | context04(F f) 2339 | : f(f) {} 2340 | 2341 | void operator()(A0 a0, A1 a1, A2 a2, A3 a3) { 2342 | f(a0, a1, a2, a3); 2343 | } 2344 | }; 2345 | 2346 | template 2347 | struct context14 { 2348 | F f; C0 c0; 2349 | 2350 | context14(F f, C0 c0) 2351 | : f(f), c0(c0) {} 2352 | 2353 | void operator()(A0 a0, A1 a1, A2 a2, A3 a3) { 2354 | f(c0, a0, a1, a2, a3); 2355 | } 2356 | }; 2357 | 2358 | template 2359 | struct context24 { 2360 | F f; C0 c0; C1 c1; 2361 | 2362 | context24(F f, C0 c0, C1 c1) 2363 | : f(f), c0(c0), c1(c1) {} 2364 | 2365 | void operator()(A0 a0, A1 a1, A2 a2, A3 a3) { 2366 | f(c0, c1, a0, a1, a2, a3); 2367 | } 2368 | }; 2369 | 2370 | template 2371 | struct context34 { 2372 | F f; C0 c0; C1 c1; C2 c2; 2373 | 2374 | context34(F f, C0 c0, C1 c1, C2 c2) 2375 | : f(f), c0(c0), c1(c1), c2(c2) {} 2376 | 2377 | void operator()(A0 a0, A1 a1, A2 a2, A3 a3) { 2378 | f(c0, c1, c2, a0, a1, a2, a3); 2379 | } 2380 | }; 2381 | 2382 | template 2383 | struct context44 { 2384 | F f; C0 c0; C1 c1; C2 c2; C3 c3; 2385 | 2386 | context44(F f, C0 c0, C1 c1, C2 c2, C3 c3) 2387 | : f(f), c0(c0), c1(c1), c2(c2), c3(c3) {} 2388 | 2389 | void operator()(A0 a0, A1 a1, A2 a2, A3 a3) { 2390 | f(c0, c1, c2, c3, a0, a1, a2, a3); 2391 | } 2392 | }; 2393 | 2394 | template 2395 | struct context54 { 2396 | F f; C0 c0; C1 c1; C2 c2; C3 c3; C4 c4; 2397 | 2398 | context54(F f, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) 2399 | : f(f), c0(c0), c1(c1), c2(c2), c3(c3), c4(c4) {} 2400 | 2401 | void operator()(A0 a0, A1 a1, A2 a2, A3 a3) { 2402 | f(c0, c1, c2, c3, c4, a0, a1, a2, a3); 2403 | } 2404 | }; 2405 | 2406 | template 2407 | struct context05 { 2408 | F f; 2409 | 2410 | context05(F f) 2411 | : f(f) {} 2412 | 2413 | void operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { 2414 | f(a0, a1, a2, a3, a4); 2415 | } 2416 | }; 2417 | 2418 | template 2419 | struct context15 { 2420 | F f; C0 c0; 2421 | 2422 | context15(F f, C0 c0) 2423 | : f(f), c0(c0) {} 2424 | 2425 | void operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { 2426 | f(c0, a0, a1, a2, a3, a4); 2427 | } 2428 | }; 2429 | 2430 | template 2431 | struct context25 { 2432 | F f; C0 c0; C1 c1; 2433 | 2434 | context25(F f, C0 c0, C1 c1) 2435 | : f(f), c0(c0), c1(c1) {} 2436 | 2437 | void operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { 2438 | f(c0, c1, a0, a1, a2, a3, a4); 2439 | } 2440 | }; 2441 | 2442 | template 2443 | struct context35 { 2444 | F f; C0 c0; C1 c1; C2 c2; 2445 | 2446 | context35(F f, C0 c0, C1 c1, C2 c2) 2447 | : f(f), c0(c0), c1(c1), c2(c2) {} 2448 | 2449 | void operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { 2450 | f(c0, c1, c2, a0, a1, a2, a3, a4); 2451 | } 2452 | }; 2453 | 2454 | template 2455 | struct context45 { 2456 | F f; C0 c0; C1 c1; C2 c2; C3 c3; 2457 | 2458 | context45(F f, C0 c0, C1 c1, C2 c2, C3 c3) 2459 | : f(f), c0(c0), c1(c1), c2(c2), c3(c3) {} 2460 | 2461 | void operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { 2462 | f(c0, c1, c2, c3, a0, a1, a2, a3, a4); 2463 | } 2464 | }; 2465 | 2466 | template 2467 | struct context55 { 2468 | F f; C0 c0; C1 c1; C2 c2; C3 c3; C4 c4; 2469 | 2470 | context55(F f, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) 2471 | : f(f), c0(c0), c1(c1), c2(c2), c3(c3), c4(c4) {} 2472 | 2473 | void operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { 2474 | f(c0, c1, c2, c3, c4, a0, a1, a2, a3, a4); 2475 | } 2476 | }; 2477 | }; 2478 | 2479 | } 2480 | 2481 | #endif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, and 10 | distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright 13 | owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other entities 16 | that control, are controlled by, or are under common control with that entity. 17 | For the purposes of this definition, "control" means (i) the power, direct or 18 | indirect, to cause the direction or management of such entity, whether by 19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the 20 | outstanding shares, or (iii) beneficial ownership of such entity. 21 | 22 | "You" (or "Your") shall mean an individual or Legal Entity exercising 23 | permissions granted by this License. 24 | 25 | "Source" form shall mean the preferred form for making modifications, including 26 | but not limited to software source code, documentation source, and configuration 27 | files. 28 | 29 | "Object" form shall mean any form resulting from mechanical transformation or 30 | translation of a Source form, including but not limited to compiled object code, 31 | generated documentation, and conversions to other media types. 32 | 33 | "Work" shall mean the work of authorship, whether in Source or Object form, made 34 | available under the License, as indicated by a copyright notice that is included 35 | in or attached to the work (an example is provided in the Appendix below). 36 | 37 | "Derivative Works" shall mean any work, whether in Source or Object form, that 38 | is based on (or derived from) the Work and for which the editorial revisions, 39 | annotations, elaborations, or other modifications represent, as a whole, an 40 | original work of authorship. For the purposes of this License, Derivative Works 41 | shall not include works that remain separable from, or merely link (or bind by 42 | name) to the interfaces of, the Work and Derivative Works thereof. 43 | 44 | "Contribution" shall mean any work of authorship, including the original version 45 | of the Work and any modifications or additions to that Work or Derivative Works 46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work 47 | by the copyright owner or by an individual or Legal Entity authorized to submit 48 | on behalf of the copyright owner. For the purposes of this definition, 49 | "submitted" means any form of electronic, verbal, or written communication sent 50 | to the Licensor or its representatives, including but not limited to 51 | communication on electronic mailing lists, source code control systems, and 52 | issue tracking systems that are managed by, or on behalf of, the Licensor for 53 | the purpose of discussing and improving the Work, but excluding communication 54 | that is conspicuously marked or otherwise designated in writing by the copyright 55 | owner as "Not a Contribution." 56 | 57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf 58 | of whom a Contribution has been received by Licensor and subsequently 59 | incorporated within the Work. 60 | 61 | 2. Grant of Copyright License. 62 | 63 | Subject to the terms and conditions of this License, each Contributor hereby 64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 65 | irrevocable copyright license to reproduce, prepare Derivative Works of, 66 | publicly display, publicly perform, sublicense, and distribute the Work and such 67 | Derivative Works in Source or Object form. 68 | 69 | 3. Grant of Patent License. 70 | 71 | Subject to the terms and conditions of this License, each Contributor hereby 72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 73 | irrevocable (except as stated in this section) patent license to make, have 74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where 75 | such license applies only to those patent claims licensable by such Contributor 76 | that are necessarily infringed by their Contribution(s) alone or by combination 77 | of their Contribution(s) with the Work to which such Contribution(s) was 78 | submitted. If You institute patent litigation against any entity (including a 79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 80 | Contribution incorporated within the Work constitutes direct or contributory 81 | patent infringement, then any patent licenses granted to You under this License 82 | for that Work shall terminate as of the date such litigation is filed. 83 | 84 | 4. Redistribution. 85 | 86 | You may reproduce and distribute copies of the Work or Derivative Works thereof 87 | in any medium, with or without modifications, and in Source or Object form, 88 | provided that You meet the following conditions: 89 | 90 | You must give any other recipients of the Work or Derivative Works a copy of 91 | this License; and 92 | You must cause any modified files to carry prominent notices stating that You 93 | changed the files; and 94 | You must retain, in the Source form of any Derivative Works that You distribute, 95 | all copyright, patent, trademark, and attribution notices from the Source form 96 | of the Work, excluding those notices that do not pertain to any part of the 97 | Derivative Works; and 98 | If the Work includes a "NOTICE" text file as part of its distribution, then any 99 | Derivative Works that You distribute must include a readable copy of the 100 | attribution notices contained within such NOTICE file, excluding those notices 101 | that do not pertain to any part of the Derivative Works, in at least one of the 102 | following places: within a NOTICE text file distributed as part of the 103 | Derivative Works; within the Source form or documentation, if provided along 104 | with the Derivative Works; or, within a display generated by the Derivative 105 | Works, if and wherever such third-party notices normally appear. The contents of 106 | the NOTICE file are for informational purposes only and do not modify the 107 | License. You may add Your own attribution notices within Derivative Works that 108 | You distribute, alongside or as an addendum to the NOTICE text from the Work, 109 | provided that such additional attribution notices cannot be construed as 110 | modifying the License. 111 | You may add Your own copyright statement to Your modifications and may provide 112 | additional or different license terms and conditions for use, reproduction, or 113 | distribution of Your modifications, or for any such Derivative Works as a whole, 114 | provided Your use, reproduction, and distribution of the Work otherwise complies 115 | with the conditions stated in this License. 116 | 117 | 5. Submission of Contributions. 118 | 119 | Unless You explicitly state otherwise, any Contribution intentionally submitted 120 | for inclusion in the Work by You to the Licensor shall be under the terms and 121 | conditions of this License, without any additional terms or conditions. 122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of 123 | any separate license agreement you may have executed with Licensor regarding 124 | such Contributions. 125 | 126 | 6. Trademarks. 127 | 128 | This License does not grant permission to use the trade names, trademarks, 129 | service marks, or product names of the Licensor, except as required for 130 | reasonable and customary use in describing the origin of the Work and 131 | reproducing the content of the NOTICE file. 132 | 133 | 7. Disclaimer of Warranty. 134 | 135 | Unless required by applicable law or agreed to in writing, Licensor provides the 136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, 137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, 138 | including, without limitation, any warranties or conditions of TITLE, 139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are 140 | solely responsible for determining the appropriateness of using or 141 | redistributing the Work and assume any risks associated with Your exercise of 142 | permissions under this License. 143 | 144 | 8. Limitation of Liability. 145 | 146 | In no event and under no legal theory, whether in tort (including negligence), 147 | contract, or otherwise, unless required by applicable law (such as deliberate 148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be 149 | liable to You for damages, including any direct, indirect, special, incidental, 150 | or consequential damages of any character arising as a result of this License or 151 | out of the use or inability to use the Work (including but not limited to 152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or 153 | any and all other commercial damages or losses), even if such Contributor has 154 | been advised of the possibility of such damages. 155 | 156 | 9. Accepting Warranty or Additional Liability. 157 | 158 | While redistributing the Work or Derivative Works thereof, You may choose to 159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or 160 | other liability obligations and/or rights consistent with this License. However, 161 | in accepting such obligations, You may act only on Your own behalf and on Your 162 | sole responsibility, not on behalf of any other Contributor, and only if You 163 | agree to indemnify, defend, and hold each Contributor harmless for any liability 164 | incurred by, or claims asserted against, such Contributor by reason of your 165 | accepting any such warranty or additional liability. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## The mbed-events library ## 2 | 3 | The mbed-events library provides a flexible queue for scheduling events. 4 | 5 | ``` cpp 6 | #include "mbed_events.h" 7 | #include 8 | 9 | int main() { 10 | // creates a queue with the default size 11 | EventQueue queue; 12 | 13 | // events are simple callbacks 14 | queue.call(printf, "called immediately\n"); 15 | queue.call_in(2000, printf, "called in 2 seconds\n"); 16 | queue.call_every(1000, printf, "called every 1 seconds\n"); 17 | 18 | // events are executed by the dispatch method 19 | queue.dispatch(); 20 | } 21 | ``` 22 | 23 | The mbed-events library can be used as a normal event loop, or it can be 24 | backgrounded on a single hardware timer or even another event loop. It is 25 | both thread and irq safe, and provides functions for easily composing 26 | independent event queues. 27 | 28 | The mbed-events library can act as a drop-in scheduler, provide synchronization 29 | between multiple threads, or just act as a mechanism for moving events out of 30 | interrupt contexts. 31 | 32 | ### Usage ### 33 | 34 | The core of the mbed-events library is the [EventQueue](EventQueue.h) class, 35 | which represents a single event queue. The `EventQueue::dispatch` function 36 | runs the queue, providing the context for executing events. 37 | 38 | ``` cpp 39 | // Creates an event queue enough buffer space for 32 Callbacks. This 40 | // is the default if no argument was provided. Alternatively the size 41 | // can just be specified in bytes. 42 | EventQueue queue(32*EVENTS_EVENT_SIZE); 43 | 44 | // Events can be posted to the underlying event queue with dynamic 45 | // context allocated from the specified buffer 46 | queue.call(printf, "hello %d %d %d %d\n", 1, 2, 3, 4); 47 | queue.call(&serial, &Serial::printf, "hi\n"); 48 | 49 | // The dispatch function provides the context for the running the queue 50 | // and can take a millisecond timeout to run for a fixed time or to just 51 | // dispatch any pending events 52 | queue.dispatch(); 53 | ``` 54 | 55 | The EventQueue class provides several call functions for posting events 56 | to the underlying event queue. The call functions are thread and irq safe, 57 | don't need the underlying loop to be running, and provide an easy mechanism 58 | for moving events out of interrupt contexts. 59 | 60 | ``` cpp 61 | // Simple call function registers events to be called as soon as possible 62 | queue.call(doit); 63 | queue.call(printf, "called immediately\n"); 64 | 65 | // The call_in function registers events to be called after a delay 66 | // specified in milliseconds 67 | queue.call_in(2000, doit_in_two_seconds); 68 | queue.call_in(300, printf, "called in 0.3 seconds\n"); 69 | 70 | // The call_every function registers events to be called repeatedly 71 | // with a period specified in milliseconds 72 | queue.call_every(2000, doit_every_two_seconds); 73 | queue.call_every(400, printf, "called every 0.4 seconds\n"); 74 | ``` 75 | 76 | The call functions return an id that uniquely represents the event in the 77 | the event queue. This id can be passed to `EventQueue::cancel` to cancel 78 | an in-flight event. 79 | 80 | ``` cpp 81 | // The event id uniquely represents the event in the queue 82 | int id = queue.call_in(100, printf, "will this work?\n"); 83 | 84 | // If there was not enough memory necessary to allocate the event, 85 | // an id of 0 is returned from the call functions 86 | if (id) { 87 | error("oh no!"); 88 | } 89 | 90 | // Events can be cancelled as long as they have not been dispatched. If the 91 | // event has already expired, cancel has no side-effects. 92 | queue.cancel(id); 93 | ``` 94 | 95 | For a more fine-grain control of event dispatch, the `Event` class can be 96 | manually instantiated and configured. An `Event` represents an event as 97 | a C++ style function object and can be directly passed to other APIs that 98 | expect a callback. 99 | 100 | ``` cpp 101 | // Creates an event bound to the specified event queue 102 | EventQueue queue; 103 | Event event(&queue, doit); 104 | 105 | // The event can be manually configured for special timing requirements 106 | // specified in milliseconds 107 | event.delay(10); 108 | event.period(10000); 109 | 110 | // Posted events are dispatched in the context of the queue's 111 | // dispatch function 112 | queue.dispatch(); 113 | 114 | // Events can also pass arguments to the underlying callback when both 115 | // initially constructed and posted. 116 | Event event(&queue, printf, "recieved %d and %d\n"); 117 | 118 | // Events can be posted multiple times and enqueue gracefully until 119 | // the dispatch function is called. 120 | event.post(1, 2); 121 | event.post(3, 4); 122 | event.post(5, 6); 123 | 124 | queue.dispatch(); 125 | ``` 126 | 127 | Event queues easily align with module boundaries, where internal state can 128 | be implicitly synchronized through event dispatch. Multiple modules can 129 | use independent event queues, but still be composed through the 130 | `EventQueue::chain` function. 131 | 132 | ``` cpp 133 | // Create some event queues with pending events 134 | EventQueue a; 135 | a.call(printf, "hello from a!\n"); 136 | 137 | EventQueue b; 138 | b.call(printf, "hello from b!\n"); 139 | 140 | EventQueue c; 141 | c.call(printf, "hello from c!\n"); 142 | 143 | // Chain c and b onto a's event queue. Both c and b will be dispatched 144 | // in the context of a's dispatch function. 145 | c.chain(&a); 146 | b.chain(&a); 147 | 148 | // Dispatching a will in turn dispatch b and c, printing hello from 149 | // all three queues 150 | a.dispatch(); 151 | ``` 152 | 153 | 154 | -------------------------------------------------------------------------------- /TESTS/events/queue/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mbed_events.h" 2 | #include "mbed.h" 3 | #include "rtos.h" 4 | #include "greentea-client/test_env.h" 5 | #include "unity.h" 6 | #include "utest.h" 7 | 8 | using namespace utest::v1; 9 | 10 | 11 | // flag for called 12 | volatile bool touched = false; 13 | 14 | // static functions 15 | void func5(int a0, int a1, int a2, int a3, int a4) { 16 | touched = true; 17 | TEST_ASSERT_EQUAL(a0 | a1 | a2 | a3 | a4, 0x1f); 18 | } 19 | 20 | void func4(int a0, int a1, int a2, int a3) { 21 | touched = true; 22 | TEST_ASSERT_EQUAL(a0 | a1 | a2 | a3, 0xf); 23 | } 24 | 25 | void func3(int a0, int a1, int a2) { 26 | touched = true; 27 | TEST_ASSERT_EQUAL(a0 | a1 | a2, 0x7); 28 | } 29 | 30 | void func2(int a0, int a1) { 31 | touched = true; 32 | TEST_ASSERT_EQUAL(a0 | a1, 0x3); 33 | } 34 | 35 | void func1(int a0) { 36 | touched = true; 37 | TEST_ASSERT_EQUAL(a0, 0x1); 38 | } 39 | 40 | void func0() { 41 | touched = true; 42 | } 43 | 44 | #define SIMPLE_POSTS_TEST(i, ...) \ 45 | void simple_posts_test##i() { \ 46 | EventQueue queue; \ 47 | \ 48 | touched = false; \ 49 | queue.call(func##i,##__VA_ARGS__); \ 50 | queue.dispatch(0); \ 51 | TEST_ASSERT(touched); \ 52 | \ 53 | touched = false; \ 54 | queue.call_in(1, func##i,##__VA_ARGS__); \ 55 | queue.dispatch(2); \ 56 | TEST_ASSERT(touched); \ 57 | \ 58 | touched = false; \ 59 | queue.call_every(1, func##i,##__VA_ARGS__); \ 60 | queue.dispatch(2); \ 61 | TEST_ASSERT(touched); \ 62 | } 63 | 64 | SIMPLE_POSTS_TEST(5, 0x01, 0x02, 0x04, 0x08, 0x010) 65 | SIMPLE_POSTS_TEST(4, 0x01, 0x02, 0x04, 0x08) 66 | SIMPLE_POSTS_TEST(3, 0x01, 0x02, 0x04) 67 | SIMPLE_POSTS_TEST(2, 0x01, 0x02) 68 | SIMPLE_POSTS_TEST(1, 0x01) 69 | SIMPLE_POSTS_TEST(0) 70 | 71 | 72 | void time_func(Timer *t, int ms) { 73 | TEST_ASSERT_INT_WITHIN(2, ms, t->read_ms()); 74 | t->reset(); 75 | } 76 | 77 | template 78 | void call_in_test() { 79 | Timer tickers[N]; 80 | 81 | EventQueue queue; 82 | 83 | for (int i = 0; i < N; i++) { 84 | tickers[i].start(); 85 | queue.call_in((i+1)*100, time_func, &tickers[i], (i+1)*100); 86 | } 87 | 88 | queue.dispatch(N*100); 89 | } 90 | 91 | template 92 | void call_every_test() { 93 | Timer tickers[N]; 94 | 95 | EventQueue queue; 96 | 97 | for (int i = 0; i < N; i++) { 98 | tickers[i].start(); 99 | queue.call_every((i+1)*100, time_func, &tickers[i], (i+1)*100); 100 | } 101 | 102 | queue.dispatch(N*100); 103 | } 104 | 105 | struct big { char data[1024]; } big; 106 | 107 | void allocate_failure_test1() { 108 | EventQueue queue(32); 109 | int id = queue.call((void (*)(struct big))0, big); 110 | TEST_ASSERT(!id); 111 | } 112 | 113 | void allocate_failure_test2() { 114 | EventQueue queue; 115 | int id; 116 | 117 | for (int i = 0; i < 100; i++) { 118 | id = queue.call((void (*)())0); 119 | } 120 | 121 | TEST_ASSERT(!id); 122 | } 123 | 124 | void no() { 125 | TEST_ASSERT(false); 126 | } 127 | 128 | template 129 | void cancel_test1() { 130 | EventQueue queue; 131 | 132 | int ids[N]; 133 | 134 | for (int i = 0; i < N; i++) { 135 | ids[i] = queue.call_in(1000, no); 136 | } 137 | 138 | for (int i = N-1; i >= 0; i--) { 139 | queue.cancel(ids[i]); 140 | } 141 | 142 | queue.dispatch(0); 143 | } 144 | 145 | 146 | // Testing the dynamic arguments to the event class 147 | unsigned counter = 0; 148 | 149 | void count5(unsigned a0, unsigned a1, unsigned a2, unsigned a3, unsigned a5) { 150 | counter += a0 + a1 + a2 + a3 + a5; 151 | } 152 | 153 | void count4(unsigned a0, unsigned a1, unsigned a2, unsigned a3) { 154 | counter += a0 + a1 + a2 + a3; 155 | } 156 | 157 | void count3(unsigned a0, unsigned a1, unsigned a2) { 158 | counter += a0 + a1 + a2; 159 | } 160 | 161 | void count2(unsigned a0, unsigned a1) { 162 | counter += a0 + a1; 163 | } 164 | 165 | void count1(unsigned a0) { 166 | counter += a0; 167 | } 168 | 169 | void count0() { 170 | counter += 0; 171 | } 172 | 173 | void event_class_test() { 174 | counter = 0; 175 | EventQueue queue(2048); 176 | 177 | Event e5(&queue, count5); 178 | Event e4(&queue, count5, 1); 179 | Event e3(&queue, count5, 1, 1); 180 | Event e2(&queue, count5, 1, 1, 1); 181 | Event e1(&queue, count5, 1, 1, 1, 1); 182 | Event e0(&queue, count5, 1, 1, 1, 1, 1); 183 | 184 | e5.post(1, 1, 1, 1, 1); 185 | e4.post(1, 1, 1, 1); 186 | e3.post(1, 1, 1); 187 | e2.post(1, 1); 188 | e1.post(1); 189 | e0.post(); 190 | 191 | queue.dispatch(0); 192 | 193 | TEST_ASSERT_EQUAL(counter, 30); 194 | } 195 | 196 | void event_class_helper_test() { 197 | counter = 0; 198 | EventQueue queue(2048); 199 | 200 | Event e5 = queue.event(count5, 1, 1, 1, 1, 1); 201 | Event e4 = queue.event(count4, 1, 1, 1, 1); 202 | Event e3 = queue.event(count3, 1, 1, 1); 203 | Event e2 = queue.event(count2, 1, 1); 204 | Event e1 = queue.event(count1, 1); 205 | Event e0 = queue.event(count0); 206 | 207 | e5.post(); 208 | e4.post(); 209 | e3.post(); 210 | e2.post(); 211 | e1.post(); 212 | e0.post(); 213 | 214 | queue.dispatch(0); 215 | 216 | TEST_ASSERT_EQUAL(counter, 15); 217 | } 218 | 219 | void event_inference_test() { 220 | counter = 0; 221 | EventQueue queue (2048); 222 | 223 | queue.event(count5, 1, 1, 1, 1, 1).post(); 224 | queue.event(count5, 1, 1, 1, 1).post(1); 225 | queue.event(count5, 1, 1, 1).post(1, 1); 226 | queue.event(count5, 1, 1).post(1, 1, 1); 227 | queue.event(count5, 1).post(1, 1, 1, 1); 228 | queue.event(count5).post(1, 1, 1, 1, 1); 229 | 230 | queue.dispatch(0); 231 | 232 | TEST_ASSERT_EQUAL(counter, 30); 233 | } 234 | 235 | 236 | // Test setup 237 | utest::v1::status_t test_setup(const size_t number_of_cases) { 238 | GREENTEA_SETUP(20, "default_auto"); 239 | return verbose_test_setup_handler(number_of_cases); 240 | } 241 | 242 | const Case cases[] = { 243 | Case("Testing calls with 5 args", simple_posts_test5), 244 | Case("Testing calls with 4 args", simple_posts_test4), 245 | Case("Testing calls with 3 args", simple_posts_test3), 246 | Case("Testing calls with 2 args", simple_posts_test2), 247 | Case("Testing calls with 1 args", simple_posts_test1), 248 | Case("Testing calls with 0 args", simple_posts_test0), 249 | 250 | Case("Testing call_in", call_in_test<20>), 251 | Case("Testing call_every", call_every_test<20>), 252 | 253 | Case("Testing allocate failure 1", allocate_failure_test1), 254 | Case("Testing allocate failure 2", allocate_failure_test2), 255 | 256 | Case("Testing event cancel 1", cancel_test1<20>), 257 | Case("Testing the event class", event_class_test), 258 | Case("Testing the event class helpers", event_class_helper_test), 259 | Case("Testing the event inference", event_inference_test), 260 | }; 261 | 262 | Specification specification(test_setup, cases); 263 | 264 | int main() { 265 | return !Harness::run(specification); 266 | } 267 | 268 | -------------------------------------------------------------------------------- /equeue/.travis.yml: -------------------------------------------------------------------------------- 1 | script: 2 | # Strict compilation of library 3 | - CFLAGS='-pedantic -Werror' make 4 | 5 | # Runtime tests 6 | - make test 7 | 8 | # Relative profiling with current master 9 | - if ( git clone https://github.com/geky/events tests/master && 10 | make -s -C tests/master prof | tee tests/results.txt ) ; 11 | then 12 | cat tests/results.txt | make prof ; 13 | else 14 | make prof ; 15 | fi 16 | -------------------------------------------------------------------------------- /equeue/LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Christopher Haster 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a 4 | copy of this software and associated documentation files (the "Software"), 5 | to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | and/or sell copies of the Software, and to permit persons to whom the 8 | Software is furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /equeue/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = libequeue.a 2 | 3 | CC = gcc 4 | AR = ar 5 | SIZE = size 6 | 7 | SRC += $(wildcard *.c) 8 | OBJ := $(SRC:.c=.o) 9 | DEP := $(SRC:.c=.d) 10 | ASM := $(SRC:.c=.s) 11 | 12 | ifdef DEBUG 13 | CFLAGS += -O0 -g3 14 | else 15 | CFLAGS += -O2 16 | endif 17 | ifdef WORD 18 | CFLAGS += -m$(WORD) 19 | endif 20 | CFLAGS += -I. 21 | CFLAGS += -std=c99 22 | CFLAGS += -Wall 23 | CFLAGS += -D_XOPEN_SOURCE=600 24 | 25 | LFLAGS += -pthread 26 | 27 | 28 | all: $(TARGET) 29 | 30 | test: tests/tests.o $(OBJ) 31 | $(CC) $(CFLAGS) $^ $(LFLAGS) -o tests/tests 32 | tests/tests 33 | 34 | prof: tests/prof.o $(OBJ) 35 | $(CC) $(CFLAGS) $^ $(LFLAGS) -o tests/prof 36 | tests/prof 37 | 38 | asm: $(ASM) 39 | 40 | size: $(OBJ) 41 | $(SIZE) -t $^ 42 | 43 | -include $(DEP) 44 | 45 | %.a: $(OBJ) 46 | $(AR) rcs $@ $^ 47 | 48 | %.o: %.c 49 | $(CC) -c -MMD $(CFLAGS) $< -o $@ 50 | 51 | %.s: %.c 52 | $(CC) -S $(CFLAGS) $< -o $@ 53 | 54 | clean: 55 | rm -f $(TARGET) 56 | rm -f tests/tests tests/tests.o tests/tests.d 57 | rm -f tests/prof tests/prof.o tests/prof.d 58 | rm -f $(OBJ) 59 | rm -f $(DEP) 60 | rm -f $(ASM) 61 | -------------------------------------------------------------------------------- /equeue/README.md: -------------------------------------------------------------------------------- 1 | ## The equeue library ## 2 | 3 | The equeue library is designed as a simple but powerful library for scheduling 4 | events on composable queues. 5 | 6 | ``` c 7 | #include "equeue.h" 8 | #include 9 | 10 | int main() { 11 | // creates a queue with space for 32 basic events 12 | equeue_t queue; 13 | equeue_create(&queue, 32*EQUEUE_EVENT_SIZE); 14 | 15 | // events can be simple callbacks 16 | equeue_call(&queue, print, "called immediately"); 17 | equeue_call_in(&queue, 2000, print, "called in 2 seconds"); 18 | equeue_call_every(&queue, 1000, print, "called every 1 seconds"); 19 | 20 | // events are executed in equeue_dispatch 21 | equeue_dispatch(&queue, 3000); 22 | 23 | print("called after 3 seconds"); 24 | 25 | equeue_destroy(&queue); 26 | } 27 | ``` 28 | 29 | The equeue library can be used as a normal event loop, or it can be 30 | backgrounded on a single hardware timer or even another event loop. It 31 | is both thread and irq safe, and provides functions for easily composing 32 | multiple queues. 33 | 34 | The equeue library can act as a drop-in scheduler, provide synchronization 35 | between multiple threads, or just act as a mechanism for moving events 36 | out of interrupt contexts. 37 | 38 | ## Documentation ## 39 | 40 | The in-depth documentation on specific functions can be found in 41 | [equeue.h](equeue.h). 42 | 43 | The core of the equeue library is the `equeue_t` type which represents a 44 | single event queue, and the `equeue_dispatch` function which runs the equeue, 45 | providing the context for executing events. 46 | 47 | On top of this, `equeue_call`, `equeue_call_in`, and `equeue_call_every` 48 | provide easy methods for posting events to execute in the context of the 49 | `equeue_dispatch` function. 50 | 51 | ``` c 52 | #include "equeue.h" 53 | #include "game.h" 54 | 55 | equeue_t queue; 56 | struct game game; 57 | 58 | // button_isr may be in interrupt context 59 | void button_isr(void) { 60 | equeue_call(&queue, game_button_update, &game); 61 | } 62 | 63 | // a simple user-interface framework 64 | int main() { 65 | equeue_create(&queue, 4096); 66 | game_create(&game); 67 | 68 | // call game_screen_udpate at 60 Hz 69 | equeue_call_every(&queue, 1000/60, game_screen_update, &game); 70 | 71 | // dispatch forever 72 | equeue_dispatch(&queue, -1); 73 | } 74 | ``` 75 | 76 | In addition to simple callbacks, an event can be manually allocated with 77 | `equeue_alloc` and posted with `equeue_post` to allow passing an arbitrary 78 | amount of context to the execution of the event. This memory is allocated out 79 | of the equeue's buffer, and dynamic memory can be completely avoided. 80 | 81 | The equeue allocator is designed to minimize jitter in interrupt contexts as 82 | well as avoid memory fragmentation on small devices. The allocator achieves 83 | both constant-runtime and zero-fragmentation for fixed-size events, however 84 | grows linearly as the quantity of differently-sized allocations increases. 85 | 86 | ``` c 87 | #include "equeue.h" 88 | 89 | equeue_t queue; 90 | 91 | // arbitrary data can be moved to a different context 92 | int enet_consume(void *buffer, int size) { 93 | if (size > 512) { 94 | size = 512; 95 | } 96 | 97 | void *data = equeue_alloc(&queue, 512); 98 | memcpy(data, buffer, size); 99 | equeue_post(&queue, handle_data_elsewhere, data); 100 | 101 | return size; 102 | } 103 | ``` 104 | 105 | Additionally, in-flight events can be cancelled with `equeue_cancel`. Events 106 | are given unique ids on post, allowing safe cancellation of expired events. 107 | 108 | ``` c 109 | #include "equeue.h" 110 | 111 | equeue_t queue; 112 | int sonar_value; 113 | int sonar_timeout_id; 114 | 115 | void sonar_isr(int value) { 116 | equeue_cancel(&queue, sonar_timeout_id); 117 | sonar_value = value; 118 | } 119 | 120 | void sonar_timeout(void *) { 121 | sonar_value = -1; 122 | } 123 | 124 | void sonar_read(void) { 125 | sonar_timeout_id = equeue_call_in(&queue, 300, sonar_timeout, 0); 126 | sonar_start(); 127 | } 128 | ``` 129 | 130 | From an architectural standpoint, event queues easily align with module 131 | boundaries, where internal state can be implicitly synchronized through 132 | event dispatch. 133 | 134 | On platforms where multiple threads are unavailable, multiple modules 135 | can use independent event queues and still be composed through the 136 | `equeue_chain` function. 137 | 138 | ``` c 139 | #include "equeue.h" 140 | 141 | // run a simultaneous localization and mapping loop in one queue 142 | struct slam { 143 | equeue_t queue; 144 | }; 145 | 146 | void slam_create(struct slam *s, equeue_t *target) { 147 | equeue_create(&s->queue, 4096); 148 | equeue_chain(&s->queue, target); 149 | equeue_call_every(&s->queue, 100, slam_filter); 150 | } 151 | 152 | // run a sonar with it's own queue 153 | struct sonar { 154 | equeue_t equeue; 155 | struct slam *slam; 156 | }; 157 | 158 | void sonar_create(struct sonar *s, equeue_t *target) { 159 | equeue_create(&s->queue, 64); 160 | equeue_chain(&s->queue, target); 161 | equeue_call_in(&s->queue, 5, sonar_update, s); 162 | } 163 | 164 | // all of the above queues can be combined into a single thread of execution 165 | int main() { 166 | equeue_t queue; 167 | equeue_create(&queue, 1024); 168 | 169 | struct sonar s1, s2, s3; 170 | sonar_create(&s1, &queue); 171 | sonar_create(&s2, &queue); 172 | sonar_create(&s3, &queue); 173 | 174 | struct slam slam; 175 | slam_create(&slam, &queue); 176 | 177 | // dispatches events from all of the modules 178 | equeue_dispatch(&queue, -1); 179 | } 180 | ``` 181 | 182 | ## Platform ## 183 | 184 | The equeue library has a minimal porting layer that is flexible depending 185 | on the requirements of the underlying platform. Platform specific declarations 186 | and more information can be found in [equeue_platform.h](equeue_platform.h). 187 | 188 | ## Tests ## 189 | 190 | The equeue library uses a set of local tests based on the posix implementation. 191 | 192 | Runtime tests are located in [tests.c](tests/tests.c): 193 | 194 | ``` bash 195 | make test 196 | ``` 197 | 198 | Profiling tests based on rdtsc are located in [prof.c](tests/prof.c): 199 | 200 | ``` bash 201 | make prof 202 | ``` 203 | 204 | To make profiling results more tangible, the profiler also supports percentage 205 | comparison with previous runs: 206 | ``` bash 207 | make prof | tee results.txt 208 | cat results.txt | make prof 209 | ``` 210 | 211 | -------------------------------------------------------------------------------- /equeue/equeue.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Flexible event queue for dispatching events 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license 6 | */ 7 | #include "equeue.h" 8 | 9 | #include 10 | #include 11 | 12 | 13 | // calculate the relative-difference between absolute times while 14 | // correctly handling overflow conditions 15 | static inline int equeue_tickdiff(unsigned a, unsigned b) { 16 | return (int)(unsigned)(a - b); 17 | } 18 | 19 | // calculate the relative-difference between absolute times, but 20 | // also clamp to zero, resulting in only non-zero values. 21 | static inline int equeue_clampdiff(unsigned a, unsigned b) { 22 | int diff = equeue_tickdiff(a, b); 23 | return ~(diff >> (8*sizeof(int)-1)) & diff; 24 | } 25 | 26 | // Increment the unique id in an event, hiding the event from cancel 27 | static inline void equeue_incid(equeue_t *q, struct equeue_event *e) { 28 | e->id += 1; 29 | if (!(e->id << q->npw2)) { 30 | e->id = 1; 31 | } 32 | } 33 | 34 | 35 | // equeue lifetime management 36 | int equeue_create(equeue_t *q, size_t size) { 37 | // dynamically allocate the specified buffer 38 | void *buffer = malloc(size); 39 | if (!buffer) { 40 | return -1; 41 | } 42 | 43 | int err = equeue_create_inplace(q, size, buffer); 44 | q->allocated = buffer; 45 | return err; 46 | } 47 | 48 | int equeue_create_inplace(equeue_t *q, size_t size, void *buffer) { 49 | // setup queue around provided buffer 50 | q->buffer = buffer; 51 | q->allocated = 0; 52 | 53 | q->npw2 = 0; 54 | for (unsigned s = size; s; s >>= 1) { 55 | q->npw2++; 56 | } 57 | 58 | q->chunks = 0; 59 | q->slab.size = size; 60 | q->slab.data = buffer; 61 | 62 | q->queue = 0; 63 | q->tick = equeue_tick(); 64 | q->generation = 0; 65 | q->breaks = 0; 66 | 67 | q->background.active = false; 68 | q->background.update = 0; 69 | q->background.timer = 0; 70 | 71 | // initialize platform resources 72 | int err; 73 | err = equeue_sema_create(&q->eventsema); 74 | if (err < 0) { 75 | return err; 76 | } 77 | 78 | err = equeue_mutex_create(&q->queuelock); 79 | if (err < 0) { 80 | return err; 81 | } 82 | 83 | err = equeue_mutex_create(&q->memlock); 84 | if (err < 0) { 85 | return err; 86 | } 87 | 88 | return 0; 89 | } 90 | 91 | void equeue_destroy(equeue_t *q) { 92 | // call destructors on pending events 93 | for (struct equeue_event *es = q->queue; es; es = es->next) { 94 | for (struct equeue_event *e = q->queue; e; e = e->sibling) { 95 | if (e->dtor) { 96 | e->dtor(e + 1); 97 | } 98 | } 99 | } 100 | 101 | // notify background timer 102 | if (q->background.update) { 103 | q->background.update(q->background.timer, -1); 104 | } 105 | 106 | // clean up platform resources + memory 107 | equeue_mutex_destroy(&q->memlock); 108 | equeue_mutex_destroy(&q->queuelock); 109 | equeue_sema_destroy(&q->eventsema); 110 | free(q->allocated); 111 | } 112 | 113 | 114 | // equeue chunk allocation functions 115 | static struct equeue_event *equeue_mem_alloc(equeue_t *q, size_t size) { 116 | // add event overhead 117 | size += sizeof(struct equeue_event); 118 | size = (size + sizeof(void*)-1) & ~(sizeof(void*)-1); 119 | 120 | equeue_mutex_lock(&q->memlock); 121 | 122 | // check if a good chunk is available 123 | for (struct equeue_event **p = &q->chunks; *p; p = &(*p)->next) { 124 | if ((*p)->size >= size) { 125 | struct equeue_event *e = *p; 126 | if (e->sibling) { 127 | *p = e->sibling; 128 | (*p)->next = e->next; 129 | } else { 130 | *p = e->next; 131 | } 132 | 133 | equeue_mutex_unlock(&q->memlock); 134 | return e; 135 | } 136 | } 137 | 138 | // otherwise allocate a new chunk out of the slab 139 | if (q->slab.size >= size) { 140 | struct equeue_event *e = (struct equeue_event *)q->slab.data; 141 | q->slab.data += size; 142 | q->slab.size -= size; 143 | e->size = size; 144 | e->id = 1; 145 | 146 | equeue_mutex_unlock(&q->memlock); 147 | return e; 148 | } 149 | 150 | equeue_mutex_unlock(&q->memlock); 151 | return 0; 152 | } 153 | 154 | static void equeue_mem_dealloc(equeue_t *q, struct equeue_event *e) { 155 | equeue_mutex_lock(&q->memlock); 156 | 157 | // stick chunk into list of chunks 158 | struct equeue_event **p = &q->chunks; 159 | while (*p && (*p)->size < e->size) { 160 | p = &(*p)->next; 161 | } 162 | 163 | if (*p && (*p)->size == e->size) { 164 | e->sibling = *p; 165 | e->next = (*p)->next; 166 | } else { 167 | e->sibling = 0; 168 | e->next = *p; 169 | } 170 | *p = e; 171 | 172 | equeue_mutex_unlock(&q->memlock); 173 | } 174 | 175 | void *equeue_alloc(equeue_t *q, size_t size) { 176 | struct equeue_event *e = equeue_mem_alloc(q, size); 177 | if (!e) { 178 | return 0; 179 | } 180 | 181 | e->target = 0; 182 | e->period = -1; 183 | e->dtor = 0; 184 | 185 | return e + 1; 186 | } 187 | 188 | void equeue_dealloc(equeue_t *q, void *p) { 189 | struct equeue_event *e = (struct equeue_event*)p - 1; 190 | 191 | if (e->dtor) { 192 | e->dtor(e+1); 193 | } 194 | 195 | equeue_mem_dealloc(q, e); 196 | } 197 | 198 | 199 | // equeue scheduling functions 200 | static int equeue_enqueue(equeue_t *q, struct equeue_event *e, unsigned tick) { 201 | // setup event and hash local id with buffer offset for unique id 202 | int id = (e->id << q->npw2) | ((unsigned char *)e - q->buffer); 203 | e->target = tick + equeue_clampdiff(e->target, tick); 204 | e->generation = q->generation; 205 | 206 | equeue_mutex_lock(&q->queuelock); 207 | 208 | // find the event slot 209 | struct equeue_event **p = &q->queue; 210 | while (*p && equeue_tickdiff((*p)->target, e->target) < 0) { 211 | p = &(*p)->next; 212 | } 213 | 214 | // insert at head in slot 215 | if (*p && (*p)->target == e->target) { 216 | e->next = (*p)->next; 217 | if (e->next) { 218 | e->next->ref = &e->next; 219 | } 220 | 221 | e->sibling = *p; 222 | e->sibling->ref = &e->sibling; 223 | } else { 224 | e->next = *p; 225 | if (e->next) { 226 | e->next->ref = &e->next; 227 | } 228 | 229 | e->sibling = 0; 230 | } 231 | 232 | *p = e; 233 | e->ref = p; 234 | 235 | // notify background timer 236 | if ((q->background.update && q->background.active) && 237 | (q->queue == e && !e->sibling)) { 238 | q->background.update(q->background.timer, 239 | equeue_clampdiff(e->target, tick)); 240 | } 241 | 242 | equeue_mutex_unlock(&q->queuelock); 243 | 244 | return id; 245 | } 246 | 247 | static struct equeue_event *equeue_unqueue(equeue_t *q, int id) { 248 | // decode event from unique id and check that the local id matches 249 | struct equeue_event *e = (struct equeue_event *) 250 | &q->buffer[id & ((1 << q->npw2)-1)]; 251 | 252 | equeue_mutex_lock(&q->queuelock); 253 | if (e->id != id >> q->npw2) { 254 | equeue_mutex_unlock(&q->queuelock); 255 | return 0; 256 | } 257 | 258 | // clear the event and check if already in-flight 259 | e->cb = 0; 260 | e->period = -1; 261 | 262 | int diff = equeue_tickdiff(e->target, q->tick); 263 | if (diff < 0 || (diff == 0 && e->generation != q->generation)) { 264 | equeue_mutex_unlock(&q->queuelock); 265 | return 0; 266 | } 267 | 268 | // disentangle from queue 269 | if (e->sibling) { 270 | e->sibling->next = e->next; 271 | if (e->sibling->next) { 272 | e->sibling->next->ref = &e->sibling->next; 273 | } 274 | 275 | *e->ref = e->sibling; 276 | e->sibling->ref = e->ref; 277 | } else { 278 | *e->ref = e->next; 279 | if (e->next) { 280 | e->next->ref = e->ref; 281 | } 282 | } 283 | 284 | equeue_incid(q, e); 285 | equeue_mutex_unlock(&q->queuelock); 286 | 287 | return e; 288 | } 289 | 290 | static struct equeue_event *equeue_dequeue(equeue_t *q, unsigned target) { 291 | equeue_mutex_lock(&q->queuelock); 292 | 293 | // find all expired events and mark a new generation 294 | q->generation += 1; 295 | if (equeue_tickdiff(q->tick, target) <= 0) { 296 | q->tick = target; 297 | } 298 | 299 | struct equeue_event *head = q->queue; 300 | struct equeue_event **p = &head; 301 | while (*p && equeue_tickdiff((*p)->target, target) <= 0) { 302 | p = &(*p)->next; 303 | } 304 | 305 | q->queue = *p; 306 | if (q->queue) { 307 | q->queue->ref = &q->queue; 308 | } 309 | 310 | *p = 0; 311 | 312 | equeue_mutex_unlock(&q->queuelock); 313 | 314 | // reverse and flatten each slot to match insertion order 315 | struct equeue_event **tail = &head; 316 | struct equeue_event *ess = head; 317 | while (ess) { 318 | struct equeue_event *es = ess; 319 | ess = es->next; 320 | 321 | struct equeue_event *prev = 0; 322 | for (struct equeue_event *e = es; e; e = e->sibling) { 323 | e->next = prev; 324 | prev = e; 325 | } 326 | 327 | *tail = prev; 328 | tail = &es->next; 329 | } 330 | 331 | return head; 332 | } 333 | 334 | int equeue_post(equeue_t *q, void (*cb)(void*), void *p) { 335 | struct equeue_event *e = (struct equeue_event*)p - 1; 336 | unsigned tick = equeue_tick(); 337 | e->cb = cb; 338 | e->target = tick + e->target; 339 | 340 | int id = equeue_enqueue(q, e, tick); 341 | equeue_sema_signal(&q->eventsema); 342 | return id; 343 | } 344 | 345 | void equeue_cancel(equeue_t *q, int id) { 346 | if (!id) { 347 | return; 348 | } 349 | 350 | struct equeue_event *e = equeue_unqueue(q, id); 351 | if (e) { 352 | equeue_dealloc(q, e + 1); 353 | } 354 | } 355 | 356 | void equeue_break(equeue_t *q) { 357 | equeue_mutex_lock(&q->queuelock); 358 | q->breaks++; 359 | equeue_mutex_unlock(&q->queuelock); 360 | equeue_sema_signal(&q->eventsema); 361 | } 362 | 363 | void equeue_dispatch(equeue_t *q, int ms) { 364 | unsigned tick = equeue_tick(); 365 | unsigned timeout = tick + ms; 366 | q->background.active = false; 367 | 368 | while (1) { 369 | // collect all the available events and next deadline 370 | struct equeue_event *es = equeue_dequeue(q, tick); 371 | 372 | // dispatch events 373 | while (es) { 374 | struct equeue_event *e = es; 375 | es = e->next; 376 | 377 | // actually dispatch the callbacks 378 | void (*cb)(void *) = e->cb; 379 | if (cb) { 380 | cb(e + 1); 381 | } 382 | 383 | // reenqueue periodic events or deallocate 384 | if (e->period >= 0) { 385 | e->target += e->period; 386 | equeue_enqueue(q, e, equeue_tick()); 387 | } else { 388 | equeue_incid(q, e); 389 | equeue_dealloc(q, e+1); 390 | } 391 | } 392 | 393 | int deadline = -1; 394 | tick = equeue_tick(); 395 | 396 | // check if we should stop dispatching soon 397 | if (ms >= 0) { 398 | deadline = equeue_tickdiff(timeout, tick); 399 | if (deadline <= 0) { 400 | // update background timer if necessary 401 | if (q->background.update) { 402 | equeue_mutex_lock(&q->queuelock); 403 | if (q->background.update && q->queue) { 404 | q->background.update(q->background.timer, 405 | equeue_clampdiff(q->queue->target, tick)); 406 | } 407 | q->background.active = true; 408 | equeue_mutex_unlock(&q->queuelock); 409 | } 410 | return; 411 | } 412 | } 413 | 414 | // find closest deadline 415 | equeue_mutex_lock(&q->queuelock); 416 | if (q->queue) { 417 | int diff = equeue_clampdiff(q->queue->target, tick); 418 | if ((unsigned)diff < (unsigned)deadline) { 419 | deadline = diff; 420 | } 421 | } 422 | equeue_mutex_unlock(&q->queuelock); 423 | 424 | // wait for events 425 | equeue_sema_wait(&q->eventsema, deadline); 426 | 427 | // check if we were notified to break out of dispatch 428 | if (q->breaks) { 429 | equeue_mutex_lock(&q->queuelock); 430 | if (q->breaks > 0) { 431 | q->breaks--; 432 | equeue_mutex_unlock(&q->queuelock); 433 | return; 434 | } 435 | equeue_mutex_unlock(&q->queuelock); 436 | } 437 | 438 | // update tick for next iteration 439 | tick = equeue_tick(); 440 | } 441 | } 442 | 443 | 444 | // event functions 445 | void equeue_event_delay(void *p, int ms) { 446 | struct equeue_event *e = (struct equeue_event*)p - 1; 447 | e->target = ms; 448 | } 449 | 450 | void equeue_event_period(void *p, int ms) { 451 | struct equeue_event *e = (struct equeue_event*)p - 1; 452 | e->period = ms; 453 | } 454 | 455 | void equeue_event_dtor(void *p, void (*dtor)(void *)) { 456 | struct equeue_event *e = (struct equeue_event*)p - 1; 457 | e->dtor = dtor; 458 | } 459 | 460 | 461 | // simple callbacks 462 | struct ecallback { 463 | void (*cb)(void*); 464 | void *data; 465 | }; 466 | 467 | static void ecallback_dispatch(void *p) { 468 | struct ecallback *e = (struct ecallback*)p; 469 | e->cb(e->data); 470 | } 471 | 472 | int equeue_call(equeue_t *q, void (*cb)(void*), void *data) { 473 | struct ecallback *e = equeue_alloc(q, sizeof(struct ecallback)); 474 | if (!e) { 475 | return 0; 476 | } 477 | 478 | e->cb = cb; 479 | e->data = data; 480 | return equeue_post(q, ecallback_dispatch, e); 481 | } 482 | 483 | int equeue_call_in(equeue_t *q, int ms, void (*cb)(void*), void *data) { 484 | struct ecallback *e = equeue_alloc(q, sizeof(struct ecallback)); 485 | if (!e) { 486 | return 0; 487 | } 488 | 489 | equeue_event_delay(e, ms); 490 | e->cb = cb; 491 | e->data = data; 492 | return equeue_post(q, ecallback_dispatch, e); 493 | } 494 | 495 | int equeue_call_every(equeue_t *q, int ms, void (*cb)(void*), void *data) { 496 | struct ecallback *e = equeue_alloc(q, sizeof(struct ecallback)); 497 | if (!e) { 498 | return 0; 499 | } 500 | 501 | equeue_event_delay(e, ms); 502 | equeue_event_period(e, ms); 503 | e->cb = cb; 504 | e->data = data; 505 | return equeue_post(q, ecallback_dispatch, e); 506 | } 507 | 508 | 509 | // backgrounding 510 | void equeue_background(equeue_t *q, 511 | void (*update)(void *timer, int ms), void *timer) { 512 | equeue_mutex_lock(&q->queuelock); 513 | if (q->background.update) { 514 | q->background.update(q->background.timer, -1); 515 | } 516 | 517 | q->background.update = update; 518 | q->background.timer = timer; 519 | 520 | if (q->background.update && q->queue) { 521 | q->background.update(q->background.timer, 522 | equeue_clampdiff(q->queue->target, equeue_tick())); 523 | } 524 | q->background.active = true; 525 | equeue_mutex_unlock(&q->queuelock); 526 | } 527 | 528 | struct equeue_chain_context { 529 | equeue_t *q; 530 | equeue_t *target; 531 | int id; 532 | }; 533 | 534 | static void equeue_chain_dispatch(void *p) { 535 | equeue_dispatch((equeue_t *)p, 0); 536 | } 537 | 538 | static void equeue_chain_update(void *p, int ms) { 539 | struct equeue_chain_context *c = (struct equeue_chain_context *)p; 540 | equeue_cancel(c->target, c->id); 541 | 542 | if (ms >= 0) { 543 | c->id = equeue_call_in(c->target, ms, equeue_chain_dispatch, c->q); 544 | } else { 545 | equeue_dealloc(c->target, c); 546 | } 547 | } 548 | 549 | void equeue_chain(equeue_t *q, equeue_t *target) { 550 | if (!target) { 551 | equeue_background(q, 0, 0); 552 | return; 553 | } 554 | 555 | struct equeue_chain_context *c = equeue_alloc(q, 556 | sizeof(struct equeue_chain_context)); 557 | 558 | c->q = q; 559 | c->target = target; 560 | c->id = 0; 561 | 562 | equeue_background(q, equeue_chain_update, c); 563 | } 564 | -------------------------------------------------------------------------------- /equeue/equeue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Flexible event queue for dispatching events 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license 6 | */ 7 | #ifndef EQUEUE_H 8 | #define EQUEUE_H 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | // Platform specific files 15 | #include "equeue_platform.h" 16 | 17 | #include 18 | #include 19 | 20 | 21 | // The minimum size of an event 22 | // This size is guaranteed to fit events created by event_call 23 | #define EQUEUE_EVENT_SIZE (sizeof(struct equeue_event) + 2*sizeof(void*)) 24 | 25 | // Internal event structure 26 | struct equeue_event { 27 | unsigned size; 28 | uint8_t id; 29 | uint8_t generation; 30 | 31 | struct equeue_event *next; 32 | struct equeue_event *sibling; 33 | struct equeue_event **ref; 34 | 35 | unsigned target; 36 | int period; 37 | void (*dtor)(void *); 38 | 39 | void (*cb)(void *); 40 | // data follows 41 | }; 42 | 43 | // Event queue structure 44 | typedef struct equeue { 45 | struct equeue_event *queue; 46 | unsigned tick; 47 | unsigned breaks; 48 | uint8_t generation; 49 | 50 | unsigned char *buffer; 51 | unsigned npw2; 52 | void *allocated; 53 | 54 | struct equeue_event *chunks; 55 | struct equeue_slab { 56 | size_t size; 57 | unsigned char *data; 58 | } slab; 59 | 60 | struct equeue_background { 61 | bool active; 62 | void (*update)(void *timer, int ms); 63 | void *timer; 64 | } background; 65 | 66 | equeue_sema_t eventsema; 67 | equeue_mutex_t queuelock; 68 | equeue_mutex_t memlock; 69 | } equeue_t; 70 | 71 | 72 | // Queue lifetime operations 73 | // 74 | // Creates and destroys an event queue. The event queue either allocates a 75 | // buffer of the specified size with malloc or uses a user provided buffer 76 | // if constructed with equeue_create_inplace. 77 | // 78 | // If the event queue creation fails, equeue_create returns a negative, 79 | // platform-specific error code. 80 | int equeue_create(equeue_t *queue, size_t size); 81 | int equeue_create_inplace(equeue_t *queue, size_t size, void *buffer); 82 | void equeue_destroy(equeue_t *queue); 83 | 84 | // Dispatch events 85 | // 86 | // Executes events until the specified milliseconds have passed. If ms is 87 | // negative, equeue_dispatch will dispatch events indefinitely or until 88 | // equeue_break is called on this queue. 89 | // 90 | // When called with a finite timeout, the equeue_dispatch function is 91 | // guaranteed to terminate. When called with a timeout of 0, the 92 | // equeue_dispatch does not wait and is irq safe. 93 | void equeue_dispatch(equeue_t *queue, int ms); 94 | 95 | // Break out of a running event loop 96 | // 97 | // Forces the specified event queue's dispatch loop to terminate. Pending 98 | // events may finish executing, but no new events will be executed. 99 | void equeue_break(equeue_t *queue); 100 | 101 | // Simple event calls 102 | // 103 | // The specified callback will be executed in the context of the event queue's 104 | // dispatch loop. When the callback is executed depends on the call function. 105 | // 106 | // equeue_call - Immediately post an event to the queue 107 | // equeue_call_in - Post an event after a specified time in milliseconds 108 | // equeue_call_every - Post an event periodically every milliseconds 109 | // 110 | // All equeue_call functions are irq safe and can act as a mechanism for 111 | // moving events out of irq contexts. 112 | // 113 | // The return value is a unique id that represents the posted event and can 114 | // be passed to equeue_cancel. If there is not enough memory to allocate the 115 | // event, equeue_call returns an id of 0. 116 | int equeue_call(equeue_t *queue, void (*cb)(void *), void *data); 117 | int equeue_call_in(equeue_t *queue, int ms, void (*cb)(void *), void *data); 118 | int equeue_call_every(equeue_t *queue, int ms, void (*cb)(void *), void *data); 119 | 120 | // Allocate memory for events 121 | // 122 | // The equeue_alloc function allocates an event that can be manually dispatched 123 | // with equeue_post. The equeue_dealloc function may be used to free an event 124 | // that has not been posted. Once posted, an event's memory is managed by the 125 | // event queue and should not be deallocated. 126 | // 127 | // Both equeue_alloc and equeue_dealloc are irq safe. 128 | // 129 | // The equeue allocator is designed to minimize jitter in interrupt contexts as 130 | // well as avoid memory fragmentation on small devices. The allocator achieves 131 | // both constant-runtime and zero-fragmentation for fixed-size events, however 132 | // grows linearly as the quantity of different sized allocations increases. 133 | // 134 | // The equeue_alloc function returns a pointer to the event's allocated memory 135 | // and acts as a handle to the underlying event. If there is not enough memory 136 | // to allocate the event, equeue_alloc returns null. 137 | void *equeue_alloc(equeue_t *queue, size_t size); 138 | void equeue_dealloc(equeue_t *queue, void *event); 139 | 140 | // Configure an allocated event 141 | // 142 | // equeue_event_delay - Millisecond delay before dispatching an event 143 | // equeue_event_period - Millisecond period for repeating dispatching an event 144 | // equeue_event_dtor - Destructor to run when the event is deallocated 145 | void equeue_event_delay(void *event, int ms); 146 | void equeue_event_period(void *event, int ms); 147 | void equeue_event_dtor(void *event, void (*dtor)(void *)); 148 | 149 | // Post an event onto the event queue 150 | // 151 | // The equeue_post function takes a callback and a pointer to an event 152 | // allocated by equeue_alloc. The specified callback will be executed in the 153 | // context of the event queue's dispatch loop with the allocated event 154 | // as its argument. 155 | // 156 | // The equeue_post function is irq safe and can act as a mechanism for 157 | // moving events out of irq contexts. 158 | // 159 | // The return value is a unique id that represents the posted event and can 160 | // be passed to equeue_cancel. 161 | int equeue_post(equeue_t *queue, void (*cb)(void *), void *event); 162 | 163 | // Cancel an in-flight event 164 | // 165 | // Attempts to cancel an event referenced by the unique id returned from 166 | // equeue_call or equeue_post. It is safe to call equeue_cancel after an event 167 | // has already been dispatched. 168 | // 169 | // The equeue_cancel function is irq safe. 170 | // 171 | // If called while the event queue's dispatch loop is active, equeue_cancel 172 | // does not guarantee that the event will not not execute after it returns as 173 | // the event may have already begun executing. 174 | void equeue_cancel(equeue_t *queue, int id); 175 | 176 | // Background an event queue onto a single-shot timer 177 | // 178 | // The provided update function will be called to indicate when the queue 179 | // should be dispatched. A negative timeout will be passed to the update 180 | // function when the timer is no longer needed. 181 | // 182 | // Passing a null update function disables the existing timer. 183 | // 184 | // The equeue_background function allows an event queue to take advantage 185 | // of hardware timers or even other event loops, allowing an event queue to 186 | // be effectively backgrounded. 187 | void equeue_background(equeue_t *queue, 188 | void (*update)(void *timer, int ms), void *timer); 189 | 190 | // Chain an event queue onto another event queue 191 | // 192 | // After chaining a queue to a target, calling equeue_dispatch on the 193 | // target queue will also dispatch events from this queue. The queues 194 | // use their own buffers and events must be managed independently. 195 | // 196 | // Passing a null queue as the target will unchain the existing queue. 197 | // 198 | // The equeue_chain function allows multiple equeues to be composed, sharing 199 | // the context of a dispatch loop while still being managed independently. 200 | void equeue_chain(equeue_t *queue, equeue_t *target); 201 | 202 | 203 | #ifdef __cplusplus 204 | } 205 | #endif 206 | 207 | #endif 208 | -------------------------------------------------------------------------------- /equeue/equeue_freertos.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation for the mbed library 3 | * https://github.com/mbedmicro/mbed 4 | * 5 | * Copyright (c) 2016 Christopher Haster 6 | * Distributed under the MIT license 7 | */ 8 | #include "equeue_platform.h" 9 | 10 | #if defined(EQUEUE_PLATFORM_FREERTOS) 11 | 12 | #include "task.h" 13 | 14 | 15 | // Ticker operations 16 | unsigned equeue_tick(void) { 17 | return xTaskGetTickCountFromISR() * portTICK_PERIOD_MS; 18 | } 19 | 20 | 21 | // Mutex operations 22 | int equeue_mutex_create(equeue_mutex_t *m) { return 0; } 23 | void equeue_mutex_destroy(equeue_mutex_t *m) { } 24 | 25 | void equeue_mutex_lock(equeue_mutex_t *m) { 26 | *m = taskENTER_CRITICAL_FROM_ISR(); 27 | } 28 | 29 | void equeue_mutex_unlock(equeue_mutex_t *m) { 30 | taskEXIT_CRITICAL_FROM_ISR(*m); 31 | } 32 | 33 | 34 | // Semaphore operations 35 | int equeue_sema_create(equeue_sema_t *s) { 36 | s->handle = xSemaphoreCreateBinaryStatic(&s->buffer); 37 | return s->handle ? 0 : -1; 38 | } 39 | 40 | void equeue_sema_destroy(equeue_sema_t *s) { 41 | vSemaphoreDelete(s->handle); 42 | } 43 | 44 | void equeue_sema_signal(equeue_sema_t *s) { 45 | xSemaphoreGiveFromISR(s->handle, NULL); 46 | } 47 | 48 | bool equeue_sema_wait(equeue_sema_t *s, int ms) { 49 | if (ms < 0) { 50 | ms = portMAX_DELAY; 51 | } else { 52 | ms = ms / portTICK_PERIOD_MS; 53 | } 54 | 55 | return xSemaphoreTake(s->handle, ms); 56 | } 57 | 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /equeue/equeue_mbed.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation for the mbed library 3 | * https://github.com/mbedmicro/mbed 4 | * 5 | * Copyright (c) 2016 Christopher Haster 6 | * Distributed under the MIT license 7 | */ 8 | #include "equeue_platform.h" 9 | 10 | #if defined(EQUEUE_PLATFORM_MBED) 11 | 12 | #include 13 | #include "mbed.h" 14 | 15 | 16 | // Ticker operations 17 | static bool equeue_tick_inited = false; 18 | static unsigned equeue_minutes = 0; 19 | static unsigned equeue_timer[ 20 | (sizeof(Timer)+sizeof(unsigned)-1)/sizeof(unsigned)]; 21 | static unsigned equeue_ticker[ 22 | (sizeof(Ticker)+sizeof(unsigned)-1)/sizeof(unsigned)]; 23 | 24 | static void equeue_tick_update() { 25 | reinterpret_cast(equeue_timer)->reset(); 26 | equeue_minutes += 1; 27 | } 28 | 29 | static void equeue_tick_init() { 30 | MBED_ASSERT(sizeof(equeue_timer) >= sizeof(Timer)); 31 | MBED_ASSERT(sizeof(equeue_ticker) >= sizeof(Ticker)); 32 | new (equeue_timer) Timer; 33 | new (equeue_ticker) Ticker; 34 | 35 | equeue_minutes = 0; 36 | reinterpret_cast(equeue_timer)->start(); 37 | reinterpret_cast(equeue_ticker) 38 | ->attach_us(equeue_tick_update, (1 << 16)*1000); 39 | 40 | equeue_tick_inited = true; 41 | } 42 | 43 | unsigned equeue_tick() { 44 | if (!equeue_tick_inited) { 45 | equeue_tick_init(); 46 | } 47 | 48 | unsigned equeue_ms = reinterpret_cast(equeue_timer)->read_ms(); 49 | return (equeue_minutes << 16) + equeue_ms; 50 | } 51 | 52 | 53 | // Mutex operations 54 | int equeue_mutex_create(equeue_mutex_t *m) { return 0; } 55 | void equeue_mutex_destroy(equeue_mutex_t *m) { } 56 | 57 | void equeue_mutex_lock(equeue_mutex_t *m) { 58 | core_util_critical_section_enter(); 59 | } 60 | 61 | void equeue_mutex_unlock(equeue_mutex_t *m) { 62 | core_util_critical_section_exit(); 63 | } 64 | 65 | 66 | // Semaphore operations 67 | #ifdef MBED_CONF_RTOS_PRESENT 68 | 69 | int equeue_sema_create(equeue_sema_t *s) { 70 | MBED_ASSERT(sizeof(equeue_sema_t) >= sizeof(Semaphore)); 71 | new (s) Semaphore(0); 72 | return 0; 73 | } 74 | 75 | void equeue_sema_destroy(equeue_sema_t *s) { 76 | reinterpret_cast(s)->~Semaphore(); 77 | } 78 | 79 | void equeue_sema_signal(equeue_sema_t *s) { 80 | reinterpret_cast(s)->release(); 81 | } 82 | 83 | bool equeue_sema_wait(equeue_sema_t *s, int ms) { 84 | if (ms < 0) { 85 | ms = osWaitForever; 86 | } 87 | 88 | return (reinterpret_cast(s)->wait(ms) > 0); 89 | } 90 | 91 | #else 92 | 93 | // Semaphore operations 94 | int equeue_sema_create(equeue_sema_t *s) { 95 | *s = false; 96 | return 0; 97 | } 98 | 99 | void equeue_sema_destroy(equeue_sema_t *s) { 100 | } 101 | 102 | void equeue_sema_signal(equeue_sema_t *s) { 103 | *s = 1; 104 | } 105 | 106 | static void equeue_sema_timeout(equeue_sema_t *s) { 107 | *s = -1; 108 | } 109 | 110 | bool equeue_sema_wait(equeue_sema_t *s, int ms) { 111 | int signal = 0; 112 | Timeout timeout; 113 | timeout.attach_us(s, equeue_sema_timeout, ms*1000); 114 | 115 | core_util_critical_section_enter(); 116 | while (!*s) { 117 | sleep(); 118 | core_util_critical_section_exit(); 119 | core_util_critical_section_enter(); 120 | } 121 | 122 | signal = *s; 123 | *s = false; 124 | core_util_critical_section_exit(); 125 | 126 | return (signal > 0); 127 | } 128 | 129 | #endif 130 | 131 | #endif 132 | -------------------------------------------------------------------------------- /equeue/equeue_platform.h: -------------------------------------------------------------------------------- 1 | /* 2 | * System specific implementation 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license 6 | */ 7 | #ifndef EQUEUE_PLATFORM_H 8 | #define EQUEUE_PLATFORM_H 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | #include 15 | 16 | // Currently supported platforms 17 | // 18 | // Uncomment to select a supported platform or reimplement this file 19 | // for a specific target. 20 | //#define EQUEUE_PLATFORM_POSIX 21 | //#define EQUEUE_PLATFORM_WINDOWS 22 | //#define EQUEUE_PLATFORM_MBED 23 | //#define EQUEUE_PLATFORM_FREERTOS 24 | 25 | // Try to infer a platform if none was manually selected 26 | #if !defined(EQUEUE_PLATFORM_POSIX) \ 27 | && !defined(EQUEUE_PLATFORM_WINDOWS) \ 28 | && !defined(EQUEUE_PLATFORM_MBED) \ 29 | && !defined(EQUEUE_PLATFORM_FREERTOS) 30 | #if defined(__unix__) 31 | #define EQUEUE_PLATFORM_POSIX 32 | #elif defined(_WIN32) 33 | #define EQUEUE_PLATFORM_WINDOWS 34 | #elif defined(__MBED__) 35 | #define EQUEUE_PLATFORM_MBED 36 | #else 37 | #warning "Unknown platform! Please update equeue_platform.h" 38 | #endif 39 | #endif 40 | 41 | // Platform includes 42 | #if defined(EQUEUE_PLATFORM_POSIX) 43 | #include 44 | #elif defined(EQUEUE_PLATFORM_WINDOWS) 45 | #include 46 | #elif defined(EQUEUE_PLATFORM_FREERTOS) 47 | #include "FreeRTOS.h" 48 | #include "semphr.h" 49 | #endif 50 | 51 | 52 | // Platform millisecond counter 53 | // 54 | // Return a tick that represents the number of milliseconds that have passed 55 | // since an arbitrary point in time. The granularity does not need to be at 56 | // the millisecond level, however the accuracy of the equeue library is 57 | // limited by the accuracy of this tick. 58 | // 59 | // Must intentionally overflow to 0 after 2^32-1 60 | unsigned equeue_tick(void); 61 | 62 | 63 | // Platform mutex type 64 | // 65 | // The equeue library requires at minimum a non-recursive mutex that is 66 | // safe in interrupt contexts. The mutex section is help for a bounded 67 | // amount of time, so simply disabling interrupts is acceptable 68 | // 69 | // If irq safety is not required, a regular blocking mutex can be used. 70 | #if defined(EQUEUE_PLATFORM_POSIX) 71 | typedef pthread_mutex_t equeue_mutex_t; 72 | #elif defined(EQUEUE_PLATFORM_WINDOWS) 73 | typedef CRITICAL_SECTION equeue_mutex_t; 74 | #elif defined(EQUEUE_PLATFORM_MBED) 75 | typedef unsigned equeue_mutex_t; 76 | #elif defined(EQUEUE_PLATFORM_FREERTOS) 77 | typedef UBaseType_t equeue_mutex_t; 78 | #endif 79 | 80 | // Platform mutex operations 81 | // 82 | // The equeue_mutex_create and equeue_mutex_destroy manage the lifetime 83 | // of the mutex. On error, equeue_mutex_create should return a negative 84 | // error code. 85 | // 86 | // The equeue_mutex_lock and equeue_mutex_unlock lock and unlock the 87 | // underlying mutex. 88 | int equeue_mutex_create(equeue_mutex_t *mutex); 89 | void equeue_mutex_destroy(equeue_mutex_t *mutex); 90 | void equeue_mutex_lock(equeue_mutex_t *mutex); 91 | void equeue_mutex_unlock(equeue_mutex_t *mutex); 92 | 93 | 94 | // Platform semaphore type 95 | // 96 | // The equeue library requires a binary semaphore type that can be safely 97 | // signaled from interrupt contexts and from inside a equeue_mutex section. 98 | // 99 | // The equeue_signal_wait is relied upon by the equeue library to sleep the 100 | // processor between events. Spurious wakeups have no negative-effects. 101 | // 102 | // A counting semaphore will also work, however may cause the event queue 103 | // dispatch loop to run unnecessarily. For that matter, equeue_signal_wait 104 | // may even be implemented as a single return statement. 105 | #if defined(EQUEUE_PLATFORM_POSIX) 106 | typedef struct equeue_sema { 107 | pthread_mutex_t mutex; 108 | pthread_cond_t cond; 109 | bool signal; 110 | } equeue_sema_t; 111 | #elif defined(EQUEUE_PLATFORM_WINDOWS) 112 | typedef HANDLE equeue_sema_t; 113 | #elif defined(EQUEUE_PLATFORM_MBED) && defined(MBED_CONF_RTOS_PRESENT) 114 | typedef unsigned equeue_sema_t[8]; 115 | #elif defined(EQUEUE_PLATFORM_MBED) 116 | typedef volatile int equeue_sema_t; 117 | #elif defined(EQUEUE_PLATFORM_FREERTOS) 118 | typedef struct equeue_sema { 119 | SemaphoreHandle_t handle; 120 | StaticSemaphore_t buffer; 121 | } equeue_sema_t; 122 | #endif 123 | 124 | // Platform semaphore operations 125 | // 126 | // The equeue_sema_create and equeue_sema_destroy manage the lifetime 127 | // of the semaphore. On error, equeue_sema_create should return a negative 128 | // error code. 129 | // 130 | // The equeue_sema_signal marks a semaphore as signalled such that the next 131 | // equeue_sema_wait will return true. 132 | // 133 | // The equeue_sema_wait waits for a semaphore to be signalled or returns 134 | // immediately if equeue_sema_signal had been called since the last 135 | // equeue_sema_wait. The equeue_sema_wait returns true if it detected that 136 | // equeue_sema_signal had been called. 137 | int equeue_sema_create(equeue_sema_t *sema); 138 | void equeue_sema_destroy(equeue_sema_t *sema); 139 | void equeue_sema_signal(equeue_sema_t *sema); 140 | bool equeue_sema_wait(equeue_sema_t *sema, int ms); 141 | 142 | 143 | #ifdef __cplusplus 144 | } 145 | #endif 146 | 147 | #endif 148 | -------------------------------------------------------------------------------- /equeue/equeue_posix.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation for Posix compliant platforms 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license 6 | */ 7 | #include "equeue_platform.h" 8 | 9 | #if defined(EQUEUE_PLATFORM_POSIX) 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | // Tick operations 17 | unsigned equeue_tick(void) { 18 | struct timeval tv; 19 | gettimeofday(&tv, 0); 20 | return (unsigned)(tv.tv_sec*1000 + tv.tv_usec/1000); 21 | } 22 | 23 | 24 | // Mutex operations 25 | int equeue_mutex_create(equeue_mutex_t *m) { 26 | return pthread_mutex_init(m, 0); 27 | } 28 | 29 | void equeue_mutex_destroy(equeue_mutex_t *m) { 30 | pthread_mutex_destroy(m); 31 | } 32 | 33 | void equeue_mutex_lock(equeue_mutex_t *m) { 34 | pthread_mutex_lock(m); 35 | } 36 | 37 | void equeue_mutex_unlock(equeue_mutex_t *m) { 38 | pthread_mutex_unlock(m); 39 | } 40 | 41 | 42 | // Semaphore operations 43 | int equeue_sema_create(equeue_sema_t *s) { 44 | int err = pthread_mutex_init(&s->mutex, 0); 45 | if (err) { 46 | return err; 47 | } 48 | 49 | err = pthread_cond_init(&s->cond, 0); 50 | if (err) { 51 | return err; 52 | } 53 | 54 | s->signal = false; 55 | return 0; 56 | } 57 | 58 | void equeue_sema_destroy(equeue_sema_t *s) { 59 | pthread_cond_destroy(&s->cond); 60 | pthread_mutex_destroy(&s->mutex); 61 | } 62 | 63 | void equeue_sema_signal(equeue_sema_t *s) { 64 | pthread_mutex_lock(&s->mutex); 65 | s->signal = true; 66 | pthread_cond_signal(&s->cond); 67 | pthread_mutex_unlock(&s->mutex); 68 | } 69 | 70 | bool equeue_sema_wait(equeue_sema_t *s, int ms) { 71 | pthread_mutex_lock(&s->mutex); 72 | if (!s->signal) { 73 | if (ms < 0) { 74 | pthread_cond_wait(&s->cond, &s->mutex); 75 | } else { 76 | struct timeval tv; 77 | gettimeofday(&tv, 0); 78 | 79 | struct timespec ts = { 80 | .tv_sec = ms/1000 + tv.tv_sec, 81 | .tv_nsec = ms*1000000 + tv.tv_usec*1000, 82 | }; 83 | 84 | pthread_cond_timedwait(&s->cond, &s->mutex, &ts); 85 | } 86 | } 87 | 88 | bool signal = s->signal; 89 | s->signal = false; 90 | pthread_mutex_unlock(&s->mutex); 91 | 92 | return signal; 93 | } 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /equeue/equeue_windows.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation for Windows 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license 6 | */ 7 | #include "equeue_platform.h" 8 | 9 | #if defined(EQUEUE_PLATFORM_WINDOWS) 10 | 11 | #include 12 | 13 | 14 | // Tick operations 15 | unsigned equeue_tick(void) { 16 | return GetTickCount(); 17 | } 18 | 19 | 20 | // Mutex operations 21 | int equeue_mutex_create(equeue_mutex_t *m) { 22 | InitializeCriticalSection(m); 23 | return 0; 24 | } 25 | 26 | void equeue_mutex_destroy(equeue_mutex_t *m) { 27 | DeleteCriticalSection(m); 28 | } 29 | 30 | void equeue_mutex_lock(equeue_mutex_t *m) { 31 | EnterCriticalSection(m); 32 | } 33 | 34 | void equeue_mutex_unlock(equeue_mutex_t *m) { 35 | LeaveCriticalSection(m); 36 | } 37 | 38 | 39 | // Semaphore operations 40 | int equeue_sema_create(equeue_sema_t *s) { 41 | *s = CreateSemaphore(NULL, 0, 1, NULL); 42 | return *s ? 0 : -1; 43 | } 44 | 45 | void equeue_sema_destroy(equeue_sema_t *s) { 46 | CloseHandle(*s); 47 | } 48 | 49 | void equeue_sema_signal(equeue_sema_t *s) { 50 | ReleaseSemaphore(*s, 1, NULL); 51 | } 52 | 53 | bool equeue_sema_wait(equeue_sema_t *s, int ms) { 54 | if (ms < 0) { 55 | ms = INFINITE; 56 | } 57 | 58 | return WaitForSingleObject(*s, ms) == WAIT_OBJECT_0; 59 | } 60 | 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /equeue/tests/prof.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Profiling framework for the events library 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license 6 | */ 7 | #include "equeue.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | // Performance measurement utils 18 | #define PROF_RUNS 5 19 | #define PROF_INTERVAL 100000000 20 | 21 | #define prof_volatile(t) __attribute__((unused)) volatile t 22 | 23 | typedef uint64_t prof_cycle_t; 24 | 25 | static volatile prof_cycle_t prof_start_cycle; 26 | static volatile prof_cycle_t prof_stop_cycle; 27 | static prof_cycle_t prof_accum_cycle; 28 | static prof_cycle_t prof_baseline_cycle; 29 | static prof_cycle_t prof_iterations; 30 | static const char *prof_units; 31 | 32 | #define prof_cycle() ({ \ 33 | uint32_t a, b; \ 34 | __asm__ volatile ("rdtsc" : "=a" (a), "=d" (b)); \ 35 | ((uint64_t)b << 32) | (uint64_t)a; \ 36 | }) 37 | 38 | #define prof_loop() \ 39 | for (prof_iterations = 0; \ 40 | prof_accum_cycle < PROF_INTERVAL; \ 41 | prof_iterations++) 42 | 43 | #define prof_start() ({ \ 44 | prof_start_cycle = prof_cycle(); \ 45 | }) 46 | 47 | #define prof_stop() ({ \ 48 | prof_stop_cycle = prof_cycle(); \ 49 | prof_accum_cycle += prof_stop_cycle - prof_start_cycle; \ 50 | }) 51 | 52 | #define prof_result(value, units) ({ \ 53 | prof_accum_cycle = value+prof_baseline_cycle; \ 54 | prof_iterations = 1; \ 55 | prof_units = units; \ 56 | }) 57 | 58 | #define prof_measure(func, ...) ({ \ 59 | printf("%s: ...", #func); \ 60 | fflush(stdout); \ 61 | \ 62 | prof_units = "cycles"; \ 63 | prof_cycle_t runs[PROF_RUNS]; \ 64 | for (int i = 0; i < PROF_RUNS; i++) { \ 65 | prof_accum_cycle = 0; \ 66 | prof_iterations = 0; \ 67 | func(__VA_ARGS__); \ 68 | runs[i] = prof_accum_cycle / prof_iterations; \ 69 | } \ 70 | \ 71 | prof_cycle_t res = runs[0]; \ 72 | for (int i = 0; i < PROF_RUNS; i++) { \ 73 | if (runs[i] < res) { \ 74 | res = runs[i]; \ 75 | } \ 76 | } \ 77 | res -= prof_baseline_cycle; \ 78 | printf("\r%s: %"PRIu64" %s", #func, res, prof_units); \ 79 | \ 80 | if (!isatty(0)) { \ 81 | prof_cycle_t prev; \ 82 | while (scanf("%*[^0-9]%"PRIu64, &prev) == 0); \ 83 | int64_t perc = 100*((int64_t)prev - (int64_t)res) / (int64_t)prev; \ 84 | \ 85 | if (perc > 10) { \ 86 | printf(" (\e[32m%+"PRId64"%%\e[0m)", perc); \ 87 | } else if (perc < -10) { \ 88 | printf(" (\e[31m%+"PRId64"%%\e[0m)", perc); \ 89 | } else { \ 90 | printf(" (%+"PRId64"%%)", perc); \ 91 | } \ 92 | } \ 93 | \ 94 | printf("\n"); \ 95 | res; \ 96 | }) 97 | 98 | #define prof_baseline(func, ...) ({ \ 99 | prof_baseline_cycle = 0; \ 100 | prof_baseline_cycle = prof_measure(func, __VA_ARGS__); \ 101 | }) 102 | 103 | 104 | // Various test functions 105 | void no_func(void *eh) { 106 | } 107 | 108 | 109 | // Actual performance tests 110 | void baseline_prof(void) { 111 | prof_loop() { 112 | prof_start(); 113 | __asm__ volatile (""); 114 | prof_stop(); 115 | } 116 | } 117 | 118 | void equeue_tick_prof(void) { 119 | prof_volatile(unsigned) res; 120 | prof_loop() { 121 | prof_start(); 122 | res = equeue_tick(); 123 | prof_stop(); 124 | } 125 | } 126 | 127 | void equeue_alloc_prof(void) { 128 | struct equeue q; 129 | equeue_create(&q, 32*EQUEUE_EVENT_SIZE); 130 | 131 | prof_loop() { 132 | prof_start(); 133 | void *e = equeue_alloc(&q, 8 * sizeof(int)); 134 | prof_stop(); 135 | 136 | equeue_dealloc(&q, e); 137 | } 138 | 139 | equeue_destroy(&q); 140 | } 141 | 142 | void equeue_alloc_many_prof(int count) { 143 | struct equeue q; 144 | equeue_create(&q, count*EQUEUE_EVENT_SIZE); 145 | 146 | void *es[count]; 147 | 148 | for (int i = 0; i < count; i++) { 149 | es[i] = equeue_alloc(&q, (i % 4) * sizeof(int)); 150 | } 151 | 152 | for (int i = 0; i < count; i++) { 153 | equeue_dealloc(&q, es[i]); 154 | } 155 | 156 | prof_loop() { 157 | prof_start(); 158 | void *e = equeue_alloc(&q, 8 * sizeof(int)); 159 | prof_stop(); 160 | 161 | equeue_dealloc(&q, e); 162 | } 163 | 164 | equeue_destroy(&q); 165 | } 166 | 167 | void equeue_post_prof(void) { 168 | struct equeue q; 169 | equeue_create(&q, EQUEUE_EVENT_SIZE); 170 | 171 | prof_loop() { 172 | void *e = equeue_alloc(&q, 0); 173 | 174 | prof_start(); 175 | int id = equeue_post(&q, no_func, e); 176 | prof_stop(); 177 | 178 | equeue_cancel(&q, id); 179 | } 180 | 181 | equeue_destroy(&q); 182 | } 183 | 184 | void equeue_post_many_prof(int count) { 185 | struct equeue q; 186 | equeue_create(&q, count*EQUEUE_EVENT_SIZE); 187 | 188 | for (int i = 0; i < count-1; i++) { 189 | equeue_call(&q, no_func, 0); 190 | } 191 | 192 | prof_loop() { 193 | void *e = equeue_alloc(&q, 0); 194 | 195 | prof_start(); 196 | int id = equeue_post(&q, no_func, e); 197 | prof_stop(); 198 | 199 | equeue_cancel(&q, id); 200 | } 201 | 202 | equeue_destroy(&q); 203 | } 204 | 205 | void equeue_post_future_prof(void) { 206 | struct equeue q; 207 | equeue_create(&q, EQUEUE_EVENT_SIZE); 208 | 209 | prof_loop() { 210 | void *e = equeue_alloc(&q, 0); 211 | equeue_event_delay(e, 1000); 212 | 213 | prof_start(); 214 | int id = equeue_post(&q, no_func, e); 215 | prof_stop(); 216 | 217 | equeue_cancel(&q, id); 218 | } 219 | 220 | equeue_destroy(&q); 221 | } 222 | 223 | void equeue_post_future_many_prof(int count) { 224 | struct equeue q; 225 | equeue_create(&q, count*EQUEUE_EVENT_SIZE); 226 | 227 | for (int i = 0; i < count-1; i++) { 228 | equeue_call(&q, no_func, 0); 229 | } 230 | 231 | prof_loop() { 232 | void *e = equeue_alloc(&q, 0); 233 | equeue_event_delay(e, 1000); 234 | 235 | prof_start(); 236 | int id = equeue_post(&q, no_func, e); 237 | prof_stop(); 238 | 239 | equeue_cancel(&q, id); 240 | } 241 | 242 | equeue_destroy(&q); 243 | } 244 | 245 | void equeue_dispatch_prof(void) { 246 | struct equeue q; 247 | equeue_create(&q, EQUEUE_EVENT_SIZE); 248 | 249 | prof_loop() { 250 | equeue_call(&q, no_func, 0); 251 | 252 | prof_start(); 253 | equeue_dispatch(&q, 0); 254 | prof_stop(); 255 | } 256 | 257 | equeue_destroy(&q); 258 | } 259 | 260 | void equeue_dispatch_many_prof(int count) { 261 | struct equeue q; 262 | equeue_create(&q, count*EQUEUE_EVENT_SIZE); 263 | 264 | prof_loop() { 265 | for (int i = 0; i < count; i++) { 266 | equeue_call(&q, no_func, 0); 267 | } 268 | 269 | prof_start(); 270 | equeue_dispatch(&q, 0); 271 | prof_stop(); 272 | } 273 | 274 | equeue_destroy(&q); 275 | } 276 | 277 | void equeue_cancel_prof(void) { 278 | struct equeue q; 279 | equeue_create(&q, EQUEUE_EVENT_SIZE); 280 | 281 | prof_loop() { 282 | int id = equeue_call(&q, no_func, 0); 283 | 284 | prof_start(); 285 | equeue_cancel(&q, id); 286 | prof_stop(); 287 | } 288 | 289 | equeue_destroy(&q); 290 | } 291 | 292 | void equeue_cancel_many_prof(int count) { 293 | struct equeue q; 294 | equeue_create(&q, count*EQUEUE_EVENT_SIZE); 295 | 296 | for (int i = 0; i < count-1; i++) { 297 | equeue_call(&q, no_func, 0); 298 | } 299 | 300 | prof_loop() { 301 | int id = equeue_call(&q, no_func, 0); 302 | 303 | prof_start(); 304 | equeue_cancel(&q, id); 305 | prof_stop(); 306 | } 307 | 308 | equeue_destroy(&q); 309 | } 310 | 311 | void equeue_alloc_size_prof(void) { 312 | size_t size = 32*EQUEUE_EVENT_SIZE; 313 | 314 | struct equeue q; 315 | equeue_create(&q, size); 316 | equeue_alloc(&q, 0); 317 | 318 | prof_result(size - q.slab.size, "bytes"); 319 | 320 | equeue_destroy(&q); 321 | } 322 | 323 | void equeue_alloc_many_size_prof(int count) { 324 | size_t size = count*EQUEUE_EVENT_SIZE; 325 | 326 | struct equeue q; 327 | equeue_create(&q, size); 328 | 329 | for (int i = 0; i < count; i++) { 330 | equeue_alloc(&q, (i % 4) * sizeof(int)); 331 | } 332 | 333 | prof_result(size - q.slab.size, "bytes"); 334 | 335 | equeue_destroy(&q); 336 | } 337 | 338 | void equeue_alloc_fragmented_size_prof(int count) { 339 | size_t size = count*EQUEUE_EVENT_SIZE; 340 | 341 | struct equeue q; 342 | equeue_create(&q, size); 343 | 344 | void *es[count]; 345 | 346 | for (int i = 0; i < count; i++) { 347 | es[i] = equeue_alloc(&q, (i % 4) * sizeof(int)); 348 | } 349 | 350 | for (int i = 0; i < count; i++) { 351 | equeue_dealloc(&q, es[i]); 352 | } 353 | 354 | for (int i = count-1; i >= 0; i--) { 355 | es[i] = equeue_alloc(&q, (i % 4) * sizeof(int)); 356 | } 357 | 358 | for (int i = count-1; i >= 0; i--) { 359 | equeue_dealloc(&q, es[i]); 360 | } 361 | 362 | for (int i = 0; i < count; i++) { 363 | equeue_alloc(&q, (i % 4) * sizeof(int)); 364 | } 365 | 366 | prof_result(size - q.slab.size, "bytes"); 367 | 368 | equeue_destroy(&q); 369 | } 370 | 371 | 372 | // Entry point 373 | int main() { 374 | printf("beginning profiling...\n"); 375 | 376 | prof_baseline(baseline_prof); 377 | 378 | prof_measure(equeue_tick_prof); 379 | prof_measure(equeue_alloc_prof); 380 | prof_measure(equeue_post_prof); 381 | prof_measure(equeue_post_future_prof); 382 | prof_measure(equeue_dispatch_prof); 383 | prof_measure(equeue_cancel_prof); 384 | 385 | prof_measure(equeue_alloc_many_prof, 1000); 386 | prof_measure(equeue_post_many_prof, 1000); 387 | prof_measure(equeue_post_future_many_prof, 1000); 388 | prof_measure(equeue_dispatch_many_prof, 100); 389 | prof_measure(equeue_cancel_many_prof, 100); 390 | 391 | prof_measure(equeue_alloc_size_prof); 392 | prof_measure(equeue_alloc_many_size_prof, 1000); 393 | prof_measure(equeue_alloc_fragmented_size_prof, 1000); 394 | 395 | printf("done!\n"); 396 | } 397 | -------------------------------------------------------------------------------- /equeue/tests/tests.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Testing framework for the events library 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license 6 | */ 7 | #include "equeue.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | // Testing setup 17 | static jmp_buf test_buf; 18 | static int test_line; 19 | static int test_failure; 20 | 21 | #define test_assert(test) ({ \ 22 | if (!(test)) { \ 23 | test_line = __LINE__; \ 24 | longjmp(test_buf, 1); \ 25 | } \ 26 | }) 27 | 28 | #define test_run(func, ...) ({ \ 29 | printf("%s: ...", #func); \ 30 | fflush(stdout); \ 31 | \ 32 | if (!setjmp(test_buf)) { \ 33 | func(__VA_ARGS__); \ 34 | printf("\r%s: \e[32mpassed\e[0m\n", #func); \ 35 | } else { \ 36 | printf("\r%s: \e[31mfailed\e[0m at line %d\n", #func, test_line); \ 37 | test_failure = true; \ 38 | } \ 39 | }) 40 | 41 | 42 | // Test functions 43 | void pass_func(void *eh) { 44 | } 45 | 46 | void simple_func(void *p) { 47 | (*(int *)p)++; 48 | } 49 | 50 | void sloth_func(void *p) { 51 | usleep(10000); 52 | (*(int *)p)++; 53 | } 54 | 55 | struct indirect { 56 | int *touched; 57 | uint8_t buffer[7]; 58 | }; 59 | 60 | void indirect_func(void *p) { 61 | struct indirect *i = (struct indirect*)p; 62 | (*i->touched)++; 63 | } 64 | 65 | struct timing { 66 | unsigned tick; 67 | unsigned delay; 68 | }; 69 | 70 | void timing_func(void *p) { 71 | struct timing *timing = (struct timing*)p; 72 | unsigned tick = equeue_tick(); 73 | 74 | unsigned t1 = timing->delay; 75 | unsigned t2 = tick - timing->tick; 76 | test_assert(t1 > t2 - 10 && t1 < t2 + 10); 77 | 78 | timing->tick = tick; 79 | } 80 | 81 | struct fragment { 82 | equeue_t *q; 83 | size_t size; 84 | struct timing timing; 85 | }; 86 | 87 | void fragment_func(void *p) { 88 | struct fragment *fragment = (struct fragment*)p; 89 | timing_func(&fragment->timing); 90 | 91 | struct fragment *nfragment = equeue_alloc(fragment->q, fragment->size); 92 | test_assert(nfragment); 93 | 94 | *nfragment = *fragment; 95 | equeue_event_delay(nfragment, fragment->timing.delay); 96 | 97 | int id = equeue_post(nfragment->q, fragment_func, nfragment); 98 | test_assert(id); 99 | } 100 | 101 | struct cancel { 102 | equeue_t *q; 103 | int id; 104 | }; 105 | 106 | void cancel_func(void *p) { 107 | struct cancel *cancel = (struct cancel *)p; 108 | equeue_cancel(cancel->q, cancel->id); 109 | } 110 | 111 | struct nest { 112 | equeue_t *q; 113 | void (*cb)(void *); 114 | void *data; 115 | }; 116 | 117 | void nest_func(void *p) { 118 | struct nest *nest = (struct nest *)p; 119 | equeue_call(nest->q, nest->cb, nest->data); 120 | 121 | usleep(10000); 122 | } 123 | 124 | 125 | // Simple call tests 126 | void simple_call_test(void) { 127 | equeue_t q; 128 | int err = equeue_create(&q, 2048); 129 | test_assert(!err); 130 | 131 | bool touched = false; 132 | equeue_call(&q, simple_func, &touched); 133 | equeue_dispatch(&q, 0); 134 | test_assert(touched); 135 | 136 | equeue_destroy(&q); 137 | } 138 | 139 | void simple_call_in_test(void) { 140 | equeue_t q; 141 | int err = equeue_create(&q, 2048); 142 | test_assert(!err); 143 | 144 | bool touched = false; 145 | int id = equeue_call_in(&q, 10, simple_func, &touched); 146 | test_assert(id); 147 | 148 | equeue_dispatch(&q, 15); 149 | test_assert(touched); 150 | 151 | equeue_destroy(&q); 152 | } 153 | 154 | void simple_call_every_test(void) { 155 | equeue_t q; 156 | int err = equeue_create(&q, 2048); 157 | test_assert(!err); 158 | 159 | bool touched = false; 160 | int id = equeue_call_every(&q, 10, simple_func, &touched); 161 | test_assert(id); 162 | 163 | equeue_dispatch(&q, 15); 164 | test_assert(touched); 165 | 166 | equeue_destroy(&q); 167 | } 168 | 169 | void simple_post_test(void) { 170 | equeue_t q; 171 | int err = equeue_create(&q, 2048); 172 | test_assert(!err); 173 | 174 | int touched = false; 175 | struct indirect *i = equeue_alloc(&q, sizeof(struct indirect)); 176 | test_assert(i); 177 | 178 | i->touched = &touched; 179 | int id = equeue_post(&q, indirect_func, i); 180 | test_assert(id); 181 | 182 | equeue_dispatch(&q, 0); 183 | test_assert(*i->touched); 184 | 185 | equeue_destroy(&q); 186 | } 187 | 188 | // Misc tests 189 | void destructor_test(void) { 190 | equeue_t q; 191 | int err = equeue_create(&q, 2048); 192 | test_assert(!err); 193 | 194 | int touched; 195 | struct indirect *e; 196 | int ids[3]; 197 | 198 | touched = 0; 199 | for (int i = 0; i < 3; i++) { 200 | e = equeue_alloc(&q, sizeof(struct indirect)); 201 | test_assert(e); 202 | 203 | e->touched = &touched; 204 | equeue_event_dtor(e, indirect_func); 205 | int id = equeue_post(&q, pass_func, e); 206 | test_assert(id); 207 | } 208 | 209 | equeue_dispatch(&q, 0); 210 | test_assert(touched == 3); 211 | 212 | touched = 0; 213 | for (int i = 0; i < 3; i++) { 214 | e = equeue_alloc(&q, sizeof(struct indirect)); 215 | test_assert(e); 216 | 217 | e->touched = &touched; 218 | equeue_event_dtor(e, indirect_func); 219 | ids[i] = equeue_post(&q, pass_func, e); 220 | test_assert(ids[i]); 221 | } 222 | 223 | for (int i = 0; i < 3; i++) { 224 | equeue_cancel(&q, ids[i]); 225 | } 226 | 227 | equeue_dispatch(&q, 0); 228 | test_assert(touched == 3); 229 | 230 | touched = 0; 231 | for (int i = 0; i < 3; i++) { 232 | e = equeue_alloc(&q, sizeof(struct indirect)); 233 | test_assert(e); 234 | 235 | e->touched = &touched; 236 | equeue_event_dtor(e, indirect_func); 237 | int id = equeue_post(&q, pass_func, e); 238 | test_assert(id); 239 | } 240 | 241 | equeue_destroy(&q); 242 | test_assert(touched == 3); 243 | } 244 | 245 | void allocation_failure_test(void) { 246 | equeue_t q; 247 | int err = equeue_create(&q, 2048); 248 | test_assert(!err); 249 | 250 | void *p = equeue_alloc(&q, 4096); 251 | test_assert(!p); 252 | 253 | for (int i = 0; i < 100; i++) { 254 | p = equeue_alloc(&q, 0); 255 | } 256 | test_assert(!p); 257 | 258 | equeue_destroy(&q); 259 | } 260 | 261 | void cancel_test(int N) { 262 | equeue_t q; 263 | int err = equeue_create(&q, 2048); 264 | test_assert(!err); 265 | 266 | bool touched = false; 267 | int *ids = malloc(N*sizeof(int)); 268 | 269 | for (int i = 0; i < N; i++) { 270 | ids[i] = equeue_call(&q, simple_func, &touched); 271 | } 272 | 273 | for (int i = N-1; i >= 0; i--) { 274 | equeue_cancel(&q, ids[i]); 275 | } 276 | 277 | free(ids); 278 | 279 | equeue_dispatch(&q, 0); 280 | test_assert(!touched); 281 | 282 | equeue_destroy(&q); 283 | } 284 | 285 | void cancel_inflight_test(void) { 286 | equeue_t q; 287 | int err = equeue_create(&q, 2048); 288 | test_assert(!err); 289 | 290 | bool touched = false; 291 | 292 | int id = equeue_call(&q, simple_func, &touched); 293 | equeue_cancel(&q, id); 294 | 295 | equeue_dispatch(&q, 0); 296 | test_assert(!touched); 297 | 298 | id = equeue_call(&q, simple_func, &touched); 299 | equeue_cancel(&q, id); 300 | 301 | equeue_dispatch(&q, 0); 302 | test_assert(!touched); 303 | 304 | struct cancel *cancel = equeue_alloc(&q, sizeof(struct cancel)); 305 | test_assert(cancel); 306 | cancel->q = &q; 307 | cancel->id = 0; 308 | 309 | id = equeue_post(&q, cancel_func, cancel); 310 | test_assert(id); 311 | 312 | cancel->id = equeue_call(&q, simple_func, &touched); 313 | 314 | equeue_dispatch(&q, 0); 315 | test_assert(!touched); 316 | 317 | equeue_destroy(&q); 318 | } 319 | 320 | void cancel_unnecessarily_test(void) { 321 | equeue_t q; 322 | int err = equeue_create(&q, 2048); 323 | test_assert(!err); 324 | 325 | int id = equeue_call(&q, pass_func, 0); 326 | for (int i = 0; i < 5; i++) { 327 | equeue_cancel(&q, id); 328 | } 329 | 330 | id = equeue_call(&q, pass_func, 0); 331 | equeue_dispatch(&q, 0); 332 | for (int i = 0; i < 5; i++) { 333 | equeue_cancel(&q, id); 334 | } 335 | 336 | bool touched = false; 337 | equeue_call(&q, simple_func, &touched); 338 | for (int i = 0; i < 5; i++) { 339 | equeue_cancel(&q, id); 340 | } 341 | 342 | equeue_dispatch(&q, 0); 343 | test_assert(touched); 344 | 345 | equeue_destroy(&q); 346 | } 347 | 348 | void loop_protect_test(void) { 349 | equeue_t q; 350 | int err = equeue_create(&q, 2048); 351 | test_assert(!err); 352 | 353 | bool touched = false; 354 | equeue_call_every(&q, 0, simple_func, &touched); 355 | 356 | equeue_dispatch(&q, 0); 357 | test_assert(touched); 358 | 359 | touched = false; 360 | equeue_call_every(&q, 1, simple_func, &touched); 361 | 362 | equeue_dispatch(&q, 0); 363 | test_assert(touched); 364 | 365 | equeue_destroy(&q); 366 | } 367 | 368 | void break_test(void) { 369 | equeue_t q; 370 | int err = equeue_create(&q, 2048); 371 | test_assert(!err); 372 | 373 | bool touched = false; 374 | equeue_call_every(&q, 0, simple_func, &touched); 375 | 376 | equeue_break(&q); 377 | equeue_dispatch(&q, -1); 378 | test_assert(touched); 379 | 380 | equeue_destroy(&q); 381 | } 382 | 383 | void period_test(void) { 384 | equeue_t q; 385 | int err = equeue_create(&q, 2048); 386 | test_assert(!err); 387 | 388 | int count = 0; 389 | equeue_call_every(&q, 10, simple_func, &count); 390 | 391 | equeue_dispatch(&q, 55); 392 | test_assert(count == 5); 393 | 394 | equeue_destroy(&q); 395 | } 396 | 397 | void nested_test(void) { 398 | equeue_t q; 399 | int err = equeue_create(&q, 2048); 400 | test_assert(!err); 401 | 402 | int touched = 0; 403 | struct nest *nest = equeue_alloc(&q, sizeof(struct nest)); 404 | test_assert(nest); 405 | nest->q = &q; 406 | nest->cb = simple_func; 407 | nest->data = &touched; 408 | 409 | int id = equeue_post(&q, nest_func, nest); 410 | test_assert(id); 411 | 412 | equeue_dispatch(&q, 5); 413 | test_assert(touched == 0); 414 | 415 | equeue_dispatch(&q, 5); 416 | test_assert(touched == 1); 417 | 418 | touched = 0; 419 | nest = equeue_alloc(&q, sizeof(struct nest)); 420 | test_assert(nest); 421 | nest->q = &q; 422 | nest->cb = simple_func; 423 | nest->data = &touched; 424 | 425 | id = equeue_post(&q, nest_func, nest); 426 | test_assert(id); 427 | 428 | equeue_dispatch(&q, 20); 429 | test_assert(touched == 1); 430 | 431 | equeue_destroy(&q); 432 | } 433 | 434 | void sloth_test(void) { 435 | equeue_t q; 436 | int err = equeue_create(&q, 2048); 437 | test_assert(!err); 438 | 439 | int touched = 0; 440 | int id = equeue_call(&q, sloth_func, &touched); 441 | test_assert(id); 442 | 443 | id = equeue_call_in(&q, 5, simple_func, &touched); 444 | test_assert(id); 445 | 446 | id = equeue_call_in(&q, 15, simple_func, &touched); 447 | test_assert(id); 448 | 449 | equeue_dispatch(&q, 20); 450 | test_assert(touched == 3); 451 | 452 | equeue_destroy(&q); 453 | } 454 | 455 | void *multithread_thread(void *p) { 456 | equeue_t *q = (equeue_t *)p; 457 | equeue_dispatch(q, -1); 458 | return 0; 459 | } 460 | 461 | void multithread_test(void) { 462 | equeue_t q; 463 | int err = equeue_create(&q, 2048); 464 | test_assert(!err); 465 | 466 | int touched = 0; 467 | equeue_call_every(&q, 1, simple_func, &touched); 468 | 469 | pthread_t thread; 470 | err = pthread_create(&thread, 0, multithread_thread, &q); 471 | test_assert(!err); 472 | 473 | usleep(10000); 474 | equeue_break(&q); 475 | err = pthread_join(thread, 0); 476 | test_assert(!err); 477 | 478 | test_assert(touched); 479 | 480 | equeue_destroy(&q); 481 | } 482 | 483 | void background_func(void *p, int ms) { 484 | *(unsigned *)p = ms; 485 | } 486 | 487 | void background_test(void) { 488 | equeue_t q; 489 | int err = equeue_create(&q, 2048); 490 | test_assert(!err); 491 | 492 | int id = equeue_call_in(&q, 20, pass_func, 0); 493 | test_assert(id); 494 | 495 | unsigned ms; 496 | equeue_background(&q, background_func, &ms); 497 | test_assert(ms == 20); 498 | 499 | id = equeue_call_in(&q, 10, pass_func, 0); 500 | test_assert(id); 501 | test_assert(ms == 10); 502 | 503 | id = equeue_call(&q, pass_func, 0); 504 | test_assert(id); 505 | test_assert(ms == 0); 506 | 507 | equeue_dispatch(&q, 0); 508 | test_assert(ms == 10); 509 | 510 | equeue_destroy(&q); 511 | test_assert(ms == -1); 512 | } 513 | 514 | void chain_test(void) { 515 | equeue_t q1; 516 | int err = equeue_create(&q1, 2048); 517 | test_assert(!err); 518 | 519 | equeue_t q2; 520 | err = equeue_create(&q2, 2048); 521 | test_assert(!err); 522 | 523 | equeue_chain(&q2, &q1); 524 | 525 | int touched = 0; 526 | 527 | int id1 = equeue_call_in(&q1, 20, simple_func, &touched); 528 | int id2 = equeue_call_in(&q2, 20, simple_func, &touched); 529 | test_assert(id1 && id2); 530 | 531 | id1 = equeue_call(&q1, simple_func, &touched); 532 | id2 = equeue_call(&q2, simple_func, &touched); 533 | test_assert(id1 && id2); 534 | 535 | id1 = equeue_call_in(&q1, 5, simple_func, &touched); 536 | id2 = equeue_call_in(&q2, 5, simple_func, &touched); 537 | test_assert(id1 && id2); 538 | 539 | equeue_cancel(&q1, id1); 540 | equeue_cancel(&q2, id2); 541 | 542 | id1 = equeue_call_in(&q1, 10, simple_func, &touched); 543 | id2 = equeue_call_in(&q2, 10, simple_func, &touched); 544 | test_assert(id1 && id2); 545 | 546 | equeue_dispatch(&q1, 30); 547 | 548 | test_assert(touched == 6); 549 | 550 | equeue_destroy(&q1); 551 | equeue_destroy(&q2); 552 | } 553 | 554 | void unchain_test(void) { 555 | equeue_t q1; 556 | int err = equeue_create(&q1, 2048); 557 | test_assert(!err); 558 | 559 | equeue_t q2; 560 | err = equeue_create(&q2, 2048); 561 | test_assert(!err); 562 | 563 | equeue_chain(&q2, &q1); 564 | 565 | int touched = 0; 566 | int id1 = equeue_call(&q1, simple_func, &touched); 567 | int id2 = equeue_call(&q2, simple_func, &touched); 568 | test_assert(id1 && id2); 569 | 570 | equeue_dispatch(&q1, 0); 571 | test_assert(touched == 2); 572 | 573 | equeue_chain(&q2, 0); 574 | equeue_chain(&q1, &q2); 575 | 576 | id1 = equeue_call(&q1, simple_func, &touched); 577 | id2 = equeue_call(&q2, simple_func, &touched); 578 | test_assert(id1 && id2); 579 | 580 | equeue_dispatch(&q2, 0); 581 | test_assert(touched == 4); 582 | 583 | equeue_destroy(&q1); 584 | equeue_destroy(&q2); 585 | } 586 | 587 | // Barrage tests 588 | void simple_barrage_test(int N) { 589 | equeue_t q; 590 | int err = equeue_create(&q, N*(EQUEUE_EVENT_SIZE+sizeof(struct timing))); 591 | test_assert(!err); 592 | 593 | for (int i = 0; i < N; i++) { 594 | struct timing *timing = equeue_alloc(&q, sizeof(struct timing)); 595 | test_assert(timing); 596 | 597 | timing->tick = equeue_tick(); 598 | timing->delay = (i+1)*100; 599 | equeue_event_delay(timing, timing->delay); 600 | equeue_event_period(timing, timing->delay); 601 | 602 | int id = equeue_post(&q, timing_func, timing); 603 | test_assert(id); 604 | } 605 | 606 | equeue_dispatch(&q, N*100); 607 | 608 | equeue_destroy(&q); 609 | } 610 | 611 | void fragmenting_barrage_test(int N) { 612 | equeue_t q; 613 | int err = equeue_create(&q, 614 | 2*N*(EQUEUE_EVENT_SIZE+sizeof(struct fragment)+N*sizeof(int))); 615 | test_assert(!err); 616 | 617 | for (int i = 0; i < N; i++) { 618 | size_t size = sizeof(struct fragment) + i*sizeof(int); 619 | struct fragment *fragment = equeue_alloc(&q, size); 620 | test_assert(fragment); 621 | 622 | fragment->q = &q; 623 | fragment->size = size; 624 | fragment->timing.tick = equeue_tick(); 625 | fragment->timing.delay = (i+1)*100; 626 | equeue_event_delay(fragment, fragment->timing.delay); 627 | 628 | int id = equeue_post(&q, fragment_func, fragment); 629 | test_assert(id); 630 | } 631 | 632 | equeue_dispatch(&q, N*100); 633 | 634 | equeue_destroy(&q); 635 | } 636 | 637 | struct ethread { 638 | pthread_t thread; 639 | equeue_t *q; 640 | int ms; 641 | }; 642 | 643 | static void *ethread_dispatch(void *p) { 644 | struct ethread *t = (struct ethread*)p; 645 | equeue_dispatch(t->q, t->ms); 646 | return 0; 647 | } 648 | 649 | void multithreaded_barrage_test(int N) { 650 | equeue_t q; 651 | int err = equeue_create(&q, N*(EQUEUE_EVENT_SIZE+sizeof(struct timing))); 652 | test_assert(!err); 653 | 654 | struct ethread t; 655 | t.q = &q; 656 | t.ms = N*100; 657 | err = pthread_create(&t.thread, 0, ethread_dispatch, &t); 658 | test_assert(!err); 659 | 660 | for (int i = 0; i < N; i++) { 661 | struct timing *timing = equeue_alloc(&q, sizeof(struct timing)); 662 | test_assert(timing); 663 | 664 | timing->tick = equeue_tick(); 665 | timing->delay = (i+1)*100; 666 | equeue_event_delay(timing, timing->delay); 667 | equeue_event_period(timing, timing->delay); 668 | 669 | int id = equeue_post(&q, timing_func, timing); 670 | test_assert(id); 671 | } 672 | 673 | err = pthread_join(t.thread, 0); 674 | test_assert(!err); 675 | 676 | equeue_destroy(&q); 677 | } 678 | 679 | 680 | int main() { 681 | printf("beginning tests...\n"); 682 | 683 | test_run(simple_call_test); 684 | test_run(simple_call_in_test); 685 | test_run(simple_call_every_test); 686 | test_run(simple_post_test); 687 | test_run(destructor_test); 688 | test_run(allocation_failure_test); 689 | test_run(cancel_test, 20); 690 | test_run(cancel_inflight_test); 691 | test_run(cancel_unnecessarily_test); 692 | test_run(loop_protect_test); 693 | test_run(break_test); 694 | test_run(period_test); 695 | test_run(nested_test); 696 | test_run(sloth_test); 697 | test_run(background_test); 698 | test_run(chain_test); 699 | test_run(unchain_test); 700 | test_run(multithread_test); 701 | test_run(simple_barrage_test, 20); 702 | test_run(fragmenting_barrage_test, 20); 703 | test_run(multithreaded_barrage_test, 20); 704 | 705 | printf("done!\n"); 706 | return test_failure; 707 | } 708 | -------------------------------------------------------------------------------- /mbed_events.h: -------------------------------------------------------------------------------- 1 | /* events 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #ifndef MBED_EVENTS_H 17 | #define MBED_EVENTS_H 18 | 19 | 20 | #include "equeue/equeue.h" 21 | 22 | 23 | #ifdef __cplusplus 24 | 25 | #include "EventQueue.h" 26 | #include "Event.h" 27 | 28 | using namespace events; 29 | 30 | #endif 31 | 32 | 33 | #endif 34 | --------------------------------------------------------------------------------