| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| #include <stdio.h> |
| #include <limits.h> |
| #include <qpid/dispatch/timer.h> |
| #include "dispatch_private.h" |
| #include <qpid/dispatch/alloc.h> |
| #include "timer_private.h" |
| #include "test_case.h" |
| #include <qpid/dispatch/threading.h> |
| |
| |
| static unsigned long fire_mask; |
| static unsigned long fired; |
| static qd_duration_t timeout; |
| static long time_value; |
| static qd_timer_t *timers[16]; |
| |
| |
| /* Dummy out the now and timeout functions */ |
| qd_timestamp_t qd_timer_now() { |
| return time_value; |
| } |
| |
| void qd_server_timeout(qd_server_t *server, qd_duration_t duration) { |
| timeout = duration; |
| } |
| |
| static void on_timer(void *context) |
| { |
| fire_mask |= (unsigned long) context; |
| ++fired; |
| } |
| |
| |
| static char* test_quiet(void *context) |
| { |
| fire_mask = fired = 0; |
| qd_timer_visit(); |
| qd_timer_visit(); |
| if (fired != 0 && fire_mask != 0) |
| return "Expected zero timers fired"; |
| return 0; |
| } |
| |
| static char* test_immediate(void *context) |
| { |
| fire_mask = fired = 0; |
| qd_timer_schedule(timers[0], 0); |
| if (fired != 0) return "Premature firing"; |
| qd_timer_visit(); |
| if (fired != 1) return "Expected 1 firing"; |
| if (fire_mask != 1) return "Incorrect fire mask"; |
| |
| return 0; |
| } |
| |
| |
| static char* test_immediate_reschedule(void *context) |
| { |
| fire_mask = fired = 0; |
| qd_timer_schedule(timers[0], 0); |
| qd_timer_schedule(timers[0], 0); |
| qd_timer_visit(); |
| |
| if (fired > 1) return "pass 1 - Too many firings"; |
| if (fire_mask != 1) return "pass 1 - Incorrect fire mask"; |
| |
| fire_mask = fired = 0; |
| qd_timer_schedule(timers[0], 0); |
| qd_timer_schedule(timers[0], 0); |
| qd_timer_visit(); |
| |
| if (fired > 1) return "pass 2 - Too many firings"; |
| if (fire_mask != 1) return "pass 2 - Incorrect fire mask"; |
| |
| return 0; |
| } |
| |
| |
| static char* test_immediate_plus_delayed(void *context) |
| { |
| fire_mask = fired = 0; |
| qd_timer_schedule(timers[0], 0); |
| qd_timer_schedule(timers[1], 5); |
| qd_timer_visit(); |
| |
| if (fired > 1) return "Too many firings"; |
| if (fire_mask != 1) return "Incorrect fire mask 1"; |
| |
| time_value += 8; |
| qd_timer_visit(); |
| |
| if (fired < 1) return "Delayed Failed to fire"; |
| if (fire_mask != 3) return "Incorrect fire mask 3"; |
| |
| return 0; |
| } |
| |
| |
| static char* test_single(void *context) |
| { |
| fire_mask = fired = 0; |
| |
| qd_timer_schedule(timers[0], 2); |
| if (timeout != 2) return "Incorrect timeout"; |
| qd_timer_visit(); |
| if (fired > 0) return "Premature firing"; |
| time_value++; |
| qd_timer_visit(); |
| if (fired > 0) return "Premature firing 2"; |
| time_value++; |
| qd_timer_visit(); |
| if (fire_mask != 1) return "Incorrect fire mask"; |
| |
| fire_mask = fired = 0; |
| time_value++; |
| qd_timer_visit(); |
| time_value++; |
| qd_timer_visit(); |
| if (fired != 0) return "Spurious fires"; |
| |
| return 0; |
| } |
| |
| |
| static char* test_two_inorder(void *context) |
| { |
| fire_mask = fired = 0; |
| |
| qd_timer_schedule(timers[0], 2); |
| if (timeout != 2) return "bad timeout 2"; |
| qd_timer_schedule(timers[1], 4); |
| if (timeout != 2) return "bad timeout still 2"; |
| time_value += 2; |
| qd_timer_visit(); |
| |
| if (fire_mask & 2) return "Second fired prematurely"; |
| if (fire_mask != 1) return "Incorrect fire mask 1"; |
| |
| time_value += 2; |
| qd_timer_visit(); |
| |
| if (fire_mask != 3) return "Incorrect fire mask 3"; |
| |
| return 0; |
| } |
| |
| |
| static char* test_two_reverse(void *context) |
| { |
| fire_mask = fired = 0; |
| |
| qd_timer_schedule(timers[0], 4); |
| qd_timer_schedule(timers[1], 2); |
| time_value += 2; |
| qd_timer_visit(); |
| |
| if (fired < 1) return "First failed to fire"; |
| if (fired > 1) return "Second fired prematurely"; |
| if (fire_mask != 2) return "Incorrect fire mask 2"; |
| |
| time_value += 2; |
| qd_timer_visit(); |
| |
| if (fired < 1) return "Second failed to fire"; |
| if (fire_mask != 3) return "Incorrect fire mask 3"; |
| |
| return 0; |
| } |
| |
| |
| static char* test_two_duplicate(void *context) |
| { |
| fire_mask = fired = 0; |
| |
| qd_timer_schedule(timers[0], 2); |
| qd_timer_schedule(timers[1], 2); |
| time_value += 2; |
| qd_timer_visit(); |
| if (fired != 2) return "Expected two firings"; |
| if (fire_mask != 3) return "Incorrect fire mask 3"; |
| |
| fire_mask = fired = 0; |
| time_value += 2; |
| qd_timer_visit(); |
| if (fired > 0) return "Spurious timer fires"; |
| |
| return 0; |
| } |
| |
| |
| static char* test_separated(void *context) |
| { |
| fire_mask = fired = 0; |
| qd_timer_schedule(timers[0], 2); |
| qd_timer_schedule(timers[1], 4); |
| time_value += 2; |
| qd_timer_visit(); |
| |
| if (fired < 1) return "First failed to fire"; |
| if (fired > 1) return "Second fired prematurely"; |
| if (fire_mask != 1) return "Incorrect fire mask 1"; |
| |
| fired = 0; |
| qd_timer_schedule(timers[2], 2); |
| qd_timer_schedule(timers[3], 4); |
| time_value += 2; |
| qd_timer_visit(); |
| |
| if (fired < 1) return "Second failed to fire"; |
| if (fired < 2) return "Third failed to fire"; |
| if (fire_mask != 7) return "Incorrect fire mask 7"; |
| |
| fired = 0; |
| time_value += 2; |
| qd_timer_visit(); |
| if (fired < 1) return "Fourth failed to fire"; |
| if (fire_mask != 15) return "Incorrect fire mask 15"; |
| |
| return 0; |
| } |
| |
| |
| static char* test_big(void *context) |
| { |
| fire_mask = fired = 0; |
| long durations[16] = |
| { 5, 8, 7, 6, |
| 14, 10, 16, 15, |
| 11, 12, 9, 12, |
| 1, 2, 3, 4}; |
| unsigned long masks[18] = { |
| 0x1000, |
| 0x3000, |
| 0x7000, |
| 0xf000, |
| 0xf001, |
| 0xf009, |
| 0xf00d, |
| 0xf00f, |
| 0xf40f, |
| 0xf42f, |
| 0xf52f, |
| 0xff2f, |
| 0xff2f, |
| 0xff3f, |
| 0xffbf, |
| 0xffff, |
| 0xffff, |
| 0xffff |
| }; |
| |
| int i; |
| for (i = 0; i < 16; i++) |
| qd_timer_schedule(timers[i], durations[i]); |
| for (i = 0; i < 18; i++) { |
| ++time_value; |
| qd_timer_visit(); |
| if (fire_mask != masks[i]) { |
| static char error[100]; |
| sprintf(error, "Iteration %d: expected mask %04lx, got %04lx", i, masks[i], fire_mask); |
| return error; |
| } |
| } |
| |
| return 0; |
| } |
| |
| |
| int timer_tests() |
| { |
| char *test_group = "timer_tests"; |
| int result = 0; |
| fire_mask = fired = 0; |
| time_value = 1; |
| |
| timers[0] = qd_timer(0, on_timer, (void*) 0x00000001); |
| timers[1] = qd_timer(0, on_timer, (void*) 0x00000002); |
| timers[2] = qd_timer(0, on_timer, (void*) 0x00000004); |
| timers[3] = qd_timer(0, on_timer, (void*) 0x00000008); |
| timers[4] = qd_timer(0, on_timer, (void*) 0x00000010); |
| timers[5] = qd_timer(0, on_timer, (void*) 0x00000020); |
| timers[6] = qd_timer(0, on_timer, (void*) 0x00000040); |
| timers[7] = qd_timer(0, on_timer, (void*) 0x00000080); |
| timers[8] = qd_timer(0, on_timer, (void*) 0x00000100); |
| timers[9] = qd_timer(0, on_timer, (void*) 0x00000200); |
| timers[10] = qd_timer(0, on_timer, (void*) 0x00000400); |
| timers[11] = qd_timer(0, on_timer, (void*) 0x00000800); |
| timers[12] = qd_timer(0, on_timer, (void*) 0x00001000); |
| timers[13] = qd_timer(0, on_timer, (void*) 0x00002000); |
| timers[14] = qd_timer(0, on_timer, (void*) 0x00004000); |
| timers[15] = qd_timer(0, on_timer, (void*) 0x00008000); |
| |
| TEST_CASE(test_quiet, 0); |
| TEST_CASE(test_immediate, 0); |
| TEST_CASE(test_immediate_reschedule, 0); |
| TEST_CASE(test_immediate_plus_delayed, 0); |
| TEST_CASE(test_single, 0); |
| TEST_CASE(test_two_inorder, 0); |
| TEST_CASE(test_two_reverse, 0); |
| TEST_CASE(test_two_duplicate, 0); |
| TEST_CASE(test_separated, 0); |
| TEST_CASE(test_big, 0); |
| |
| int i; |
| for (i = 0; i < 16; i++) |
| qd_timer_free(timers[i]); |
| |
| return result; |
| } |