// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-
// Copyright (c) 2006-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/task.cc,v 1.7 2007/02/16 22:46:23 pavlin Exp $"
#include "libxorp_module.h"
#include "xorp.h"
#include "xlog.h"
#include "task.hh"
// ----------------------------------------------------------------------------
// TaskNode methods
TaskNode::TaskNode(TaskList* task_list, BasicTaskCallback cb)
: _task_list(task_list), _cb(cb), _ref_cnt(0), _priority(0), _weight(0)
{
debug_msg("TaskNode constructor %p\n", this);
}
TaskNode::~TaskNode()
{
debug_msg("TaskNode destructor %p\n", this);
unschedule();
}
void
TaskNode::add_ref()
{
_ref_cnt++;
debug_msg("add_ref on %p, now ref_cnt = %d\n", this, _ref_cnt);
}
void
TaskNode::release_ref()
{
if (--_ref_cnt <= 0)
delete this;
}
void
TaskNode::schedule(int priority, int weight)
{
debug_msg("TaskNode schedule %p p = %d, w = %d\n", this, priority, weight);
XLOG_ASSERT(_task_list != NULL);
unschedule();
_priority = priority;
_weight = weight;
_task_list->schedule_node(this);
}
void
TaskNode::reschedule()
{
XLOG_ASSERT(_task_list != NULL);
unschedule();
_task_list->schedule_node(this);
}
void
TaskNode::unschedule()
{
if (scheduled())
_task_list->unschedule_node(this);
}
// ----------------------------------------------------------------------------
// Specialized Tasks. These are what the XorpTask objects returned by
// the TaskList XorpTask creation methods (e.g. TaskList::new_oneoff_at(), etc)
// actually refer to.
class OneoffTaskNode2 : public TaskNode {
public:
OneoffTaskNode2(TaskList* task_list, const OneoffTaskCallback& cb)
: TaskNode(task_list, callback(this, &OneoffTaskNode2::run)),
_cb(cb) {}
private:
void run(XorpTask& xorp_task) {
debug_msg("OneoffTaskNode2::run() %p\n", this);
//
// XXX: we have to unschedule before the callback dispatch, in case
// the callback decides to schedules again the task.
//
xorp_task.unschedule();
_cb->dispatch();
}
OneoffTaskCallback _cb;
};
class RepeatedTaskNode2 : public TaskNode {
public:
RepeatedTaskNode2(TaskList* task_list, const RepeatedTaskCallback& cb)
: TaskNode(task_list, callback(this, &RepeatedTaskNode2::run)),
_cb(cb) {}
private:
void run(XorpTask& xorp_task) {
if (! _cb->dispatch()) {
xorp_task.unschedule();
}
}
RepeatedTaskCallback _cb;
};
// ----------------------------------------------------------------------------
// XorpTask
void
XorpTask::unschedule()
{
if (_task_node != NULL)
_task_node->unschedule();
}
bool
XorpTask::scheduled() const
{
if (_task_node != NULL)
return _task_node->scheduled();
else
return false;
}
// ----------------------------------------------------------------------------
// TaskList
XorpTask
TaskList::new_oneoff_task(const OneoffTaskCallback& cb,
int priority, int weight)
{
debug_msg("new oneoff task %p p = %d, w = %d\n", this, priority, weight);
TaskNode* task_node = new OneoffTaskNode2(this, cb);
task_node->schedule(priority, weight);
return XorpTask(task_node);
}
XorpTask
TaskList::new_task(const RepeatedTaskCallback& cb,
int priority, int weight)
{
debug_msg("new task %p p = %d, w = %d\n", this, priority, weight);
TaskNode* task_node = new RepeatedTaskNode2(this, cb);
task_node->schedule(priority, weight);
return XorpTask(task_node);
}
int
TaskList::get_runnable_priority() const
{
map<int, RoundRobinQueue*>::const_iterator rri;
for (rri = _rr_list.begin(); rri != _rr_list.end(); ++rri) {
if (rri->second->size() != 0) {
return rri->first;
}
}
return XorpTask::PRIORITY_INFINITY;
}
bool
TaskList::empty() const
{
bool result = true;
map<int, RoundRobinQueue*>::const_iterator rri;
for (rri = _rr_list.begin(); rri != _rr_list.end(); ++rri) {
if (rri->second->size() != 0) {
result = false;
break;
}
}
return result;
}
void
TaskList::run()
{
map<int, RoundRobinQueue*>::const_iterator rri;
debug_msg("TaskList run()\n");
for (rri = _rr_list.begin(); rri != _rr_list.end(); ++rri) {
RoundRobinQueue* rr = rri->second;
if (rr->size() != 0) {
TaskNode* task_node = static_cast<TaskNode*>(rr->get_next_entry());
debug_msg("node to run: %p\n", task_node);
XorpTask xorp_task(task_node);
task_node->run(xorp_task);
return;
}
}
}
RoundRobinQueue*
TaskList::find_round_robin(int priority)
{
map<int, RoundRobinQueue*>::iterator rri = _rr_list.find(priority);
if (rri == _rr_list.end()) {
RoundRobinQueue* rr = new RoundRobinQueue();
_rr_list[priority] = rr;
return rr;
} else {
return rri->second;
}
}
void
TaskList::schedule_node(TaskNode* task_node)
{
debug_msg("TaskList::schedule_node: n = %p\n", task_node);
RoundRobinObjBase* obj = static_cast<RoundRobinObjBase*>(task_node);
RoundRobinQueue* rr = find_round_robin(task_node->priority());
rr->push(obj, task_node->weight());
}
void
TaskList::unschedule_node(TaskNode* task_node)
{
debug_msg("TaskList::unschedule_node: n = %p\n", task_node);
RoundRobinObjBase* obj = static_cast<RoundRobinObjBase*>(task_node);
RoundRobinQueue* rr = find_round_robin(task_node->priority());
rr->pop_obj(obj);
}
syntax highlighted by Code2HTML, v. 0.9.1