/*****************************************************************************

 @(#) $Id: bufq.h,v 0.7.2.5 2001/02/03 05:48:34 brian Test $

 -----------------------------------------------------------------------------

 Copyright (C) 1997-2001  Brian Bidulock <bidulock@dallas.net>

 All Rights Reserved.

 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
 Foundation; either version 2 of the License, or (at your option) any later
 version.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 details.

 You should have received a copy of the GNU General Public License along with
 this program; if not, write to the Free Software Foundation, Inc., 675 Mass
 Ave, Cambridge, MA 02139, USA.

 -----------------------------------------------------------------------------

 Last Modified $Date: 2001/02/03 05:48:34 $ by $Author: brian $

 *****************************************************************************/

#ifndef __BUFQ_H__
#define __BUFQ_H__

typedef struct bufq {
    spinlock_t  q_lock;
    mblk_t      *q_first;
    mblk_t      **q_tail;
    size_t      q_msgs;
    size_t      q_count;
} bufq_t;

static __inline void bufq_init(bufq_t *q)
{
    spin_lock_init(&q->q_lock);
    q->q_first = NULL;
    q->q_tail = &q->q_first;
    q->q_msgs = 0;
    q->q_count = 0;
}

static __inline int bufq_length(bufq_t *q)
{
    return q->q_msgs;
}

static __inline int bufq_size(bufq_t *q)
{
    return q->q_count;
}

static __inline void bufq_queue(bufq_t *q, mblk_t *mp)
{
    mblk_t *md;
    if ( (md = mp) ) {
        mp->b_next = NULL;
        *(q->q_tail) = mp;
        q->q_tail = &mp->b_cont;
        q->q_msgs++;
        while ( md ) {
            q->q_count += md->b_wptr - md->b_rptr;
            md = md->b_cont;
        }
    }
}

static __inline mblk_t *bufq_dequeue(bufq_t *q)
{
    mblk_t *mp, *md;
    if ( (mp = md = q->q_first) ) {
        q->q_first = q->q_first->b_next;
        q->q_msgs--;
        while ( md ) {
            q->q_count -= md->b_wptr - md->b_rptr;
            md = md->b_cont;
        }
    }
    return mp;
}

static __inline void bufq_supply(bufq_t *q, mblk_t *mp)
{
    mblk_t *md = mp;
    while ( md ) {
        md->b_datap->db_type = M_DATA;
        md->b_rptr = md->b_wptr = md->b_datap->db_base;
        bufq_queue(q, md);
        md = unlinkb(md);
    }
}

static __inline mblk_t *bufq_resupply(bufq_t *q, mblk_t *mp, int maxsize, int maxcount)
{
    if ( bufq_length(q) > maxcount || bufq_size(q) > maxsize )
        return mp;
    bufq_supply(q, mp);
    return NULL;
}

static __inline void bufq_purge(bufq_t *q)
{
    while ( q->q_msgs ) freemsg(bufq_dequeue(q));
}




#endif  __BUFQ_H__
