Marco Zecchini
/
Example_RTOS
Rtos API example
Embed:
(wiki syntax)
Show/hide line numbers
tests.c
00001 /* 00002 * Testing framework for the events library 00003 * 00004 * Copyright (c) 2016 Christopher Haster 00005 * 00006 * Licensed under the Apache License, Version 2.0 (the "License"); 00007 * you may not use this file except in compliance with the License. 00008 * You may obtain a copy of the License at 00009 * 00010 * http://www.apache.org/licenses/LICENSE-2.0 00011 * 00012 * Unless required by applicable law or agreed to in writing, software 00013 * distributed under the License is distributed on an "AS IS" BASIS, 00014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 * See the License for the specific language governing permissions and 00016 * limitations under the License. 00017 */ 00018 #include "equeue.h" 00019 #include <unistd.h> 00020 #include <stdio.h> 00021 #include <setjmp.h> 00022 #include <stdint.h> 00023 #include <stdlib.h> 00024 #include <pthread.h> 00025 00026 00027 // Testing setup 00028 static jmp_buf test_buf; 00029 static int test_line; 00030 static int test_failure; 00031 00032 #define test_assert(test) ({ \ 00033 if (!(test)) { \ 00034 test_line = __LINE__; \ 00035 longjmp(test_buf, 1); \ 00036 } \ 00037 }) 00038 00039 #define test_run(func, ...) ({ \ 00040 printf("%s: ...", #func); \ 00041 fflush(stdout); \ 00042 \ 00043 if (!setjmp(test_buf)) { \ 00044 func(__VA_ARGS__); \ 00045 printf("\r%s: \e[32mpassed\e[0m\n", #func); \ 00046 } else { \ 00047 printf("\r%s: \e[31mfailed\e[0m at line %d\n", #func, test_line); \ 00048 test_failure = true; \ 00049 } \ 00050 }) 00051 00052 00053 // Test functions 00054 void pass_func(void *eh) { 00055 } 00056 00057 void simple_func(void *p) { 00058 (*(int *)p)++; 00059 } 00060 00061 void sloth_func(void *p) { 00062 usleep(10000); 00063 (*(int *)p)++; 00064 } 00065 00066 struct indirect { 00067 int *touched; 00068 uint8_t buffer[7]; 00069 }; 00070 00071 void indirect_func(void *p) { 00072 struct indirect *i = (struct indirect*)p; 00073 (*i->touched)++; 00074 } 00075 00076 struct timing { 00077 unsigned tick; 00078 unsigned delay; 00079 }; 00080 00081 void timing_func(void *p) { 00082 struct timing *timing = (struct timing*)p; 00083 unsigned tick = equeue_tick(); 00084 00085 unsigned t1 = timing->delay; 00086 unsigned t2 = tick - timing->tick; 00087 test_assert(t1 > t2 - 10 && t1 < t2 + 10); 00088 00089 timing->tick = tick; 00090 } 00091 00092 struct fragment { 00093 equeue_t *q; 00094 size_t size; 00095 struct timing timing; 00096 }; 00097 00098 void fragment_func(void *p) { 00099 struct fragment *fragment = (struct fragment*)p; 00100 timing_func(&fragment->timing); 00101 00102 struct fragment *nfragment = equeue_alloc(fragment->q, fragment->size); 00103 test_assert(nfragment); 00104 00105 *nfragment = *fragment; 00106 equeue_event_delay(nfragment, fragment->timing.delay); 00107 00108 int id = equeue_post(nfragment->q, fragment_func, nfragment); 00109 test_assert(id); 00110 } 00111 00112 struct cancel { 00113 equeue_t *q; 00114 int id; 00115 }; 00116 00117 void cancel_func(void *p) { 00118 struct cancel *cancel = (struct cancel *)p; 00119 equeue_cancel(cancel->q, cancel->id); 00120 } 00121 00122 struct nest { 00123 equeue_t *q; 00124 void (*cb)(void *); 00125 void *data; 00126 }; 00127 00128 void nest_func(void *p) { 00129 struct nest *nest = (struct nest *)p; 00130 equeue_call(nest->q, nest->cb, nest->data); 00131 00132 usleep(10000); 00133 } 00134 00135 00136 // Simple call tests 00137 void simple_call_test(void) { 00138 equeue_t q; 00139 int err = equeue_create(&q, 2048); 00140 test_assert(!err); 00141 00142 bool touched = false; 00143 equeue_call(&q, simple_func, &touched); 00144 equeue_dispatch(&q, 0); 00145 test_assert(touched); 00146 00147 equeue_destroy(&q); 00148 } 00149 00150 void simple_call_in_test(void) { 00151 equeue_t q; 00152 int err = equeue_create(&q, 2048); 00153 test_assert(!err); 00154 00155 bool touched = false; 00156 int id = equeue_call_in(&q, 10, simple_func, &touched); 00157 test_assert(id); 00158 00159 equeue_dispatch(&q, 15); 00160 test_assert(touched); 00161 00162 equeue_destroy(&q); 00163 } 00164 00165 void simple_call_every_test(void) { 00166 equeue_t q; 00167 int err = equeue_create(&q, 2048); 00168 test_assert(!err); 00169 00170 bool touched = false; 00171 int id = equeue_call_every(&q, 10, simple_func, &touched); 00172 test_assert(id); 00173 00174 equeue_dispatch(&q, 15); 00175 test_assert(touched); 00176 00177 equeue_destroy(&q); 00178 } 00179 00180 void simple_post_test(void) { 00181 equeue_t q; 00182 int err = equeue_create(&q, 2048); 00183 test_assert(!err); 00184 00185 int touched = false; 00186 struct indirect *i = equeue_alloc(&q, sizeof(struct indirect)); 00187 test_assert(i); 00188 00189 i->touched = &touched; 00190 int id = equeue_post(&q, indirect_func, i); 00191 test_assert(id); 00192 00193 equeue_dispatch(&q, 0); 00194 test_assert(*i->touched); 00195 00196 equeue_destroy(&q); 00197 } 00198 00199 // Misc tests 00200 void destructor_test(void) { 00201 equeue_t q; 00202 int err = equeue_create(&q, 2048); 00203 test_assert(!err); 00204 00205 int touched; 00206 struct indirect *e; 00207 int ids[3]; 00208 00209 touched = 0; 00210 for (int i = 0; i < 3; i++) { 00211 e = equeue_alloc(&q, sizeof(struct indirect)); 00212 test_assert(e); 00213 00214 e->touched = &touched; 00215 equeue_event_dtor(e, indirect_func); 00216 int id = equeue_post(&q, pass_func, e); 00217 test_assert(id); 00218 } 00219 00220 equeue_dispatch(&q, 0); 00221 test_assert(touched == 3); 00222 00223 touched = 0; 00224 for (int i = 0; i < 3; i++) { 00225 e = equeue_alloc(&q, sizeof(struct indirect)); 00226 test_assert(e); 00227 00228 e->touched = &touched; 00229 equeue_event_dtor(e, indirect_func); 00230 ids[i] = equeue_post(&q, pass_func, e); 00231 test_assert(ids[i]); 00232 } 00233 00234 for (int i = 0; i < 3; i++) { 00235 equeue_cancel(&q, ids[i]); 00236 } 00237 00238 equeue_dispatch(&q, 0); 00239 test_assert(touched == 3); 00240 00241 touched = 0; 00242 for (int i = 0; i < 3; i++) { 00243 e = equeue_alloc(&q, sizeof(struct indirect)); 00244 test_assert(e); 00245 00246 e->touched = &touched; 00247 equeue_event_dtor(e, indirect_func); 00248 int id = equeue_post(&q, pass_func, e); 00249 test_assert(id); 00250 } 00251 00252 equeue_destroy(&q); 00253 test_assert(touched == 3); 00254 } 00255 00256 void allocation_failure_test(void) { 00257 equeue_t q; 00258 int err = equeue_create(&q, 2048); 00259 test_assert(!err); 00260 00261 void *p = equeue_alloc(&q, 4096); 00262 test_assert(!p); 00263 00264 for (int i = 0; i < 100; i++) { 00265 p = equeue_alloc(&q, 0); 00266 } 00267 test_assert(!p); 00268 00269 equeue_destroy(&q); 00270 } 00271 00272 void cancel_test(int N) { 00273 equeue_t q; 00274 int err = equeue_create(&q, 2048); 00275 test_assert(!err); 00276 00277 bool touched = false; 00278 int *ids = malloc(N*sizeof(int)); 00279 00280 for (int i = 0; i < N; i++) { 00281 ids[i] = equeue_call(&q, simple_func, &touched); 00282 } 00283 00284 for (int i = N-1; i >= 0; i--) { 00285 equeue_cancel(&q, ids[i]); 00286 } 00287 00288 free(ids); 00289 00290 equeue_dispatch(&q, 0); 00291 test_assert(!touched); 00292 00293 equeue_destroy(&q); 00294 } 00295 00296 void cancel_inflight_test(void) { 00297 equeue_t q; 00298 int err = equeue_create(&q, 2048); 00299 test_assert(!err); 00300 00301 bool touched = false; 00302 00303 int id = equeue_call(&q, simple_func, &touched); 00304 equeue_cancel(&q, id); 00305 00306 equeue_dispatch(&q, 0); 00307 test_assert(!touched); 00308 00309 id = equeue_call(&q, simple_func, &touched); 00310 equeue_cancel(&q, id); 00311 00312 equeue_dispatch(&q, 0); 00313 test_assert(!touched); 00314 00315 struct cancel *cancel = equeue_alloc(&q, sizeof(struct cancel)); 00316 test_assert(cancel); 00317 cancel->q = &q; 00318 cancel->id = 0; 00319 00320 id = equeue_post(&q, cancel_func, cancel); 00321 test_assert(id); 00322 00323 cancel->id = equeue_call(&q, simple_func, &touched); 00324 00325 equeue_dispatch(&q, 0); 00326 test_assert(!touched); 00327 00328 equeue_destroy(&q); 00329 } 00330 00331 void cancel_unnecessarily_test(void) { 00332 equeue_t q; 00333 int err = equeue_create(&q, 2048); 00334 test_assert(!err); 00335 00336 int id = equeue_call(&q, pass_func, 0); 00337 for (int i = 0; i < 5; i++) { 00338 equeue_cancel(&q, id); 00339 } 00340 00341 id = equeue_call(&q, pass_func, 0); 00342 equeue_dispatch(&q, 0); 00343 for (int i = 0; i < 5; i++) { 00344 equeue_cancel(&q, id); 00345 } 00346 00347 bool touched = false; 00348 equeue_call(&q, simple_func, &touched); 00349 for (int i = 0; i < 5; i++) { 00350 equeue_cancel(&q, id); 00351 } 00352 00353 equeue_dispatch(&q, 0); 00354 test_assert(touched); 00355 00356 equeue_destroy(&q); 00357 } 00358 00359 void loop_protect_test(void) { 00360 equeue_t q; 00361 int err = equeue_create(&q, 2048); 00362 test_assert(!err); 00363 00364 bool touched = false; 00365 equeue_call_every(&q, 0, simple_func, &touched); 00366 00367 equeue_dispatch(&q, 0); 00368 test_assert(touched); 00369 00370 touched = false; 00371 equeue_call_every(&q, 1, simple_func, &touched); 00372 00373 equeue_dispatch(&q, 0); 00374 test_assert(touched); 00375 00376 equeue_destroy(&q); 00377 } 00378 00379 void break_test(void) { 00380 equeue_t q; 00381 int err = equeue_create(&q, 2048); 00382 test_assert(!err); 00383 00384 bool touched = false; 00385 equeue_call_every(&q, 0, simple_func, &touched); 00386 00387 equeue_break(&q); 00388 equeue_dispatch(&q, -1); 00389 test_assert(touched); 00390 00391 equeue_destroy(&q); 00392 } 00393 00394 void period_test(void) { 00395 equeue_t q; 00396 int err = equeue_create(&q, 2048); 00397 test_assert(!err); 00398 00399 int count = 0; 00400 equeue_call_every(&q, 10, simple_func, &count); 00401 00402 equeue_dispatch(&q, 55); 00403 test_assert(count == 5); 00404 00405 equeue_destroy(&q); 00406 } 00407 00408 void nested_test(void) { 00409 equeue_t q; 00410 int err = equeue_create(&q, 2048); 00411 test_assert(!err); 00412 00413 int touched = 0; 00414 struct nest *nest = equeue_alloc(&q, sizeof(struct nest)); 00415 test_assert(nest); 00416 nest->q = &q; 00417 nest->cb = simple_func; 00418 nest->data = &touched; 00419 00420 int id = equeue_post(&q, nest_func, nest); 00421 test_assert(id); 00422 00423 equeue_dispatch(&q, 5); 00424 test_assert(touched == 0); 00425 00426 equeue_dispatch(&q, 5); 00427 test_assert(touched == 1); 00428 00429 touched = 0; 00430 nest = equeue_alloc(&q, sizeof(struct nest)); 00431 test_assert(nest); 00432 nest->q = &q; 00433 nest->cb = simple_func; 00434 nest->data = &touched; 00435 00436 id = equeue_post(&q, nest_func, nest); 00437 test_assert(id); 00438 00439 equeue_dispatch(&q, 20); 00440 test_assert(touched == 1); 00441 00442 equeue_destroy(&q); 00443 } 00444 00445 void sloth_test(void) { 00446 equeue_t q; 00447 int err = equeue_create(&q, 2048); 00448 test_assert(!err); 00449 00450 int touched = 0; 00451 int id = equeue_call(&q, sloth_func, &touched); 00452 test_assert(id); 00453 00454 id = equeue_call_in(&q, 5, simple_func, &touched); 00455 test_assert(id); 00456 00457 id = equeue_call_in(&q, 15, simple_func, &touched); 00458 test_assert(id); 00459 00460 equeue_dispatch(&q, 20); 00461 test_assert(touched == 3); 00462 00463 equeue_destroy(&q); 00464 } 00465 00466 void *multithread_thread(void *p) { 00467 equeue_t *q = (equeue_t *)p; 00468 equeue_dispatch(q, -1); 00469 return 0; 00470 } 00471 00472 void multithread_test(void) { 00473 equeue_t q; 00474 int err = equeue_create(&q, 2048); 00475 test_assert(!err); 00476 00477 int touched = 0; 00478 equeue_call_every(&q, 1, simple_func, &touched); 00479 00480 pthread_t thread; 00481 err = pthread_create(&thread, 0, multithread_thread, &q); 00482 test_assert(!err); 00483 00484 usleep(10000); 00485 equeue_break(&q); 00486 err = pthread_join(thread, 0); 00487 test_assert(!err); 00488 00489 test_assert(touched); 00490 00491 equeue_destroy(&q); 00492 } 00493 00494 void background_func(void *p, int ms) { 00495 *(unsigned *)p = ms; 00496 } 00497 00498 void background_test(void) { 00499 equeue_t q; 00500 int err = equeue_create(&q, 2048); 00501 test_assert(!err); 00502 00503 int id = equeue_call_in(&q, 20, pass_func, 0); 00504 test_assert(id); 00505 00506 unsigned ms; 00507 equeue_background(&q, background_func, &ms); 00508 test_assert(ms == 20); 00509 00510 id = equeue_call_in(&q, 10, pass_func, 0); 00511 test_assert(id); 00512 test_assert(ms == 10); 00513 00514 id = equeue_call(&q, pass_func, 0); 00515 test_assert(id); 00516 test_assert(ms == 0); 00517 00518 equeue_dispatch(&q, 0); 00519 test_assert(ms == 10); 00520 00521 equeue_destroy(&q); 00522 test_assert(ms == -1); 00523 } 00524 00525 void chain_test(void) { 00526 equeue_t q1; 00527 int err = equeue_create(&q1, 2048); 00528 test_assert(!err); 00529 00530 equeue_t q2; 00531 err = equeue_create(&q2, 2048); 00532 test_assert(!err); 00533 00534 equeue_chain(&q2, &q1); 00535 00536 int touched = 0; 00537 00538 int id1 = equeue_call_in(&q1, 20, simple_func, &touched); 00539 int id2 = equeue_call_in(&q2, 20, simple_func, &touched); 00540 test_assert(id1 && id2); 00541 00542 id1 = equeue_call(&q1, simple_func, &touched); 00543 id2 = equeue_call(&q2, simple_func, &touched); 00544 test_assert(id1 && id2); 00545 00546 id1 = equeue_call_in(&q1, 5, simple_func, &touched); 00547 id2 = equeue_call_in(&q2, 5, simple_func, &touched); 00548 test_assert(id1 && id2); 00549 00550 equeue_cancel(&q1, id1); 00551 equeue_cancel(&q2, id2); 00552 00553 id1 = equeue_call_in(&q1, 10, simple_func, &touched); 00554 id2 = equeue_call_in(&q2, 10, simple_func, &touched); 00555 test_assert(id1 && id2); 00556 00557 equeue_dispatch(&q1, 30); 00558 00559 test_assert(touched == 6); 00560 00561 equeue_destroy(&q1); 00562 equeue_destroy(&q2); 00563 } 00564 00565 void unchain_test(void) { 00566 equeue_t q1; 00567 int err = equeue_create(&q1, 2048); 00568 test_assert(!err); 00569 00570 equeue_t q2; 00571 err = equeue_create(&q2, 2048); 00572 test_assert(!err); 00573 00574 equeue_chain(&q2, &q1); 00575 00576 int touched = 0; 00577 int id1 = equeue_call(&q1, simple_func, &touched); 00578 int id2 = equeue_call(&q2, simple_func, &touched); 00579 test_assert(id1 && id2); 00580 00581 equeue_dispatch(&q1, 0); 00582 test_assert(touched == 2); 00583 00584 equeue_chain(&q2, 0); 00585 equeue_chain(&q1, &q2); 00586 00587 id1 = equeue_call(&q1, simple_func, &touched); 00588 id2 = equeue_call(&q2, simple_func, &touched); 00589 test_assert(id1 && id2); 00590 00591 equeue_dispatch(&q2, 0); 00592 test_assert(touched == 4); 00593 00594 equeue_destroy(&q1); 00595 equeue_destroy(&q2); 00596 } 00597 00598 // Barrage tests 00599 void simple_barrage_test(int N) { 00600 equeue_t q; 00601 int err = equeue_create(&q, N*(EQUEUE_EVENT_SIZE+sizeof(struct timing))); 00602 test_assert(!err); 00603 00604 for (int i = 0; i < N; i++) { 00605 struct timing *timing = equeue_alloc(&q, sizeof(struct timing)); 00606 test_assert(timing); 00607 00608 timing->tick = equeue_tick(); 00609 timing->delay = (i+1)*100; 00610 equeue_event_delay(timing, timing->delay); 00611 equeue_event_period(timing, timing->delay); 00612 00613 int id = equeue_post(&q, timing_func, timing); 00614 test_assert(id); 00615 } 00616 00617 equeue_dispatch(&q, N*100); 00618 00619 equeue_destroy(&q); 00620 } 00621 00622 void fragmenting_barrage_test(int N) { 00623 equeue_t q; 00624 int err = equeue_create(&q, 00625 2*N*(EQUEUE_EVENT_SIZE+sizeof(struct fragment)+N*sizeof(int))); 00626 test_assert(!err); 00627 00628 for (int i = 0; i < N; i++) { 00629 size_t size = sizeof(struct fragment) + i*sizeof(int); 00630 struct fragment *fragment = equeue_alloc(&q, size); 00631 test_assert(fragment); 00632 00633 fragment->q = &q; 00634 fragment->size = size; 00635 fragment->timing.tick = equeue_tick(); 00636 fragment->timing.delay = (i+1)*100; 00637 equeue_event_delay(fragment, fragment->timing.delay); 00638 00639 int id = equeue_post(&q, fragment_func, fragment); 00640 test_assert(id); 00641 } 00642 00643 equeue_dispatch(&q, N*100); 00644 00645 equeue_destroy(&q); 00646 } 00647 00648 struct ethread { 00649 pthread_t thread; 00650 equeue_t *q; 00651 int ms; 00652 }; 00653 00654 static void *ethread_dispatch(void *p) { 00655 struct ethread *t = (struct ethread*)p; 00656 equeue_dispatch(t->q, t->ms); 00657 return 0; 00658 } 00659 00660 void multithreaded_barrage_test(int N) { 00661 equeue_t q; 00662 int err = equeue_create(&q, N*(EQUEUE_EVENT_SIZE+sizeof(struct timing))); 00663 test_assert(!err); 00664 00665 struct ethread t; 00666 t.q = &q; 00667 t.ms = N*100; 00668 err = pthread_create(&t.thread, 0, ethread_dispatch, &t); 00669 test_assert(!err); 00670 00671 for (int i = 0; i < N; i++) { 00672 struct timing *timing = equeue_alloc(&q, sizeof(struct timing)); 00673 test_assert(timing); 00674 00675 timing->tick = equeue_tick(); 00676 timing->delay = (i+1)*100; 00677 equeue_event_delay(timing, timing->delay); 00678 equeue_event_period(timing, timing->delay); 00679 00680 int id = equeue_post(&q, timing_func, timing); 00681 test_assert(id); 00682 } 00683 00684 err = pthread_join(t.thread, 0); 00685 test_assert(!err); 00686 00687 equeue_destroy(&q); 00688 } 00689 00690 00691 int main() { 00692 printf("beginning tests...\n"); 00693 00694 test_run(simple_call_test); 00695 test_run(simple_call_in_test); 00696 test_run(simple_call_every_test); 00697 test_run(simple_post_test); 00698 test_run(destructor_test); 00699 test_run(allocation_failure_test); 00700 test_run(cancel_test, 20); 00701 test_run(cancel_inflight_test); 00702 test_run(cancel_unnecessarily_test); 00703 test_run(loop_protect_test); 00704 test_run(break_test); 00705 test_run(period_test); 00706 test_run(nested_test); 00707 test_run(sloth_test); 00708 test_run(background_test); 00709 test_run(chain_test); 00710 test_run(unchain_test); 00711 test_run(multithread_test); 00712 test_run(simple_barrage_test, 20); 00713 test_run(fragmenting_barrage_test, 20); 00714 test_run(multithreaded_barrage_test, 20); 00715 00716 printf("done!\n"); 00717 return test_failure; 00718 }
Generated on Sun Jul 17 2022 08:25:32 by 1.7.2