// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-
// Copyright (c) 2001-2007 International Computer Science Institute
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software")
// to deal in the Software without restriction, subject to the conditions
// listed in the XORP LICENSE file. These conditions include: you must
// preserve this copyright notice, and you cannot mention the copyright
// holders in advertising related to the Software without their permission.
// The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
// notice is a summary of the XORP LICENSE file; the license in that file is
// legally binding.
#ident "$XORP: xorp/libxorp/test_timer.cc,v 1.16 2007/02/16 22:46:26 pavlin Exp $"
//
// demo program to test timers and event loops (and show
// how to use them
//
#include <stdio.h>
#include "libxorp_module.h"
#include "libxorp/timer.hh"
#include "libxorp/eventloop.hh"
#include "libxorp/xlog.h"
int fired = 0 ;
// callback for non-periodic timer. Does not need to return a value
static void some_foo() {
fired++;
printf("O"); fflush(stdout);
}
// callback for a periodic timer. If true, the timer is rescheduled.
static bool print_dot() {
printf("."); fflush(stdout);
return true;
}
static void
test_many(EventLoop& e)
{
#define N 100
int i;
XorpTimer a[N];
fired = 0 ;
fprintf(stderr, "++ create a bunch of timers to fire in about 2s\n");
for (i=0; i<N ; i++) {
a[i] = e.new_oneoff_after_ms(2110+1*i, callback(some_foo));
}
fprintf(stderr, "++ move deadline of 1/3 of them by 5s\n");
for (i=0; i<N ; i += 3) {
a[i].reschedule_after(TimeVal(5, 0)) ;
}
fprintf(stderr, "++ create 100K timers which never fire because\n"
"they go out of scope and are automatically deleted\n");
for (i=0; i<100000 ; i++) {
XorpTimer b = e.new_oneoff_after_ms(2110+1*i, callback(some_foo));
}
fprintf(stderr, "++ wait for the two batches of events at 2 and 5s\n");
while (e.timers_pending()) {
fprintf(stdout, "-- fired %d\n", fired);
fflush(stdout);
e.run();
}
printf("\ndone with test_many\n"); fflush(stdout);
}
static void
print_tv(FILE * s, TimeVal a)
{
fprintf(s, "%lu.%06lu", (unsigned long)a.sec(), (unsigned long)a.usec());
fflush(s);
}
static void
test_wrap()
{
TimeVal a(INT_MAX, 999998);
TimeVal one_us(0, 1);
TimeVal b = a + one_us;
TimeVal c = b + one_us;
fprintf(stderr, "a is ");print_tv(stderr, a);fprintf(stderr, "\n");
fprintf(stderr, "b is ");print_tv(stderr, b);fprintf(stderr, "\n");
fprintf(stderr, "c is ");print_tv(stderr, c);fprintf(stderr, "\n");
fprintf(stderr, "a < b is %d\n", (int)(a < b));
fprintf(stderr, "b < c is %d\n", (int)(b < c));
}
class ZeroTimerTest {
public:
ZeroTimerTest(EventLoop& eventloop)
: _eventloop(eventloop),
_done(false) {}
void start() {
_zero_timer = _eventloop.new_oneoff_after(
TimeVal(0, 0),
callback(this, &ZeroTimerTest::zero_timer_cb));
}
bool done() const { return _done; }
void zero_timer_cb() {
_done = true;
_zero_timer = _eventloop.new_oneoff_after(
TimeVal(0, 0),
callback(this, &ZeroTimerTest::zero_timer_cb));
}
private:
EventLoop& _eventloop;
bool _done;
XorpTimer _zero_timer;
};
#ifdef SIGALRM
static void
alarm_signalhandler(int sig)
{
XLOG_ASSERT(sig == SIGALRM);
fprintf(stderr, "Test failed: alarm timeout\n");
exit(1);
}
#endif
//
// Test that recursively generating callbacks after time zero
// doesn't block the execution inside the internal timer loop forever.
//
static void
test_zero_timer(EventLoop& eventloop)
{
ZeroTimerTest zero_timer_test(eventloop);
fprintf(stderr, "Start ZeroTimer test\n");
#ifdef SIGALRM
signal(SIGALRM, alarm_signalhandler);
alarm(20);
#endif
zero_timer_test.start();
while (! zero_timer_test.done()) {
eventloop.run();
}
#ifdef SIGALRM
signal(SIGALRM, SIG_IGN);
#endif
fprintf(stderr, "End ZeroTimer test\n");
}
static void
run_test()
{
EventLoop e;
test_wrap();
XorpTimer show_stopper;
show_stopper = e.new_oneoff_after_ms(500, callback(some_foo));
assert(show_stopper.scheduled());
XorpTimer zzz = e.new_periodic_ms(3, callback(print_dot));
assert(zzz.scheduled());
while(show_stopper.scheduled()) {
assert(zzz.scheduled());
e.run(); // run will return after one or more pending events
// have fired.
}
zzz.unschedule();
test_many(e);
test_zero_timer(e);
}
int main(int /* argc */, const char* argv[])
{
//
// Initialize and start xlog
//
xlog_init(argv[0], NULL);
xlog_set_verbose(XLOG_VERBOSE_LOW); // Least verbose messages
// XXX: verbosity of the error messages temporary increased
xlog_level_set_verbose(XLOG_LEVEL_ERROR, XLOG_VERBOSE_HIGH);
xlog_add_default_output();
xlog_start();
run_test();
//
// Gracefully stop and exit xlog
//
xlog_stop();
xlog_exit();
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1