// -*- 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_observers.cc,v 1.11 2007/02/16 22:46:25 pavlin Exp $"
//
// Test program to the Observer classes for TimerList and SelectorList
//
#include "libxorp_module.h"
#include "libxorp/xorp.h"
#include "libxorp/xlog.h"
#include "libxorp/xorpfd.hh"
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include "timer.hh"
#include "eventloop.hh"
#ifndef HOST_OS_WINDOWS
static int fired(0);
static int add_rem_fd_counter(0);
static int add_rem_mask_counter(0);
static bool fd_read_notification_called = false;
static bool fd_write_notification_called = false;
static bool fd_exeption_notification_called = false;
static bool fd_removal_notification_called = false;
static bool schedule_notification_called = false;
static bool unschedule_notification_called = false;
static bool one_fd_rem_per_each_fd_add_notif = false;
static bool no_notifications_beyond_this_point = false;
void
print_tv(FILE * s, TimeVal a)
{
fprintf(s, "%lu.%06lu", (unsigned long)a.sec(), (unsigned long)a.usec());
fflush(s);
}
// callback for non-periodic timer. Does not need to return a value
static void some_foo() {
fired++;
printf("#"); fflush(stdout);
}
// callback for a periodic timer. If true, the timer is rescheduled.
static bool print_dot() {
printf("."); fflush(stdout);
return true;
}
// callback for selector.
static void do_the_twist(XorpFd fd, IoEventType event) {
printf("fd: %s event: %0x is here\n", fd.str().c_str(), event);
}
// Implement the SelectorList observer and notification functions
class mySelectorListObserver : public SelectorListObserverBase {
void notify_added(XorpFd, const SelectorMask&);
void notify_removed(XorpFd, const SelectorMask&);
};
void
mySelectorListObserver::notify_added(XorpFd fd, const SelectorMask& mask)
{
fprintf(stderr, "notif added fd: %s mask: %#0x\n", fd.str().c_str(), mask);
add_rem_fd_counter+=fd;
add_rem_mask_counter+=mask;
switch (mask) {
case SEL_RD: fd_read_notification_called = true; break;
case SEL_WR: fd_write_notification_called = true; break;
case SEL_EX: fd_exeption_notification_called = true; break;
default: fprintf(stderr, "invalid mask notification\n"); exit(1);
}
}
void
mySelectorListObserver::notify_removed(XorpFd fd, const SelectorMask& mask)
{
fprintf(stderr, "notif removed fd: %s mask: %#0x\n", fd.str().c_str(),
mask);
add_rem_fd_counter-=fd;
add_rem_mask_counter-=mask;
if (no_notifications_beyond_this_point) {
fprintf(stderr, "duplicate removal!!\n");
exit(1);
}
fd_removal_notification_called = true;
}
// Implement TimerList observer and notification functions
class myTimerListObserver : public TimerListObserverBase {
void notify_scheduled(const TimeVal&);
void notify_unscheduled(const TimeVal&);
};
void myTimerListObserver::notify_scheduled(const TimeVal& tv)
{
fprintf(stderr, "notif sched ");print_tv(stderr, tv);fprintf(stderr, "\n");
schedule_notification_called = true;
}
void myTimerListObserver::notify_unscheduled(const TimeVal& tv)
{
fprintf(stderr, "notif unsch "); print_tv(stderr, tv);fprintf(stderr, "\n");
unschedule_notification_called = true;
}
void run_test()
{
EventLoop e;
mySelectorListObserver sel_obs;
myTimerListObserver timer_obs;
e.selector_list().set_observer(sel_obs);
e.timer_list().set_observer(timer_obs);
XorpTimer show_stopper;
show_stopper = e.new_oneoff_after_ms(500, callback(some_foo));
assert(show_stopper.scheduled());
XorpTimer zzz = e.new_periodic_ms(30, callback(print_dot));
assert(zzz.scheduled());
XorpFd fd[2];
int pipefds[2];
#ifndef HOST_OS_WINDOWS
if (pipe(pipefds)) {
fprintf(stderr, "unable to generate file descriptors for test\n");
exit(2);
}
fd[0] = XorpFd(pipefds[0]);
fd[1] = XorpFd(pipefds[1]);
#else // HOST_OS_WINDOWS
if (_pipe(pipefds, 65536, _O_BINARY)) {
fprintf(stderr, "unable to generate file descriptors for test\n");
exit(2);
}
fd[0] = XorpFd(_get_osfhandle(pipefds[0]));
fd[1] = XorpFd(_get_osfhandle(pipefds[1]));
#endif // HOST_OS_WINDOWS
XorpCallback2<void,XorpFd,IoEventType>::RefPtr cb = callback(do_the_twist);
e.selector_list().add_ioevent_cb(fd[0], IOT_READ, cb);
e.selector_list().add_ioevent_cb(fd[1], IOT_WRITE, cb);
e.selector_list().add_ioevent_cb(fd[0], IOT_EXCEPTION, cb);
while(show_stopper.scheduled()) {
assert(zzz.scheduled());
e.run(); // run will return after one or more pending events
// have fired.
e.selector_list().remove_ioevent_cb(fd[0], IOT_READ);
e.selector_list().remove_ioevent_cb(fd[1], IOT_WRITE);
e.selector_list().remove_ioevent_cb(fd[0], IOT_EXCEPTION);
}
zzz.unschedule();
// these should not raise notifications since they have already been removed
no_notifications_beyond_this_point = true;
e.selector_list().remove_ioevent_cb(fd[0], IOT_READ);
e.selector_list().remove_ioevent_cb(fd[1], IOT_WRITE);
#ifndef HOST_OS_WINDOWS
close(fd[0]);
close(fd[1]);
#else
_close(fd[0]);
_close(fd[1]);
#endif
one_fd_rem_per_each_fd_add_notif = (add_rem_fd_counter == 0) &&
(add_rem_mask_counter == 0);
if (!one_fd_rem_per_each_fd_add_notif) {
fprintf(stderr, "cumulative fd and mask should both be 0 but are ");
fprintf(stderr, "fd: %d mask: %d\n", add_rem_fd_counter,
add_rem_mask_counter);
exit(1);
}
if (!(fd_read_notification_called && fd_write_notification_called &&
fd_exeption_notification_called && fd_removal_notification_called &&
schedule_notification_called && unschedule_notification_called)) {
fprintf(stderr, "Some notifications not called correctly\n");
exit(1);
}
fprintf(stderr, "Test passed\n");
}
#endif // !HOST_OS_WINDOWS
int main(int /* argc */, const char* argv[])
{
// TODO: enable the test for Windows
#ifndef HOST_OS_WINDOWS
//
// 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();
fprintf(stderr, "------------------------------------------------------\n");
run_test();
fprintf(stderr, "------------------------------------------------------\n");
//
// Gracefully stop and exit xlog
//
xlog_stop();
xlog_exit();
#else // HOST_OS_WINDOWS
UNUSED(argv);
#endif // HOST_OS_WINDOWS
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1