// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-
// vim:set sts=4 ts=8:
// 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/eventloop.cc,v 1.22 2007/03/08 00:03:55 atanu Exp $"
#include "libxorp_module.h"
#include "libxorp/xorp.h"
#include "libxorp/xlog.h"
#include "libxorp/debug.h"
#include "eventloop.hh"
//
// Number of EventLoop instances.
// XXX: Warning: static instance. Not suitable for shared library use.
//
static int instance_count = 0;
//
// Last call to EventLoop::run. 0 is a special value that indicates
// EventLoop::run has not been called.
//
// XXX: Warning: static instance. Not suitable for shared library use.
//
static time_t last_ev_run;
EventLoop::EventLoop()
: _clock(new SystemClock), _timer_list(_clock),
#ifdef HOST_OS_WINDOWS
_win_dispatcher(_clock)
#else
_selector_list(_clock)
#endif
{
instance_count++;
XLOG_ASSERT(instance_count == 1);
last_ev_run = 0;
}
EventLoop::~EventLoop()
{
instance_count--;
XLOG_ASSERT(instance_count == 0);
delete _clock;
}
void
EventLoop::run()
{
const time_t MAX_ALLOWED = 2;
static time_t last_warned;
if (last_ev_run == 0)
last_ev_run = time(0);
time_t now = time(0);
time_t diff = now - last_ev_run;
if (now - last_warned > 0 && (diff > MAX_ALLOWED)) {
XLOG_WARNING("%d seconds between calls to EventLoop::run", (int)diff);
last_warned = now;
}
TimeVal t;
_timer_list.advance_time();
_timer_list.get_next_delay(t);
int timer_priority = XorpTask::PRIORITY_INFINITY;
int selector_priority = XorpTask::PRIORITY_INFINITY;
int task_priority = XorpTask::PRIORITY_INFINITY;
if (t == TimeVal::ZERO()) {
timer_priority = _timer_list.get_expired_priority();
}
#ifdef HOST_OS_WINDOWS
if (_win_dispatcher.ready())
selector_priority = _win_dispatcher.get_ready_priority();
#else
if (_selector_list.ready()) {
selector_priority = _selector_list.get_ready_priority();
}
#endif
if (!_task_list.empty()) {
task_priority = _task_list.get_runnable_priority();
}
debug_msg("Priorities: timer = %d selector = %d task = %d\n",
timer_priority, selector_priority, task_priority);
if ( (timer_priority != XorpTask::PRIORITY_INFINITY)
&& (timer_priority <= selector_priority)
&& (timer_priority <= task_priority)) {
// the most important thing to run next is a timer
_timer_list.run();
} else if ( (selector_priority != XorpTask::PRIORITY_INFINITY)
&& (selector_priority <= task_priority) ) {
// the most important thing to run next is a selector
#ifdef HOST_OS_WINDOWS
_win_dispatcher.wait_and_dispatch(&t);
#else
_selector_list.wait_and_dispatch(&t);
#endif
} else if (task_priority != XorpTask::PRIORITY_INFINITY) {
// the most important thing to run next is a task
_task_list.run();
} else {
// there's nothing immediate to run, so go to sleep until the
// next selector or timer goes off
#ifdef HOST_OS_WINDOWS
_win_dispatcher.wait_and_dispatch(&t);
#else
_selector_list.wait_and_dispatch(&t);
#endif
}
last_ev_run = time(0);
}
bool
EventLoop::add_ioevent_cb(XorpFd fd, IoEventType type, const IoEventCb& cb,
int priority)
{
#ifdef HOST_OS_WINDOWS
return _win_dispatcher.add_ioevent_cb(fd, type, cb, priority);
#else
return _selector_list.add_ioevent_cb(fd, type, cb, priority);
#endif
}
bool
EventLoop::remove_ioevent_cb(XorpFd fd, IoEventType type)
{
#ifdef HOST_OS_WINDOWS
return _win_dispatcher.remove_ioevent_cb(fd, type);
#else
_selector_list.remove_ioevent_cb(fd, type);
return true;
#endif
}
size_t
EventLoop::descriptor_count() const
{
#ifdef HOST_OS_WINDOWS
return _win_dispatcher.descriptor_count();
#else
return _selector_list.descriptor_count();
#endif
}
XorpTask
EventLoop::new_oneoff_task(const OneoffTaskCallback& cb, int priority,
int weight)
{
return _task_list.new_oneoff_task(cb, priority, weight);
}
XorpTask
EventLoop::new_task(const RepeatedTaskCallback& cb, int priority, int weight)
{
return _task_list.new_task(cb, priority, weight);
}
syntax highlighted by Code2HTML, v. 0.9.1