DEFINITION MODULE Queues;

	(********************************************************)
	(*							*)
	(*		Generic queue module.			*)
	(*							*)
	(*  Programmer:		P. Moylan			*)
	(*  Last edited:	12 November 1991		*)
	(*  Status:		OK				*)
	(*							*)
	(********************************************************)

(************************************************************************)
(*									*)
(*  A non-obvious decision to be made in the design of a module like	*)
(*  this is whether to work directly with the caller's data, or with	*)
(*  pointers to the data.  In the present case, this means deciding	*)
(*  whether to implement queues of user data or queues of pointers.	*)
(*  The former choice is superior in terms of clarity and ease of use,	*)
(*  but requires the physical copying of data between the queue and	*)
(*  the caller's data structure.  The latter choice is more efficient,	*)
(*  but requires the caller to be concerned with allocation and		*)
(*  deallocation of data space.  With some languages we would not be	*)
(*  faced with this delicate choice, but Modula-2 has relatively poor	*)
(*  support for generic data structures.				*)
(*									*)
(*  For this module, the decision has been to support the more		*)
(*  efficient but less elegant arrangement: to add something to the	*)
(*  queue, the caller supplies a pointer to the data, which might	*)
(*  require that the caller allocate some space for that data.  When	*)
(*  an item is removed from the queue, what is returned is again a	*)
(*  pointer to the data.  That is, the actual data live in a data	*)
(*  space which is under the control of the user.  This implies that	*)
(*  the caller can - but should not - modify queued data.  This		*)
(*  solution is not as clean as it might have been, but is justified	*)
(*  by the need of some callers of this module for a low-overhead	*)
(*  solution.								*)
(*									*)
(*  Note, however, that the caller is not required to supply space for	*)
(*  the "bookkeeping" information such as the pointers which link the	*)
(*  queue elements together.  That level of detail is hidden inside	*)
(*  this module, as it should be.					*)
(*									*)
(*  Critical section protection is also provided; that is, a queue	*)
(*  may safely be used by multiple tasks.				*)
(*									*)
(************************************************************************)

FROM SYSTEM IMPORT
    (* type *)	ADDRESS;

TYPE Queue;	(* is private *)

PROCEDURE CreateQueue (VAR (*OUT*) Q: Queue);

    (* Creates a new queue, initially empty.	*)

PROCEDURE DestroyQueue (Q: Queue);

    (* Destroys queue Q, thus freeing up the space it occupied.  Any	*)
    (* data still on the queue are lost.  After this call, no further	*)
    (* operations should be performed on the queue.			*)

PROCEDURE AddToQueue (Q: Queue;  DataPointer: ADDRESS);

    (* Places a new element at the tail of queue Q.  The caller has an	*)
    (* obligation to ensure that DataPointer^ remains in existence	*)
    (* for as long as it remains on the queue.				*)

PROCEDURE TakeFromQueue (Q: Queue): ADDRESS;

    (* Removes and returns a pointer to the datum at the head of the	*)
    (* queue.  If the queue is empty, waits until data available.	*)

PROCEDURE Empty (Q: Queue): BOOLEAN;

    (* Returns TRUE iff Q is empty.  Warning: if more than one task is	*)
    (* using this queue, there is no guarantee as to how long the queue	*)
    (* will remain empty.						*)

END Queues.
