1
0
Files
irix-657m-src/eoe/cmd/mediad/Task.C
2022-09-29 17:59:04 +03:00

198 lines
3.6 KiB
C

#include "Task.H"
#include <assert.h>
#include "operators.H"
//////////////////////////////////////////////////////////////////////////////
// Timeval operators.
timeval&
operator += (timeval& left, const timeval& right)
{
left.tv_sec += right.tv_sec;
left.tv_usec += right.tv_usec;
while (left.tv_usec >= 1000000)
{ left.tv_usec -= 1000000;
left.tv_sec += 1;
}
return left;
}
timeval&
operator -= (timeval& left, const timeval& right)
{
left.tv_sec -= right.tv_sec;
left.tv_usec -= right.tv_usec;
while (left.tv_usec < 0)
{ left.tv_usec += 1000000;
left.tv_sec -= 1;
}
return left;
}
inline bool
operator < (const timeval& left, const timeval& right)
{
return timercmp(&left, &right, < );
}
inline bool
operator > (const timeval& left, const timeval& right)
{
return timercmp(&left, &right, > );
}
inline bool
operator == (const timeval& left, const timeval& right)
{
return timercmp(&left, &right, == );
}
inline bool
operator != (const timeval& left, const timeval& right)
{
return timercmp(&left, &right, != );
}
//////////////////////////////////////////////////////////////////////////////
const timeval Task::ASAP = { 0, 0 };
const timeval Task::Once = { 0, 0 };
timeval Task::now;
Task *Task::queue;
Task::Task(TaskProc proc, void *closure)
: _next(NULL), _prev(NULL), _proc(proc), _closure(closure)
{
_when.tv_sec = _when.tv_usec = 0;
_interval.tv_sec = _interval.tv_usec = 0;
}
Task::~Task()
{
if (scheduled())
cancel();
}
void
Task::schedule(const timeval& when, const timeval& interval)
{
if (scheduled())
cancel();
_when = when;
if (when != ASAP)
{ (void) gettimeofday(&now, NULL);
_when += now;
}
_interval = interval;
enqueue();
}
void
Task::cancel()
{
// assert(scheduled());
if (scheduled())
dequeue();
}
void
Task::run_now()
{
// Dequeue first; reschedule last in case task wants to change its
// reenqueue itself or change its scheduling.
assert(queue == this); // Only run 1st task in queue.
dequeue();
// Run it.
(*_proc)(*this, _closure);
// Reschedule it, if appropriate.
if (!scheduled() && _interval != Once)
{ if (_when == ASAP)
{ (void) gettimeofday(&now, NULL);
_when = now;
}
_when += _interval;
enqueue();
}
}
void
Task::enqueue()
{
Task *prev, *next;
for (next = queue, prev = NULL; next; prev = next, next = next->_next)
if (next->_when > _when)
break;
_next = next;
_prev = prev;
if (next)
next->_prev = this;
if (prev)
prev->_next = this;
else
queue = this;
assert(scheduled());
}
void
Task::dequeue()
{
if (_prev)
_prev->_next = _next;
else
queue = _next;
if (_next)
_next->_prev = _prev;
_next = _prev = NULL;
assert(!scheduled());
}
//////////////////////////////////////////////////////////////////////////////
// static functions
// calc_timeout calculates the timeout to pass to select().
// It returns:
// NULL (if no timed tasks exist)
// zero time (if it's time for the next task)
// nonzero time (if it's not time yet)
timeval *
Task::calc_timeout()
{
static timeval sleep_interval;
if (!queue)
return NULL;
if (queue->_when == ASAP)
timerclear(&sleep_interval);
else
{ (void) gettimeofday(&now, NULL);
sleep_interval = queue->_when - now;
if (sleep_interval.tv_sec < 0)
timerclear(&sleep_interval);
}
return &sleep_interval;
}
void
Task::run_tasks()
{
while (queue)
{ if (queue->_when == ASAP || queue->_when < now)
queue->run_now();
else
{ (void) gettimeofday(&now, NULL);
if (queue->_when > now)
break;
}
}
}