Init
This commit is contained in:
361
sys/sundev/vuid_queue.c
Normal file
361
sys/sundev/vuid_queue.c
Normal file
@@ -0,0 +1,361 @@
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)vuid_queue.c 1.1 94/10/31 Copyr 1985 Sun Micro";
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Copyright (c) 1985 by Sun Microsystems, Inc.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Vuid (Virtual User Input Device) queue management.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sundev/vuid_event.h>
|
||||
#include <sundev/vuid_queue.h>
|
||||
|
||||
Vuid_q_node *vq_alloc_node();
|
||||
void vq_free_node();
|
||||
int tv_equal();
|
||||
struct timeval tv_subt();
|
||||
struct timeval tv_divide();
|
||||
struct timeval tv_mult();
|
||||
#define tv_to_usec(tv) (((tv).tv_sec * 1000000) + (tv).tv_usec)
|
||||
/* Works for small numbers (< 1000) of seconds */
|
||||
struct timeval usec_to_tv();
|
||||
|
||||
void
|
||||
vq_initialize(vq, data, bytes)
|
||||
register Vuid_queue *vq;
|
||||
caddr_t data;
|
||||
u_int bytes;
|
||||
{
|
||||
register Vuid_q_node *new_vqns, *vqn;
|
||||
|
||||
/* Initialize vq */
|
||||
vq->top = vq->bottom = vq->free = VUID_Q_NODE_NULL;
|
||||
vq->size = 1 + (bytes - sizeof (Vuid_q_node)) / sizeof (Vuid_q_node);
|
||||
/* Place in pool by freeing all nodes (fudge vq->num for this) */
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
Vuid_q_code
|
||||
vq_put(vq, firm_event)
|
||||
Vuid_queue *vq;
|
||||
Firm_event *firm_event;
|
||||
{
|
||||
register Vuid_q_node *vp;
|
||||
|
||||
/* Merge into existing events based on time stamp */
|
||||
for (vp = vq->bottom; vp; vp = vp->prev) {
|
||||
/* Put later times closer to the bottom than earlier ones */
|
||||
if (timercmp(&vp->firm_event.time, &firm_event->time, <) ||
|
||||
tv_equal(vp->firm_event.time, firm_event->time)) {
|
||||
register Vuid_q_node *vqn = vq_alloc_node(vq);
|
||||
|
||||
if (vqn == VUID_Q_NODE_NULL)
|
||||
return (VUID_Q_OVERFLOW);
|
||||
vqn->firm_event = *firm_event;
|
||||
/* Insert vqn before vq (neither are null) */
|
||||
/* Initialize vqn's next and prev */
|
||||
vqn->next = vp->next;
|
||||
vqn->prev = vp;
|
||||
/* Fix up vp next's prev */
|
||||
if (vp->next != VUID_Q_NODE_NULL)
|
||||
vp->next->prev = vqn;
|
||||
/* Fix up vp's next */
|
||||
vp->next = vqn;
|
||||
/* Change bottom */
|
||||
if (vp == vq->bottom)
|
||||
vq->bottom = vqn;
|
||||
/* Change top */
|
||||
if (vq->top == VUID_Q_NODE_NULL)
|
||||
vq->top = vqn;
|
||||
return (VUID_Q_OK);
|
||||
}
|
||||
}
|
||||
/* Place at top of queue */
|
||||
return (vq_putback(vq, firm_event));
|
||||
}
|
||||
|
||||
Vuid_q_code
|
||||
vq_get(vq, firm_event)
|
||||
register Vuid_queue *vq;
|
||||
Firm_event *firm_event;
|
||||
{
|
||||
register Vuid_q_node *vqn = vq->top;
|
||||
|
||||
if (vqn == VUID_Q_NODE_NULL)
|
||||
return (VUID_Q_EMPTY);
|
||||
/* Conditionally copy data */
|
||||
if (firm_event != FIRM_EVENT_NULL)
|
||||
*firm_event = vqn->firm_event;
|
||||
/* Change top */
|
||||
vq->top = vqn->next;
|
||||
/* Null new top's prev */
|
||||
if (vq->top != VUID_Q_NODE_NULL)
|
||||
vq->top->prev = VUID_Q_NODE_NULL;
|
||||
/* Change bottom */
|
||||
if (vq->bottom == vqn)
|
||||
vq->bottom = VUID_Q_NODE_NULL;
|
||||
/* Release storage */
|
||||
vq_free_node(vq, vqn);
|
||||
return (VUID_Q_OK);
|
||||
}
|
||||
|
||||
Vuid_q_code
|
||||
vq_peek(vq, firm_event)
|
||||
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(vq, firm_event)
|
||||
register Vuid_queue *vq;
|
||||
Firm_event *firm_event;
|
||||
{
|
||||
register Vuid_q_node *vqn = vq_alloc_node(vq);
|
||||
|
||||
if (vqn == VUID_Q_NODE_NULL)
|
||||
return (VUID_Q_OVERFLOW);
|
||||
vqn->firm_event = *firm_event;
|
||||
/* Change new top's next */
|
||||
vqn->next = vq->top;
|
||||
/* Null new top's prev */
|
||||
vqn->prev = VUID_Q_NODE_NULL;
|
||||
/* Change old top's prev */
|
||||
if (vq->top != VUID_Q_NODE_NULL)
|
||||
vq->top->prev = vqn;
|
||||
/* Change top */
|
||||
vq->top = vqn;
|
||||
/* Change bottom */
|
||||
if (vq->bottom == VUID_Q_NODE_NULL)
|
||||
vq->bottom = vqn;
|
||||
return (VUID_Q_OK);
|
||||
}
|
||||
|
||||
int
|
||||
vq_compress(vq, factor)
|
||||
register Vuid_queue *vq;
|
||||
int factor;
|
||||
{
|
||||
struct timeval tv_interval, tv_avg_diff, tv_diff; /* Intermediates */
|
||||
struct timeval tv_threshold;
|
||||
register 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;
|
||||
/*
|
||||
* Determine the threshold time interval under which events of
|
||||
* the same type (valuator only) are collapsed.
|
||||
* min_time_betvqnen_values = ((first_entry_time - last_entry_time) /
|
||||
* max_number_of_queue_entries) * factor_by_which_to_compress_queue;
|
||||
*/
|
||||
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);
|
||||
/* March down list */
|
||||
for (base = vq->top; base; base = base->next) {
|
||||
/* See if valuator event */
|
||||
if (!vq_is_valuator(base))
|
||||
continue;
|
||||
/* Run down list looking for a collapse victim */
|
||||
for (victim = base->next; victim; victim = victim_next) {
|
||||
/* Remember next victim incase axe victim below */
|
||||
victim_next = victim->next;
|
||||
/* Fail if not valuator event */
|
||||
if (!vq_is_valuator(victim))
|
||||
goto Advance_Base;
|
||||
/*
|
||||
* May peek ahead and do the collapse as long as the
|
||||
* intervening times of other valuator event types
|
||||
* are the same. Fail if intervening event's time
|
||||
* differs from victim's.
|
||||
*/
|
||||
if (victim->prev != base) {
|
||||
if (!tv_equal(victim->prev->firm_event.time,
|
||||
victim->firm_event.time))
|
||||
goto Advance_Base;
|
||||
}
|
||||
/* Fail if time difference is above threshold */
|
||||
tv_diff = tv_subt(victim->firm_event.time,
|
||||
base->firm_event.time);
|
||||
/* Zero factor means collapse regardless of threshold */
|
||||
if ((factor > 0) &&
|
||||
(timercmp(&tv_diff, &tv_threshold, >)))
|
||||
goto Advance_Base;
|
||||
/* Do collapse if same event id */
|
||||
if (victim->firm_event.id == base->firm_event.id){
|
||||
/* Collapse value into base event */
|
||||
switch (base->firm_event.pair_type) {
|
||||
case FE_PAIR_ABSOLUTE:
|
||||
/* id is delta */
|
||||
base->firm_event.value +=
|
||||
victim->firm_event.value;
|
||||
break;
|
||||
case FE_PAIR_DELTA:
|
||||
/* id is absolute */
|
||||
/* Fall through */
|
||||
default:
|
||||
/* Assume id is absolute */
|
||||
base->firm_event.value =
|
||||
victim->firm_event.value;
|
||||
break;
|
||||
}
|
||||
/* Remove victim node */
|
||||
vq_delete_node(vq, victim);
|
||||
}
|
||||
}
|
||||
Advance_Base:
|
||||
{}
|
||||
}
|
||||
return (num_start - vq->num);
|
||||
}
|
||||
|
||||
int
|
||||
vq_is_valuator(vqn)
|
||||
register 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(vq, vqn)
|
||||
register Vuid_queue *vq;
|
||||
register Vuid_q_node *vqn;
|
||||
{
|
||||
/* Use get if removing off top of queue */
|
||||
if (vqn == vq->top) {
|
||||
(void) vq_get(vq, FIRM_EVENT_NULL);
|
||||
return;
|
||||
}
|
||||
/* Update previous next link (not null else vqn would be top) */
|
||||
vqn->prev->next = vqn->next;
|
||||
/* Change bottom */
|
||||
if (vq->bottom == vqn)
|
||||
vq->bottom = vqn->prev;
|
||||
else
|
||||
/* Update next previous link (if null else vqn is bottom) */
|
||||
vqn->next->prev = vqn->prev;
|
||||
/* Release storage */
|
||||
vq_free_node(vq, vqn);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Caller must initialize data returned from vq_alloc_node.
|
||||
* VUID_Q_NODE_NULL is possible.
|
||||
*/
|
||||
Vuid_q_node *
|
||||
vq_alloc_node(vq)
|
||||
register Vuid_queue *vq;
|
||||
{
|
||||
register 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);
|
||||
}
|
||||
|
||||
void
|
||||
vq_free_node(vq, vqn)
|
||||
register Vuid_queue *vq;
|
||||
Vuid_q_node *vqn;
|
||||
{
|
||||
vqn->next = vq->free;
|
||||
vqn->prev = VUID_Q_NODE_NULL;
|
||||
vq->free = vqn;
|
||||
vq->num--;
|
||||
}
|
||||
|
||||
int
|
||||
tv_equal(a, b)
|
||||
struct timeval a, b;
|
||||
{
|
||||
return(a.tv_sec == b.tv_sec && a.tv_usec == b.tv_usec);
|
||||
}
|
||||
|
||||
/* atv-btv */
|
||||
struct timeval
|
||||
tv_subt(atv, btv)
|
||||
struct timeval atv, 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);
|
||||
}
|
||||
|
||||
/* tv / dividend */
|
||||
struct timeval
|
||||
tv_divide(tv, dividend)
|
||||
struct timeval tv;
|
||||
int dividend;
|
||||
{
|
||||
int usecs;
|
||||
|
||||
if (dividend == 0)
|
||||
return (tv);
|
||||
usecs = tv_to_usec(tv);
|
||||
usecs /= dividend;
|
||||
tv = usec_to_tv(usecs);
|
||||
return (tv);
|
||||
}
|
||||
|
||||
/* tv * multiplier (works for small multipliers * seconds, < 1000) */
|
||||
struct timeval
|
||||
tv_mult(tv, multiplier)
|
||||
struct timeval tv;
|
||||
int multiplier;
|
||||
{
|
||||
int usecs;
|
||||
|
||||
usecs = tv_to_usec(tv);
|
||||
usecs *= multiplier;
|
||||
tv = usec_to_tv(usecs);
|
||||
return (tv);
|
||||
}
|
||||
|
||||
struct timeval
|
||||
usec_to_tv(usec)
|
||||
int usec;
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
tv.tv_sec = usec / 1000000;
|
||||
tv.tv_usec = usec % 1000000;
|
||||
return (tv);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user