#include <sys/types.h>
#include <sys/time.h>
#include <sys/vuid_event.h>
#include <sys/vuid_queue.h>
static Vuid_q_node *vq_alloc_node(Vuid_queue *vq);
static void vq_free_node(Vuid_queue *vq, Vuid_q_node *vqn);
static int tv_equal(struct timeval32 a, struct timeval32 b);
static struct timeval32 tv_subt(struct timeval32 atv, struct timeval32 btv);
static struct timeval32 tv_divide(struct timeval32 tv, int dividend);
static struct timeval32 tv_mult(struct timeval32 tv, int multiplier);
#define tv_to_usec(tv) (((tv).tv_sec * 1000000) + (tv).tv_usec)
static struct timeval32 usec_to_tv(int usec);
void
vq_initialize(Vuid_queue *vq, caddr_t data, u_int bytes)
{
Vuid_q_node *new_vqns, *vqn;
vq->top = vq->bottom = vq->free = VUID_Q_NODE_NULL;
vq->size = 1 + (bytes - sizeof (Vuid_q_node)) / sizeof (Vuid_q_node);
new_vqns = (Vuid_q_node *)data;
vq->num = vq->size;
for (vqn = new_vqns; vqn < new_vqns + vq->size; vqn++)
vq_free_node(vq, vqn);
}
Vuid_q_code
vq_put(Vuid_queue *vq, Firm_event *firm_event)
{
Vuid_q_node *vp;
for (vp = vq->bottom; vp; vp = vp->prev) {
if (timercmp(&vp->firm_event.time, &firm_event->time,
< ) ||
tv_equal(vp->firm_event.time, firm_event->time)) {
Vuid_q_node *vqn = vq_alloc_node(vq);
if (vqn == VUID_Q_NODE_NULL)
return (VUID_Q_OVERFLOW);
vqn->firm_event = *firm_event;
vqn->next = vp->next;
vqn->prev = vp;
if (vp->next != VUID_Q_NODE_NULL)
vp->next->prev = vqn;
vp->next = vqn;
if (vp == vq->bottom)
vq->bottom = vqn;
if (vq->top == VUID_Q_NODE_NULL)
vq->top = vqn;
return (VUID_Q_OK);
}
}
return (vq_putback(vq, firm_event));
}
Vuid_q_code
vq_get(Vuid_queue *vq, Firm_event *firm_event)
{
Vuid_q_node *vqn = vq->top;
if (vqn == VUID_Q_NODE_NULL)
return (VUID_Q_EMPTY);
if (firm_event != FIRM_EVENT_NULL)
*firm_event = vqn->firm_event;
vq->top = vqn->next;
if (vq->top != VUID_Q_NODE_NULL)
vq->top->prev = VUID_Q_NODE_NULL;
if (vq->bottom == vqn)
vq->bottom = VUID_Q_NODE_NULL;
vq_free_node(vq, vqn);
return (VUID_Q_OK);
}
Vuid_q_code
vq_peek(Vuid_queue *vq, Firm_event *firm_event)
{
if (vq->top == VUID_Q_NODE_NULL)
return (VUID_Q_EMPTY);
*firm_event = vq->top->firm_event;
return (VUID_Q_OK);
}
Vuid_q_code
vq_putback(Vuid_queue *vq, Firm_event *firm_event)
{
Vuid_q_node *vqn = vq_alloc_node(vq);
if (vqn == VUID_Q_NODE_NULL)
return (VUID_Q_OVERFLOW);
vqn->firm_event = *firm_event;
vqn->next = vq->top;
vqn->prev = VUID_Q_NODE_NULL;
if (vq->top != VUID_Q_NODE_NULL)
vq->top->prev = vqn;
vq->top = vqn;
if (vq->bottom == VUID_Q_NODE_NULL)
vq->bottom = vqn;
return (VUID_Q_OK);
}
int
vq_compress(Vuid_queue *vq, int factor)
{
struct timeval32 tv_interval, tv_avg_diff, tv_diff;
struct timeval32 tv_threshold;
Vuid_q_node *base, *victim;
Vuid_q_node *victim_next;
int num_start;
if (vq->top == VUID_Q_NODE_NULL)
return (0);
num_start = vq->num;
tv_interval = tv_subt(vq->bottom->firm_event.time,
vq->top->firm_event.time);
tv_avg_diff = tv_divide(tv_interval, vq->num);
tv_threshold = tv_mult(tv_avg_diff, factor);
for (base = vq->top; base; base = base->next) {
if (!vq_is_valuator(base))
continue;
for (victim = base->next; victim; victim = victim_next) {
victim_next = victim->next;
if (!vq_is_valuator(victim))
goto Advance_Base;
if (victim->prev != base) {
if (!tv_equal(victim->prev->firm_event.time,
victim->firm_event.time))
goto Advance_Base;
}
tv_diff = tv_subt(victim->firm_event.time,
base->firm_event.time);
if ((factor > 0) &&
(timercmp(&tv_diff, &tv_threshold, > )))
goto Advance_Base;
if (victim->firm_event.id == base->firm_event.id) {
switch (base->firm_event.pair_type) {
case FE_PAIR_ABSOLUTE:
base->firm_event.value +=
victim->firm_event.value;
break;
case FE_PAIR_DELTA:
default:
base->firm_event.value =
victim->firm_event.value;
break;
}
vq_delete_node(vq, victim);
}
}
Advance_Base:
{}
}
return (num_start - vq->num);
}
int
vq_is_valuator(Vuid_q_node *vqn)
{
return ((vqn->firm_event.value < 1 && vqn->firm_event.value > -1) ||
(vqn->firm_event.pair_type == FE_PAIR_DELTA) ||
(vqn->firm_event.pair_type == FE_PAIR_ABSOLUTE));
}
void
vq_delete_node(Vuid_queue *vq, Vuid_q_node *vqn)
{
if (vqn == vq->top) {
(void) vq_get(vq, FIRM_EVENT_NULL);
return;
}
vqn->prev->next = vqn->next;
if (vq->bottom == vqn)
vq->bottom = vqn->prev;
else
vqn->next->prev = vqn->prev;
vq_free_node(vq, vqn);
}
static Vuid_q_node *
vq_alloc_node(Vuid_queue *vq)
{
Vuid_q_node *vqn;
if (vq->free == VUID_Q_NODE_NULL)
return (VUID_Q_NODE_NULL);
vqn = vq->free;
vq->free = vq->free->next;
vq->num++;
vqn->next = VUID_Q_NODE_NULL;
return (vqn);
}
static void
vq_free_node(Vuid_queue *vq, Vuid_q_node *vqn)
{
vqn->next = vq->free;
vqn->prev = VUID_Q_NODE_NULL;
vq->free = vqn;
vq->num--;
}
static int
tv_equal(struct timeval32 a, struct timeval32 b)
{
return (a.tv_sec == b.tv_sec && a.tv_usec == b.tv_usec);
}
static struct timeval32
tv_subt(struct timeval32 atv, struct timeval32 btv)
{
if ((atv.tv_usec < btv.tv_usec) && atv.tv_sec) {
atv.tv_usec += 1000000;
atv.tv_sec--;
}
if (atv.tv_usec > btv.tv_usec)
atv.tv_usec -= btv.tv_usec;
else
atv.tv_usec = 0;
if (atv.tv_sec > btv.tv_sec)
atv.tv_sec -= btv.tv_sec;
else {
if (atv.tv_sec < btv.tv_sec)
atv.tv_usec = 0;
atv.tv_sec = 0;
}
return (atv);
}
static struct timeval32
tv_divide(struct timeval32 tv, int dividend)
{
int usecs;
if (dividend == 0)
return (tv);
usecs = tv_to_usec(tv);
usecs /= dividend;
tv = usec_to_tv(usecs);
return (tv);
}
static struct timeval32
tv_mult(struct timeval32 tv, int multiplier)
{
int usecs;
usecs = tv_to_usec(tv);
usecs *= multiplier;
tv = usec_to_tv(usecs);
return (tv);
}
static struct timeval32
usec_to_tv(int usec)
{
struct timeval32 tv;
tv.tv_sec = usec / 1000000;
tv.tv_usec = usec % 1000000;
return (tv);
}