/*
 * FILENAME: q.h
 *
 * Copyright  2000 By InterNiche Technologies Inc. All rights reserved
 *
 * Software Definitions for the basic queing package. See netq.h for
 * some extensions.
 *
 * MODULE: INET
 *
 *
 * PORTABLE: yes
 */

/* Additional Copyrights: */
/* Portions Copyright 1990-1994 by NetPort 10/13/90 
 * Portions Copyright 1986 by Carnegie Mellon 
 * Portions Copyright 1983 by the Massachusetts Institute of 
 * Technology 
 */

#ifndef _Q_H_
#define  _Q_H_ 1

struct   q_elt    {     /* queue element: cast to right type */
   struct   q_elt   *   qe_next; /* it's just a pointer to next elt */
};

typedef struct q_elt * qp;    /* q pointer */

#define  q_elt qp

typedef   struct   queue   
{        /* queue header */
   q_elt q_head;        /* first element in queue */
   q_elt q_tail;        /* last element in queue */
   int   q_len;         /* number of elements in queue */
   int   q_max;         /* maximum length */
   int   q_min;         /* minimum length */
} queue;

/* The following macros implement most of the common queue operations */

/* Add an element to the head of the queue */

#define   q_addh(q, elt)    { \
   if ((q)->q_head == 0) (q)->q_tail = (elt); \
   (elt)->qe_next = (q)->q_head; \
   (q)->q_head = (elt); \
   (q)->q_len++; \
   if(++((q)->q_len) > (q)->q_max) (q)->q_max = (q)->q_len; \
}

/* Add an element to the tail of a queue */

#define   q_addt(q, elt)   { \
   (elt)->qe_next = 0; \
   if ((q)->q_head == 0) { \
      (q)->q_head = (elt); \
   } else { \
      (q)->q_tail->qe_next = (elt); \
   } \
   (q)->q_tail = (elt); \
   if(++((q)->q_len) > (q)->q_max) (q)->q_max = (q)->q_len; \
}

/* Add an element after a specified element in the queue.  If prev == */
/* &q->q_head, can be used to add an element to the head of the queue */

#define   q_adda(q, prev, new)   { \
   if ((q)->q_tail == (prev) || (q)->q_tail == 0) { \
      (q)->q_tail = (new); \
   } \
   (new)->qe_next = (prev)->qe_next; \
   (prev)->qe_next = (new); \
   if(++((q)->q_len) > (q)->q_max) (q)->q_max = (q)->q_len; \
}

/* Delete an element from a queue, given a pointer to the preceeding element */
/* Will delete the first element if prev == &q->q_head */

#define   q_dela(q, elt, prev)   { \
   if ((q)->q_tail == (elt)) { \
      if ((q)->q_head == (elt)) \
         (q)->q_tail = 0; \
      else \
         (q)->q_tail = (prev); \
   } \
   (prev)->qe_next = (elt)->qe_next; \
   (elt)->qe_next = 0; \
   if(--((q)->q_len) < (q)->q_min) (q)->q_min = (q)->q_len; \
}

/* The above MACROs are quite dangerous; because of lack of 
 * prototypeing, compile time snags, and no built in protection from 
 * premeption. Though they are fast, Code seems to be less buggy if 
 */
/* full prototypes: */
void     putq(queue*, void*);    /* add item to tail of queue */
void *   getq(queue*);           /* de-queue item from head of queue */
queue *  createq(void);
qp       qdel(queue*, void*);    /* delete an item from a queue */

#define  q_add(q,p)  putq(q,p)   /* allow old MIT names */
#define  q_deq(q) getq(q)
#define  aq_deq(q)   getq(q)     /* putq() and getq() are always atomic */
#define  q_create()  createq() 

#endif   /* _Q_H_ */


