You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
955 lines
30 KiB
955 lines
30 KiB
#ifndef _QUEUE_HPP_
|
|
#define _QUEUE_HPP_
|
|
// Ruler
|
|
// 1 2 3 4 5 6 7 8
|
|
//345678901234567890123456789012345678901234567890123456789012345678901234567890
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* The standard layout. */
|
|
/* */
|
|
/* The standard layout for 'hpp' files for this code is as */
|
|
/* follows: */
|
|
/* */
|
|
/* 1. Include files. */
|
|
/* 2. Constants exported from the class. */
|
|
/* 3. Data structures exported from the class. */
|
|
/* 4. Forward references to other data structures. */
|
|
/* 5. Class specifications (including inline functions). */
|
|
/* 6. Additional large inline functions. */
|
|
/* */
|
|
/* Any portion that is not required is simply omitted. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
#include "Global.hpp"
|
|
|
|
#include "Common.hpp"
|
|
#include "Lock.hpp"
|
|
#include "Vector.hpp"
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Constants exported from the class. */
|
|
/* */
|
|
/* The queue constants specify the initial size of the queue. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
CONST SBIT32 QueueSize = 1024;
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Queues and queue management. */
|
|
/* */
|
|
/* This class provides general purpose queues along with some */
|
|
/* basic management. The queues are optimized for very high */
|
|
/* performance on SMP systems. Whenever possible multiple */
|
|
/* items should added and removed from a queue at the same time. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
template <class TYPE,class LOCK=NO_LOCK> class QUEUE : public COMMON, public LOCK
|
|
{
|
|
//
|
|
// Private data.
|
|
//
|
|
SBIT32 MaxSize;
|
|
|
|
BOOLEAN Align;
|
|
SBIT32 Mask;
|
|
|
|
SBIT32 Back;
|
|
SBIT32 Front;
|
|
|
|
VECTOR<TYPE> Queue;
|
|
|
|
public:
|
|
//
|
|
// Public functions.
|
|
//
|
|
QUEUE( SBIT32 NewMaxSize = QueueSize,BOOLEAN NewAlign = True );
|
|
|
|
BOOLEAN MultiplePopBackOfQueue
|
|
(
|
|
SBIT32 Requested,
|
|
TYPE Data[],
|
|
SBIT32 *Size
|
|
);
|
|
|
|
BOOLEAN MultiplePopFrontOfQueue
|
|
(
|
|
SBIT32 Requested,
|
|
TYPE Data[],
|
|
SBIT32 *Size
|
|
);
|
|
|
|
VOID MultiplePushBackOfQueue
|
|
(
|
|
CONST TYPE Data[],
|
|
CONST SBIT32 Size
|
|
);
|
|
|
|
VOID MultiplePushFrontOfQueue
|
|
(
|
|
CONST TYPE Data[],
|
|
CONST SBIT32 Size
|
|
);
|
|
|
|
BOOLEAN PeekBackOfQueue( TYPE *Data );
|
|
|
|
BOOLEAN PeekFrontOfQueue( TYPE *Data );
|
|
|
|
BOOLEAN PopBackOfQueue( TYPE *Data );
|
|
|
|
BOOLEAN PopFrontOfQueue( TYPE *Data );
|
|
|
|
VOID PushBackOfQueue( CONST TYPE & Data );
|
|
|
|
VOID PushFrontOfQueue( CONST TYPE & Data );
|
|
|
|
SBIT32 SizeOfQueue( VOID );
|
|
|
|
~QUEUE( VOID );
|
|
|
|
//
|
|
// Public inline functions.
|
|
//
|
|
INLINE BOOLEAN MultiplePopQueue
|
|
(
|
|
SBIT32 Requested,
|
|
TYPE Data[],
|
|
SBIT32 *Size
|
|
)
|
|
{ return MultiplePopFrontOfQueue( Requested,Data,Size ); }
|
|
|
|
INLINE VOID MultiplePushQueue
|
|
(
|
|
CONST TYPE Data[],
|
|
CONST SBIT32 Size
|
|
)
|
|
{ MultiplePushBackOfQueue( Data,Size ); }
|
|
|
|
INLINE BOOLEAN PeekQueue( TYPE *Data )
|
|
{ return PeekFrontOfQueue( Data ); }
|
|
|
|
INLINE BOOLEAN PopQueue( TYPE *Data )
|
|
{ return PopFrontOfQueue( Data ); }
|
|
|
|
INLINE VOID PushQueue( CONST TYPE & Data )
|
|
{ PushBackOfQueue( Data ); }
|
|
|
|
private:
|
|
//
|
|
// Private functions.
|
|
//
|
|
VOID ExpandQueue( VOID );
|
|
|
|
//
|
|
// Disabled operations.
|
|
//
|
|
QUEUE( CONST QUEUE & Copy );
|
|
|
|
VOID operator=( CONST QUEUE & Copy );
|
|
};
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Class constructor. */
|
|
/* */
|
|
/* Create a new queue and prepare it for use. This call is */
|
|
/* not thread safe and should only be made in a single thread */
|
|
/* environment. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
template <class TYPE,class LOCK> QUEUE<TYPE,LOCK>::QUEUE
|
|
(
|
|
SBIT32 NewMaxSize,
|
|
BOOLEAN NewAlign
|
|
) :
|
|
//
|
|
// Call the constructors for the contained classes.
|
|
//
|
|
Queue( NewMaxSize,1,CacheLineSize )
|
|
{
|
|
#ifdef DEBUGGING
|
|
if ( NewMaxSize > 0 )
|
|
{
|
|
#endif
|
|
//
|
|
// Setup the control information.
|
|
//
|
|
MaxSize = NewMaxSize;
|
|
|
|
Align = NewAlign;
|
|
Mask = 0x7fffffff;
|
|
|
|
//
|
|
// Setup the queue so it is empty.
|
|
//
|
|
Back = 0;
|
|
Front = 0;
|
|
|
|
//
|
|
// Compute the alignment mask.
|
|
//
|
|
if
|
|
(
|
|
((sizeof(TYPE) > 0) && (sizeof(TYPE) <= CacheLineSize))
|
|
&&
|
|
(PowerOfTwo( sizeof(TYPE) ))
|
|
)
|
|
{ Mask = ((CacheLineSize / sizeof(TYPE))-1); }
|
|
#ifdef DEBUGGING
|
|
}
|
|
else
|
|
{ Failure( "Size in constructor for QUEUE" ); }
|
|
#endif
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Expand a queue. */
|
|
/* */
|
|
/* When a queue becomes full we need to expand it and to copy */
|
|
/* the tail end of the queue into the correct place. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
template <class TYPE,class LOCK> VOID QUEUE<TYPE,LOCK>::ExpandQueue( VOID )
|
|
{
|
|
REGISTER SBIT32 Count;
|
|
REGISTER SBIT32 NewSize = (MaxSize * ExpandStore);
|
|
|
|
//
|
|
// Expand the queue (it will be at least doubled).
|
|
//
|
|
Queue.Resize( NewSize );
|
|
|
|
//
|
|
// Copy the tail end of the queue to the correct
|
|
// place in the expanded queue.
|
|
//
|
|
for ( Count = 0;Count < Back;Count ++ )
|
|
{ Queue[ (MaxSize + Count) ] = Queue[ Count ]; }
|
|
|
|
//
|
|
// Update the control information.
|
|
//
|
|
Back += MaxSize;
|
|
MaxSize = NewSize;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Pop multiple items from the back of the queue. */
|
|
/* */
|
|
/* We remove multiple items from a queue and check to make sure */
|
|
/* that the queue has not wrapped. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
template <class TYPE,class LOCK> BOOLEAN QUEUE<TYPE,LOCK>::MultiplePopBackOfQueue
|
|
(
|
|
SBIT32 Requested,
|
|
TYPE Data[],
|
|
SBIT32 *Size
|
|
)
|
|
{
|
|
REGISTER BOOLEAN Result;
|
|
|
|
//
|
|
// Claim an exclusive lock (if enabled).
|
|
//
|
|
ClaimExclusiveLock();
|
|
|
|
//
|
|
// When running on SMP hardware it is very important
|
|
// to prevent multiple CPU fighting over the same memory.
|
|
// Most systems prevent multiple CPUs accessing a cache
|
|
// line at the same time. Here we modify the request
|
|
// to pop exactly the correct number of items to leave
|
|
// us on a cache line boundary.
|
|
//
|
|
if ( Align )
|
|
{
|
|
REGISTER SBIT32 Spare = (Back & Mask);
|
|
|
|
if ( Requested > Spare )
|
|
{
|
|
Requested -= Spare;
|
|
Requested &= ~Mask;
|
|
Requested += Spare;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If there is enough elements in the current queue
|
|
// to extract without wrapping then just do a straight
|
|
// copy.
|
|
//
|
|
if
|
|
(
|
|
((Front <= Back) && (Front <= (Back - Requested)))
|
|
||
|
|
((Front > Back) && ((Back - Requested) >= 0))
|
|
)
|
|
{
|
|
REGISTER SBIT32 Count;
|
|
|
|
//
|
|
// We have verified that it is safe to remove all
|
|
// the requested elements with a straight copy.
|
|
//
|
|
for ( Count = 0;Count < Requested;Count ++ )
|
|
{ Data[ Count ] = Queue[ -- Back ]; }
|
|
|
|
(*Size) = Requested;
|
|
|
|
Result = True;
|
|
}
|
|
else
|
|
{
|
|
REGISTER SBIT32 Count;
|
|
|
|
//
|
|
// It is not safe to remove all the elements from
|
|
// the array. Hence, I must remove them one at a
|
|
// time. This is tedious but should only happen
|
|
// occasionally.
|
|
//
|
|
for ( Count=0,(*Size)=0;Count < Requested;Count ++,(*Size) ++ )
|
|
{
|
|
if ( Front != Back )
|
|
{
|
|
//
|
|
// We have found an element so return it
|
|
// to the caller. However, lets we need
|
|
// to be careful about wrapping.
|
|
//
|
|
if ( Back <= 0 )
|
|
{ Back = MaxSize; }
|
|
|
|
Data[ Count ] = Queue[ -- Back ];
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We are out of queue elements so lets exit.
|
|
// However, we only return 'False' if we didn't
|
|
// find any elements at all.
|
|
//
|
|
Result = (Count != 0);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Release any lock we claimed earlier.
|
|
//
|
|
ReleaseExclusiveLock();
|
|
|
|
return Result;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Pop multiple items from the front of the queue. */
|
|
/* */
|
|
/* We remove multiple items from a queue and check to make sure */
|
|
/* that the queue has not wrapped. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
template <class TYPE,class LOCK> BOOLEAN QUEUE<TYPE,LOCK>::MultiplePopFrontOfQueue
|
|
(
|
|
SBIT32 Requested,
|
|
TYPE Data[],
|
|
SBIT32 *Size
|
|
)
|
|
{
|
|
REGISTER BOOLEAN Result;
|
|
|
|
//
|
|
// Claim an exclusive lock (if enabled).
|
|
//
|
|
ClaimExclusiveLock();
|
|
|
|
//
|
|
// When running on SMP hardware it is very important
|
|
// to prevent multiple CPU fighting over the same memory.
|
|
// Most systems prevent multiple CPUs accessing cache
|
|
// lines at the same time. Here we modify the request
|
|
// to access exactly the correct number of items to leave
|
|
// us on a cache line boundary.
|
|
//
|
|
if ( Align )
|
|
{
|
|
REGISTER SBIT32 Spare = ((Mask + 1) - (Front & Mask));
|
|
|
|
if ( Requested > Spare )
|
|
{
|
|
Requested -= Spare;
|
|
Requested &= ~Mask;
|
|
Requested += Spare;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If there is enough elements in the current queue
|
|
// to extract without wrapping then just do a straight
|
|
// copy.
|
|
//
|
|
if
|
|
(
|
|
((Front <= Back) && ((Front + Requested) <= Back))
|
|
||
|
|
((Front > Back) && ((Front + Requested) < MaxSize))
|
|
)
|
|
{
|
|
REGISTER SBIT32 Count;
|
|
|
|
//
|
|
// We have verified that it is safe to remove all
|
|
// the requested elements with a straight copy.
|
|
//
|
|
for ( Count = 0;Count < Requested;Count ++ )
|
|
{ Data[ Count ] = Queue[ Front ++ ]; }
|
|
|
|
(*Size) = Requested;
|
|
|
|
Result = True;
|
|
}
|
|
else
|
|
{
|
|
REGISTER SBIT32 Count;
|
|
//
|
|
// It is not safe to remove all the elements from
|
|
// the array. Hence, I must remove them one at a
|
|
// time. This is tedious but should only happen
|
|
// occasionally.
|
|
//
|
|
for ( Count=0,(*Size)=0;Count < Requested;Count ++,(*Size) ++ )
|
|
{
|
|
if ( Front != Back )
|
|
{
|
|
//
|
|
// We have found an element so return it
|
|
// to the caller. However, lets we need
|
|
// to be careful about wrapping.
|
|
//
|
|
Data[ Count ] = Queue[ Front ++ ];
|
|
|
|
if ( Front >= MaxSize )
|
|
{ Front = 0; }
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We are out of queue elements so lets exit.
|
|
// However, we only return 'False' if we didn't
|
|
// find any elements at all.
|
|
//
|
|
Result = (Count != 0);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Release any lock we claimed earlier.
|
|
//
|
|
ReleaseExclusiveLock();
|
|
|
|
return Result;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Push multiple items onto the back of the queue. */
|
|
/* */
|
|
/* We add multiple items to a queue and check to make sure that */
|
|
/* the queue has not overflowed. If the queue has overflowed */
|
|
/* we double its size. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
template <class TYPE,class LOCK> VOID QUEUE<TYPE,LOCK>::MultiplePushBackOfQueue
|
|
(
|
|
CONST TYPE Data[],
|
|
CONST SBIT32 Size
|
|
)
|
|
{
|
|
//
|
|
// Claim an exclusive lock (if enabled).
|
|
//
|
|
ClaimExclusiveLock();
|
|
|
|
//
|
|
// If there is enough space in the current queue
|
|
// for the new elements without wrapping then
|
|
// just do a straight copy.
|
|
//
|
|
if
|
|
(
|
|
((Front <= Back) && ((Back + Size) < MaxSize))
|
|
||
|
|
((Front > Back) && (Front > (Back + Size)))
|
|
)
|
|
{
|
|
REGISTER SBIT32 Count;
|
|
|
|
//
|
|
// We have verified that it is safe to copy
|
|
// all the new elements on to the end of the
|
|
// array. So lets do it and then we can exit.
|
|
//
|
|
for ( Count = 0;Count < Size;Count ++ )
|
|
{ Queue[ Back ++ ] = Data[ Count ]; }
|
|
}
|
|
else
|
|
{
|
|
REGISTER SBIT32 Count;
|
|
|
|
//
|
|
// It is not safe to add the new elements to
|
|
// the end of the array so add them one at a
|
|
// time. This is tedious but should only happen
|
|
// occasionally.
|
|
//
|
|
for ( Count=0;Count < Size;Count ++ )
|
|
{
|
|
//
|
|
// Add element to the queue. If necessary
|
|
// wrap round to the front of the array.
|
|
//
|
|
Queue[ Back ++ ] = Data[ Count ];
|
|
|
|
if ( Back >= MaxSize )
|
|
{ Back = 0; }
|
|
|
|
//
|
|
// Verify that the queue is not full. If
|
|
// it is full then double its size and
|
|
// copy wrapped data to the correct position
|
|
// in the new array.
|
|
//
|
|
if ( Front == Back )
|
|
{ ExpandQueue(); }
|
|
}
|
|
}
|
|
|
|
//
|
|
// Release any lock we claimed earlier.
|
|
//
|
|
ReleaseExclusiveLock();
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Push multiple items onto the front of the queue. */
|
|
/* */
|
|
/* We add multiple items to a queue and check to make sure that */
|
|
/* the queue has not overflowed. If the queue has overflowed */
|
|
/* we double its size. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
template <class TYPE,class LOCK> VOID QUEUE<TYPE,LOCK>::MultiplePushFrontOfQueue
|
|
(
|
|
CONST TYPE Data[],
|
|
CONST SBIT32 Size
|
|
)
|
|
{
|
|
//
|
|
// Claim an exclusive lock (if enabled).
|
|
//
|
|
ClaimExclusiveLock();
|
|
|
|
//
|
|
// If there is enough space in the current queue
|
|
// for the new elements without wrapping then
|
|
// just do a straight copy.
|
|
//
|
|
if
|
|
(
|
|
((Front <= Back) && ((Front - Size) >= 0))
|
|
||
|
|
((Front > Back) && ((Front - Size) > Back))
|
|
)
|
|
{
|
|
REGISTER SBIT32 Count;
|
|
|
|
//
|
|
// We have verified that it is safe to copy
|
|
// all the new elements on to the end of the
|
|
// array. So lets do it and then we can exit.
|
|
//
|
|
for ( Count = 0;Count < Size;Count ++ )
|
|
{ Queue[ -- Front ] = Data[ Count ]; }
|
|
}
|
|
else
|
|
{
|
|
REGISTER SBIT32 Count;
|
|
|
|
//
|
|
// It is not safe to add the new elements to
|
|
// the end of the array so add them one at a
|
|
// time. This is tedious but should only happen
|
|
// occasionally.
|
|
//
|
|
for ( Count = 0;Count < Size;Count ++ )
|
|
{
|
|
//
|
|
// Add element to the queue. If necessary
|
|
// wrap round to the back of the array.
|
|
//
|
|
if ( Front <= 0 )
|
|
{ Front = MaxSize; }
|
|
|
|
Queue[ -- Front ] = Data[ Count ];
|
|
|
|
//
|
|
// Verify that the queue is not full. If
|
|
// it is full then double its size and
|
|
// copy wrapped data to the correct position
|
|
// in the new array.
|
|
//
|
|
if ( Front == Back )
|
|
{ ExpandQueue(); }
|
|
}
|
|
}
|
|
|
|
//
|
|
// Release any lock we claimed earlier.
|
|
//
|
|
ReleaseExclusiveLock();
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Peek the back of the queue. */
|
|
/* */
|
|
/* We return the end of the queue but check to make sure */
|
|
/* that the queue is not empty. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
template <class TYPE,class LOCK> BOOLEAN QUEUE<TYPE,LOCK>::PeekBackOfQueue
|
|
(
|
|
TYPE *Data
|
|
)
|
|
{
|
|
REGISTER BOOLEAN Result;
|
|
|
|
//
|
|
// Claim an exclusive lock (if enabled).
|
|
//
|
|
ClaimExclusiveLock();
|
|
|
|
//
|
|
// If the queue contains at least one element then
|
|
// return a copy of the last element.
|
|
//
|
|
if ( Front != Back )
|
|
{
|
|
//
|
|
// The 'Back' index points at the next free cell.
|
|
// So the last element is 'Back - 1'. However,
|
|
// when 'Back' is zero we need to wrap.
|
|
//
|
|
if ( Back > 0 )
|
|
{ (*Data) = Queue[ (Back - 1) ]; }
|
|
else
|
|
{ (*Data) = Queue[ (MaxSize - 1) ]; }
|
|
|
|
Result = True;
|
|
}
|
|
else
|
|
{ Result = False; }
|
|
|
|
//
|
|
// Release any lock we claimed earlier.
|
|
//
|
|
ReleaseExclusiveLock();
|
|
|
|
return Result;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Peek the front of the queue. */
|
|
/* */
|
|
/* We return the front of the queue but check to make sure */
|
|
/* that the queue is not empty. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
template <class TYPE,class LOCK> BOOLEAN QUEUE<TYPE,LOCK>::PeekFrontOfQueue
|
|
(
|
|
TYPE *Data
|
|
)
|
|
{
|
|
REGISTER BOOLEAN Result;
|
|
|
|
//
|
|
// Claim an exclusive lock (if enabled).
|
|
//
|
|
ClaimExclusiveLock();
|
|
|
|
//
|
|
// If the queue contains at least one element then
|
|
// return a copy of the first element.
|
|
//
|
|
if ( Front != Back )
|
|
{
|
|
(*Data) = Queue[ Front ];
|
|
|
|
Result = True;
|
|
}
|
|
else
|
|
{ Result = False; }
|
|
|
|
//
|
|
// Release any lock we claimed earlier.
|
|
//
|
|
ReleaseExclusiveLock();
|
|
|
|
return Result;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Pop an item from the back of the queue. */
|
|
/* */
|
|
/* We remove a single item from a queue and check to make sure */
|
|
/* that the queue has not wrapped. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
template <class TYPE,class LOCK> BOOLEAN QUEUE<TYPE,LOCK>::PopBackOfQueue
|
|
(
|
|
TYPE *Data
|
|
)
|
|
{
|
|
REGISTER BOOLEAN Result;
|
|
|
|
//
|
|
// Claim an exclusive lock (if enabled).
|
|
//
|
|
ClaimExclusiveLock();
|
|
|
|
//
|
|
// We make sure the queue is not empty.
|
|
//
|
|
if ( Front != Back )
|
|
{
|
|
//
|
|
// We have found an element so return it to
|
|
// the caller. If we walk off the end of the
|
|
// queue then wrap to the other end.
|
|
//
|
|
if ( Back <= 0 )
|
|
{ Back = MaxSize; }
|
|
|
|
(*Data) = Queue[ -- Back ];
|
|
|
|
Result = True;
|
|
}
|
|
else
|
|
{ Result = False; }
|
|
|
|
//
|
|
// Release any lock we claimed earlier.
|
|
//
|
|
ReleaseExclusiveLock();
|
|
|
|
return Result;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Pop an item from the front of the queue. */
|
|
/* */
|
|
/* We remove a single item from a queue and check to make sure */
|
|
/* that the queue has not wrapped. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
template <class TYPE,class LOCK> BOOLEAN QUEUE<TYPE,LOCK>::PopFrontOfQueue
|
|
(
|
|
TYPE *Data
|
|
)
|
|
{
|
|
REGISTER BOOLEAN Result;
|
|
|
|
//
|
|
// Claim an exclusive lock (if enabled).
|
|
//
|
|
ClaimExclusiveLock();
|
|
|
|
//
|
|
// We make sure the queue is not empty.
|
|
//
|
|
if ( Front != Back )
|
|
{
|
|
//
|
|
// We have found an element so return it to
|
|
// the caller. If we walk off the end of the
|
|
// queue then wrap to the other end.
|
|
//
|
|
(*Data) = Queue[ Front ++ ];
|
|
|
|
if ( Front >= MaxSize )
|
|
{ Front = 0; }
|
|
|
|
Result = True;
|
|
}
|
|
else
|
|
{ Result = False; }
|
|
|
|
//
|
|
// Release any lock we claimed earlier.
|
|
//
|
|
ReleaseExclusiveLock();
|
|
|
|
return Result;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Push an item onto the back of the queue. */
|
|
/* */
|
|
/* We add a single item to a queue and check to make sure that */
|
|
/* the queue has not overflowed. If the queue has overflowed */
|
|
/* we double its size. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
template <class TYPE,class LOCK> VOID QUEUE<TYPE,LOCK>::PushBackOfQueue
|
|
(
|
|
CONST TYPE & Data
|
|
)
|
|
{
|
|
//
|
|
// Claim an exclisive lock (if enabled).
|
|
//
|
|
ClaimExclusiveLock();
|
|
|
|
//
|
|
// Add element to the queue. If necessary wrap round
|
|
// to the front of the array.
|
|
//
|
|
Queue[ Back ++ ] = Data;
|
|
|
|
if ( Back >= MaxSize )
|
|
{ Back = 0; }
|
|
|
|
//
|
|
// Verify that the queue is not full. If it is full then
|
|
// double its size and copy wrapped data to the correct
|
|
// position in the new array.
|
|
//
|
|
if ( Front == Back )
|
|
{ ExpandQueue(); }
|
|
|
|
//
|
|
// Release any lock we claimed earlier.
|
|
//
|
|
ReleaseExclusiveLock();
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Push an item onto the front of the queue. */
|
|
/* */
|
|
/* We add a single item to a queue and check to make sure that */
|
|
/* the queue has not overflowed. If the queue has overflowed */
|
|
/* we double its size. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
template <class TYPE,class LOCK> VOID QUEUE<TYPE,LOCK>::PushFrontOfQueue
|
|
(
|
|
CONST TYPE & Data
|
|
)
|
|
{
|
|
//
|
|
// Claim an exclisive lock (if enabled).
|
|
//
|
|
ClaimExclusiveLock();
|
|
|
|
//
|
|
// Add element to the queue. If necessary wrap round
|
|
// to the back of the array.
|
|
//
|
|
if ( Front <= 0 )
|
|
{ Front = MaxSize; }
|
|
|
|
Queue[ -- Front ] = Data;
|
|
|
|
//
|
|
// Verify that the queue is not full. If it is full then
|
|
// double its size and copy wrapped data to the correct
|
|
// position in the new array.
|
|
//
|
|
if ( Front == Back )
|
|
{ ExpandQueue(); }
|
|
|
|
//
|
|
// Release any lock we claimed earlier.
|
|
//
|
|
ReleaseExclusiveLock();
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Calculate the size of the queue. */
|
|
/* */
|
|
/* Calculate the size of the queue and return it to the caller. */
|
|
/* This is only used when the size is needed in all other cases */
|
|
/* we just try to remove the elements in the queue. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
template <class TYPE,class LOCK> SBIT32 QUEUE<TYPE,LOCK>::SizeOfQueue( VOID )
|
|
{
|
|
REGISTER SBIT32 Size;
|
|
|
|
//
|
|
// Claim a shared lock (if enabled).
|
|
//
|
|
ClaimSharedLock();
|
|
|
|
//
|
|
// Compute the size of the queue.
|
|
//
|
|
Size = (Back - Front);
|
|
|
|
if ( Size < 0 )
|
|
{ Size += MaxSize; }
|
|
|
|
//
|
|
// Release any lock we claimed earlier.
|
|
//
|
|
ReleaseSharedLock();
|
|
|
|
return Size;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Class destructor. */
|
|
/* */
|
|
/* Destory a queue. This call is not thread safe and should */
|
|
/* only be made in a single thread environment. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
template <class TYPE,class LOCK> QUEUE<TYPE,LOCK>::~QUEUE( VOID )
|
|
{ /* void */ }
|
|
#endif
|