blob: 409cba3da5ab17efc5db4e418ba3135dabdbebeb [file] [log] [blame]
/*
* 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 <qpid/dispatch/timer.h>
#include "dispatch_private.h"
#include "alloc.h"
#include "timer_private.h"
#include "test_case.h"
#include <qpid/dispatch/threading.h>
static unsigned long fire_mask;
static qd_timer_list_t pending_timers;
static sys_mutex_t *lock;
static long time;
static qd_timer_t *timers[16];
void qd_server_timer_pending_LH(qd_timer_t *timer)
{
DEQ_INSERT_TAIL(pending_timers, timer);
}
void qd_server_timer_cancel_LH(qd_timer_t *timer)
{
if (timer->state == TIMER_PENDING)
DEQ_REMOVE(pending_timers, timer);
}
static int fire_head()
{
sys_mutex_lock(lock);
int result = DEQ_SIZE(pending_timers);
qd_timer_t *timer = DEQ_HEAD(pending_timers);
if (timer) {
DEQ_REMOVE_HEAD(pending_timers);
qd_timer_idle_LH(timer);
fire_mask |= (unsigned long) timer->context;
}
sys_mutex_unlock(lock);
return result;
}
static char* test_quiet(void *context)
{
fire_mask = 0;
sys_mutex_lock(lock);
qd_timer_visit_LH(time++);
qd_timer_visit_LH(time++);
qd_timer_visit_LH(time++);
qd_timer_visit_LH(time++);
qd_timer_visit_LH(time++);
sys_mutex_unlock(lock);
while(fire_head());
if (fire_mask != 0)
return "Expected zero timers fired";
return 0;
}
static char* test_immediate(void *context)
{
while(fire_head());
fire_mask = 0;
qd_timer_schedule(timers[0], 0);
if (fire_mask != 0) return "Premature firing";
if (fire_head() > 1) return "Too many firings";
if (fire_mask != 1) return "Incorrect fire mask";
return 0;
}
static char* test_immediate_reschedule(void *context)
{
while(fire_head());
fire_mask = 0;
qd_timer_schedule(timers[0], 0);
qd_timer_schedule(timers[0], 0);
if (fire_mask != 0) return "pass 1 - Premature firing";
if (fire_head() > 1) return "pass 1 - Too many firings";
if (fire_mask != 1) return "pass 1 - Incorrect fire mask";
fire_mask = 0;
qd_timer_schedule(timers[0], 0);
qd_timer_schedule(timers[0], 0);
if (fire_mask != 0) return "pass 2 - Premature firing";
if (fire_head() > 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)
{
while(fire_head());
fire_mask = 0;
qd_timer_schedule(timers[0], 0);
qd_timer_schedule(timers[1], 5);
if (fire_mask != 0) return "Premature firing";
if (fire_head() > 1) return "Too many firings";
if (fire_mask != 1) return "Incorrect fire mask 1";
sys_mutex_lock(lock);
qd_timer_visit_LH(time++);
time += 8;
qd_timer_visit_LH(time++);
sys_mutex_unlock(lock);
if (fire_head() < 1) return "Delayed Failed to fire";
if (fire_mask != 3) return "Incorrect fire mask 3";
return 0;
}
static char* test_single(void *context)
{
while(fire_head());
fire_mask = 0;
qd_timer_schedule(timers[0], 2);
if (fire_head() > 0) return "Premature firing 1";
sys_mutex_lock(lock);
qd_timer_visit_LH(time++);
sys_mutex_unlock(lock);
if (fire_head() > 0) return "Premature firing 2";
sys_mutex_lock(lock);
qd_timer_visit_LH(time++);
sys_mutex_unlock(lock);
if (fire_head() < 1) return "Failed to fire";
sys_mutex_lock(lock);
qd_timer_visit_LH(time++);
qd_timer_visit_LH(time++);
qd_timer_visit_LH(time++);
sys_mutex_unlock(lock);
if (fire_head() != 0) return "Spurious fires";
if (fire_mask != 1) return "Incorrect fire mask";
if (timers[0]->state != TIMER_IDLE) return "Expected idle timer state";
return 0;
}
static char* test_two_inorder(void *context)
{
while(fire_head());
fire_mask = 0;
qd_timer_schedule(timers[0], 2);
qd_timer_schedule(timers[1], 4);
sys_mutex_lock(lock);
qd_timer_visit_LH(time++);
qd_timer_visit_LH(time++);
sys_mutex_unlock(lock);
int count = fire_head();
if (count < 1) return "First failed to fire";
if (count > 1) return "Second fired prematurely";
if (fire_mask != 1) return "Incorrect fire mask 1";
sys_mutex_lock(lock);
qd_timer_visit_LH(time++);
qd_timer_visit_LH(time++);
sys_mutex_unlock(lock);
if (fire_head() < 1) return "Second failed to fire";
if (fire_mask != 3) return "Incorrect fire mask 3";
return 0;
}
static char* test_two_reverse(void *context)
{
while(fire_head());
fire_mask = 0;
qd_timer_schedule(timers[0], 4);
qd_timer_schedule(timers[1], 2);
sys_mutex_lock(lock);
qd_timer_visit_LH(time++);
qd_timer_visit_LH(time++);
sys_mutex_unlock(lock);
int count = fire_head();
if (count < 1) return "First failed to fire";
if (count > 1) return "Second fired prematurely";
if (fire_mask != 2) return "Incorrect fire mask 2";
sys_mutex_lock(lock);
qd_timer_visit_LH(time++);
qd_timer_visit_LH(time++);
sys_mutex_unlock(lock);
if (fire_head() < 1) return "Second failed to fire";
if (fire_mask != 3) return "Incorrect fire mask 3";
return 0;
}
static char* test_two_duplicate(void *context)
{
while(fire_head());
fire_mask = 0;
qd_timer_schedule(timers[0], 2);
qd_timer_schedule(timers[1], 2);
sys_mutex_lock(lock);
qd_timer_visit_LH(time++);
qd_timer_visit_LH(time++);
sys_mutex_unlock(lock);
int count = fire_head();
if (count != 2) return "Expected two firings";
fire_head();
if (fire_mask != 3) return "Incorrect fire mask 3";
sys_mutex_lock(lock);
qd_timer_visit_LH(time++);
qd_timer_visit_LH(time++);
sys_mutex_unlock(lock);
if (fire_head() > 0) return "Spurious timer fires";
return 0;
}
static char* test_separated(void *context)
{
int count;
while(fire_head());
fire_mask = 0;
qd_timer_schedule(timers[0], 2);
qd_timer_schedule(timers[1], 4);
sys_mutex_lock(lock);
qd_timer_visit_LH(time++);
qd_timer_visit_LH(time++);
sys_mutex_unlock(lock);
count = fire_head();
if (count < 1) return "First failed to fire";
if (count > 1) return "Second fired prematurely";
if (fire_mask != 1) return "Incorrect fire mask 1";
qd_timer_schedule(timers[2], 2);
qd_timer_schedule(timers[3], 4);
sys_mutex_lock(lock);
qd_timer_visit_LH(time++);
qd_timer_visit_LH(time++);
sys_mutex_unlock(lock);
count = fire_head();
fire_head();
if (count < 1) return "Second failed to fire";
if (count < 2) return "Third failed to fire";
if (fire_mask != 7) return "Incorrect fire mask 7";
sys_mutex_lock(lock);
qd_timer_visit_LH(time++);
qd_timer_visit_LH(time++);
sys_mutex_unlock(lock);
count = fire_head();
if (count < 1) return "Fourth failed to fire";
if (fire_mask != 15) return "Incorrect fire mask 15";
sys_mutex_lock(lock);
qd_timer_visit_LH(time++);
qd_timer_visit_LH(time++);
qd_timer_visit_LH(time++);
qd_timer_visit_LH(time++);
qd_timer_visit_LH(time++);
qd_timer_visit_LH(time++);
sys_mutex_unlock(lock);
count = fire_head();
if (count > 0) return "Spurious fire";
return 0;
}
static char* test_big(void *context)
{
while(fire_head());
fire_mask = 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++) {
sys_mutex_lock(lock);
qd_timer_visit_LH(time++);
sys_mutex_unlock(lock);
while(fire_head());
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(void)
{
int result = 0;
fire_mask = 0;
DEQ_INIT(pending_timers);
lock = qd_timer_lock();
time = 1;
timers[0] = qd_timer(0, 0, (void*) 0x00000001);
timers[1] = qd_timer(0, 0, (void*) 0x00000002);
timers[2] = qd_timer(0, 0, (void*) 0x00000004);
timers[3] = qd_timer(0, 0, (void*) 0x00000008);
timers[4] = qd_timer(0, 0, (void*) 0x00000010);
timers[5] = qd_timer(0, 0, (void*) 0x00000020);
timers[6] = qd_timer(0, 0, (void*) 0x00000040);
timers[7] = qd_timer(0, 0, (void*) 0x00000080);
timers[8] = qd_timer(0, 0, (void*) 0x00000100);
timers[9] = qd_timer(0, 0, (void*) 0x00000200);
timers[10] = qd_timer(0, 0, (void*) 0x00000400);
timers[11] = qd_timer(0, 0, (void*) 0x00000800);
timers[12] = qd_timer(0, 0, (void*) 0x00001000);
timers[13] = qd_timer(0, 0, (void*) 0x00002000);
timers[14] = qd_timer(0, 0, (void*) 0x00004000);
timers[15] = qd_timer(0, 0, (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;
}