/*++

Copyright (C) Microsoft Corporation, 1993 - 1998

Module Name:

    queue.c

Abstract:

   Creates a simple Queue that works in Kernel Mode.

Author:

    Robbie Harris (Hewlett-Packard) 22-May-1998

Environment:

    Kernel mode

Revision History :

--*/
#include "pch.h"

void Queue_Create(Queue *pQueue, int size)
{
    if (!pQueue)
    {
        ParDump(PARERRORS, ("Queue_Create: Queue is Bad"));
        return;
    }

    if (pQueue->theArray)
        Queue_Delete(pQueue);
        
    pQueue->theArray = (UCHAR *)ExAllocatePool(NonPagedPool, size);
    pQueue->max      = size;
    pQueue->head     = pQueue->tail = 0;
}

BOOLEAN Queue_Delete(Queue *pQueue)
{
    if (!pQueue)
    {
        return FALSE;
    }

    if (pQueue->theArray) {
    
        ExFreePool(pQueue->theArray);
        pQueue->theArray = NULL;
    }
    
    pQueue->head = 0;
    pQueue->tail = 0;
    pQueue->max  = 0;
    // NOTE: This can come back to haunt you!
    pQueue = 0;
    
    return TRUE;
}

BOOLEAN Queue_Dequeue(Queue *pQueue, PUCHAR data)
{
    // Validity of pQueue is checked in Queue_IsEmpty proc. 
    if (Queue_IsEmpty(pQueue))
    {
        ParDump(PARERRORS, ("Queue_Dequeue: Queue is Empty"));
        return FALSE;
    }

    *data = pQueue->theArray[pQueue->head++];
    return TRUE;
}

BOOLEAN Queue_Enqueue(Queue *pQueue, UCHAR data)
{
    // Validity of pQueue is checked in Queue_IsFull proc. 
    if (Queue_IsFull(pQueue)) {
    
        ParDump(PARERRORS, ("Queue_Enqueue: Queue is full. Data is lost"));
        return FALSE;
    
    } else {
        pQueue->theArray[pQueue->tail++] = data;
    }

    return TRUE;
}

/* Return TRUE if we were able to free some space in the Queue
*/
BOOLEAN Queue_GarbageCollect(Queue *pQueue)
{
    int     iListSize;
    int     i;

    if (!pQueue)
    {
        ParDump(PARERRORS, ("Queue_GarbageCollect: Queue is Bad"));
        return FALSE;
    }

    iListSize = pQueue->tail - pQueue->head;

    // Check to see if there is any free entries
    if (pQueue->head == 0 && pQueue->tail == pQueue->max)
        return FALSE;
         
    for (i = 0; i < iListSize; i++) {
    
        pQueue->theArray[i] = pQueue->theArray[pQueue->head+i];
    }

    pQueue->head = 0;
    pQueue->tail = iListSize;

    return TRUE;
}

//============================================================================
// NAME:    HPKQueue::IsEmpty()
//  
// PARAMETERS: None
//
// RETURNS: True is Queue is empty or doesn't exist.  Otherwise False.
//
//============================================================================
BOOLEAN Queue_IsEmpty(Queue *pQueue)
{
    if (!pQueue)
    {
        ParDump(PARERRORS, ("Queue_IsEmpty: Queue is Bad"));
        return TRUE;
    }

    if (pQueue->theArray) {
    
        return ((BOOLEAN) (pQueue->head == pQueue->tail));
    }
    ParDump(PARERRORS, ("Queue_IsEmpty: Queue->theArray is Bad"));
    return TRUE;
}

//============================================================================
// NAME:    HPKQueue::IsFull()
//  
// PARAMETERS: None
//
// RETURNS: True is Queue is full or doesn't exist.  Otherwise False.
//
//============================================================================
BOOLEAN Queue_IsFull(Queue *pQueue)
{
    if (!pQueue)
    {
        ParDump(PARERRORS, ("Queue_IsFull: Queue is Bad"));
        return TRUE;
    }

    if (pQueue->theArray) {
    
        if (pQueue->tail == pQueue->max)
            return !(Queue_GarbageCollect(pQueue));

        return FALSE;
    }
    ParDump(PARERRORS, ("Queue_IsFull: Queue->theArray is Bad"));
    return TRUE;
}

