Google
 

Trailing-Edge - PDP-10 Archives - BB-JR93K-BB_1990 - 10,7/decmai/mx/mxnque.b36
There are 13 other files named mxnque.b36 in the archive. Click here to see a list.
%title 'NMUQUE -- General Queue Management'
module NMUQUE (
               ident = 'X00.04'
               ) =
begin
!	COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1985, 1989.
!	ALL RIGHTS RESERVED.
!
!	THIS SOFTWARE IS FURNISHED UNDER A  LICENSE AND MAY BE USED AND  COPIED
!	ONLY IN  ACCORDANCE  WITH  THE  TERMS OF  SUCH  LICENSE  AND  WITH  THE
!	INCLUSION OF THE ABOVE  COPYRIGHT NOTICE.  THIS  SOFTWARE OR ANY  OTHER
!	COPIES THEREOF MAY NOT BE PROVIDED  OR OTHERWISE MADE AVAILABLE TO  ANY
!	OTHER PERSON.  NO  TITLE TO  AND OWNERSHIP  OF THE  SOFTWARE IS  HEREBY
!	TRANSFERRED.
!
!	THE INFORMATION IN THIS  SOFTWARE IS SUBJECT  TO CHANGE WITHOUT  NOTICE
!	AND SHOULD  NOT  BE CONSTRUED  AS  A COMMITMENT  BY  DIGITAL  EQUIPMENT
!	CORPORATION.
!
!	DIGITAL ASSUMES NO  RESPONSIBILITY FOR  THE USE OR  RELIABILITY OF  ITS
!	SOFTWARE ON EQUIPMENT THAT IS NOT SUPPLIED BY DIGITAL.
!++
! Facility: LSG DECnet Network Management
!
! Abstract:
!
!       This set of routines provides a primitives for
!       manipulating queues.  The only requirement for
!       using this set of routines is that the queue overhead
!       information must be defined at the very beginning
!       of any entry made to a queue.
!
! Environment: TOPS10 and TOPS20 user mode, MCB RSX task level
!
! Author: Steven M. Jenness, Creation date: 19 August 1980
!
!--
!
! INCLUDE FILES
!

library 'MXNLIB';                       ! All needed definitions

!
! TABLE OF CONTENTS
!

forward routine
    NMU$QUEUE_MANAGER;                  ! Global entry definitions
%global_routine ('NMU$QUEUE_RESET', QUEUE: ref Q_HEADER) : novalue =

!++
! Functional description:
!
!       This routine resets a queue header to the null
!       state.
!
! Formal parameters:
!
!       .QUEUE   Address of queue header
!
! Routine value: none
! Side effects:
!
!       All pointers in the queue header point to
!       the header itself (empty queue).
!
!--

    begin

    QUEUE[Q_FORWARD] = .QUEUE;
    QUEUE[Q_REVERSE] = .QUEUE;
    UNLOCK (QUEUE[Q_SEMAPHORE]);

    end;                                ! End of NMU$QUEUE_RESET
%global_routine ('NMU$QUEUE_INSERT', QUEUE: ref Q_HEADER, ENTRY: ref Q_ENTRY) =

!++
! Functional description:
!
!       This routine inserts an entry to the end of
!       a queue.
!
! Formal parameters:
!
!       .QUEUE   Address of queue header
!       .ENTRY   Address of entry data.  The queueing information
!                is stored starting at this address.  A block
!                of length Q_ENTRY_SIZE must be reserved.
!
! Routine value:
!
!       $true   if queue becomes non-empty with this insert
!       $false  if queue was previously non-empty
!
! Side effects:
!
!       The forward pointer of the last item on the queue and
!       the reverse pointer of the queue header are changed to
!       point to the new entry.
!
!--

    begin

    local
	LAST_ENTRY : ref Q_ENTRY,
	RET_VAL;

!
! Lock the queue from concurrently running processes.
!

    while not LOCK (QUEUE[Q_SEMAPHORE])
    do 1;

!
! If the queue header is zero ... queue is empty.
! Initialize the queue header.
!

    if .(.QUEUE) eql 0
    then begin
         QUEUE[Q_FORWARD] = .QUEUE;
         QUEUE[Q_REVERSE] = .QUEUE;
         end;

!
! Check for queue empty and set empty transition
! flag.
!

    RET_VAL = (.QUEUE eql .QUEUE[Q_REVERSE]); ! Check for non-empty

!
! Insert entry onto end of queue and
! update pointers.
!

    LAST_ENTRY = .QUEUE[Q_REVERSE];
    ENTRY[Q_REVERSE] = .LAST_ENTRY;
    ENTRY[Q_FORWARD] = .QUEUE;
    QUEUE[Q_REVERSE] = .ENTRY;
    LAST_ENTRY[Q_FORWARD] = .ENTRY;

!
! Unlock the queue.
!

    UNLOCK (QUEUE[Q_SEMAPHORE]);

!
! Return empty to non-empty transition flag.
!

    return .RET_VAL;
    end;                                ! End of NMU$QUEUE_INSERT
%global_routine ('NMU$QUEUE_REMOVE', QUEUE: ref Q_HEADER) =

!++
! Functional description:
!
!       This routine removes the first entry on a queue.
!       If the queue is empty a zero (0) value is returned.
!
! Formal parameters:
!
!       .QUEUE   Address of queue header
!
! Routine value:
!
!       Non-empty queue    Address of entry (after queue information)
!       Empty queue        Zero (0)
!
! Side effects:
!
!       The forward pointer of the queue header and the
!       reverse pointer of the second entry (if any) are
!       changed to point to each other.
!--

    begin

    local
	ENTRY : ref Q_ENTRY,
	NEXT_ENTRY : ref Q_ENTRY;

!
! Lock the queue from concurrently running processes.
!

    while not LOCK (QUEUE[Q_SEMAPHORE])
    do 1;

!
! If the queue header is zero ... queue is empty.
! Initialize the queue header.
!

    if .(.QUEUE) eql 0
    then begin
         QUEUE[Q_FORWARD] = .QUEUE;
         QUEUE[Q_REVERSE] = .QUEUE;
         end;

!
! Get address of first entry on the queue.
!

    ENTRY = .QUEUE[Q_FORWARD];

!
! Check for empty queue, return zero if empty.
! If entry found...
!	unlink from queue
!	fixup queue around hole made by removal
!	clear queue linkage in removed entry.
!

    if .ENTRY eql .QUEUE
    then ENTRY = 0
    else begin
         NEXT_ENTRY = .ENTRY[Q_FORWARD];
         QUEUE[Q_FORWARD] = .NEXT_ENTRY;
         NEXT_ENTRY[Q_REVERSE] = .QUEUE;
         ENTRY[Q_FORWARD] = 0;
         ENTRY[Q_REVERSE] = 0;
         end;

    UNLOCK (QUEUE[Q_SEMAPHORE]);        ! Unlock the queue

    return .ENTRY;                      ! Return address of entry found, if any
    end;                                ! End of NMU$QUEUE_REMOVE
%global_routine ('NMU$QUEUE_EXTRACT', QUEUE: ref Q_HEADER, ENTRY: ref Q_ENTRY) =

!++
! Functional description:
!
!       This routine handles extraction of an entry from a place
!       in a queue other than the beginning.  This requires "knowing"
!       the address of the queue entry before calling this routine.
!
! Formal parameters:
!
!       .QUEUE   Address of queue header
!       .ENTRY   Address of entry (after queue information)
!
! Routine value:
!
!	$true	Entry was found on the queue and extracted
!	$false	Entry was not found on the queue
!
! Side effects:
!
!       The links of the queue entries before and after the
!       entry to be extracted are updated to point to each
!       other.
!
!--

    begin

    local
	NEXT_ENTRY : ref Q_ENTRY,
	PREVIOUS_ENTRY : ref Q_ENTRY,
	SEARCH : ref Q_ENTRY,
	RET_VAL;

!
! Lock the queue from concurrently running processes.
!

    while not LOCK (QUEUE[Q_SEMAPHORE])
    do 1;

!
! If the queue header is zero ... queue is empty.
! Initialize the queue header.
!

    if .(.QUEUE) eql 0
    then begin
         QUEUE[Q_FORWARD] = .QUEUE;
         QUEUE[Q_REVERSE] = .QUEUE;
         end;

!
! Loop until the entry is found.
!

    SEARCH = .QUEUE[Q_FORWARD];

    while (.SEARCH neq .ENTRY) and (.SEARCH neq .QUEUE)
    do SEARCH = .SEARCH[Q_FORWARD];

    if .SEARCH eql .ENTRY               ! Found entry ?
    then begin                          ! Yes, extract it and return true
         NEXT_ENTRY = .ENTRY[Q_FORWARD];
         PREVIOUS_ENTRY = .ENTRY[Q_REVERSE];
         NEXT_ENTRY[Q_REVERSE] = .PREVIOUS_ENTRY;
         PREVIOUS_ENTRY[Q_FORWARD] = .NEXT_ENTRY;
         RET_VAL = $TRUE;
         end
    else RET_VAL = $FALSE;              ! No, return false

    UNLOCK (QUEUE[Q_SEMAPHORE]);        ! Unlock queue

    return .RET_VAL;                    ! Return result of extraction
    end;                                ! End of NMU$QUEUE_EXTRACT
%global_routine ('NMU$QUEUE_LENGTH', QUEUE: ref Q_HEADER) =

!++
! Functional description:
!
!       This routine returns the length (number of entries) of a queue.
!
! Formal parameters:
!
!       .QUEUE   Address of queue header
!
! Routine value:
!
!       The length (number of entries) of the queue.
!
! Side effects: none
!
!--

    begin

    local
	ENTRY,
        RESULT,
	NEXT : ref Q_ENTRY;

!
! Lock the queue from concurrently running processes.
!

    while not LOCK (QUEUE[Q_SEMAPHORE])
    do 1;

!
! If the queue header is zero ... queue is empty.
! Return length of 0
!

    RESULT = 0;

    if .(.QUEUE) neq 0
    then begin
         NEXT = .QUEUE[Q_FORWARD];      ! Set first entry to the queue

         while (ENTRY = .NEXT) neq .QUEUE
         do begin                       ! Scan queue until end of queue
            RESULT = .RESULT + 1;
            NEXT = .NEXT[Q_FORWARD];
            end;
         end;

    UNLOCK (QUEUE[Q_SEMAPHORE]);        ! Unlock the queue

    return .RESULT;                     ! Return the result of scanning
    end;                                ! End of NMU$QUEUE_LENGTH
%global_routine ('NMU$QUEUE_SCAN', QUEUE: ref Q_HEADER, DATA, S_RTN) =

!++
! Functional description:
!
!       This routine facilitates scanning a queue.  The S_RTN
!       parameter specifies a routine that is to be called with
!       the DATA parameter and each ENTRY.  When the return
!       from the S_RTN is non-zero or the queue runs out, the
!       scanning stops.
!
! Formal parameters:
!
!       .QUEUE   Address of queue header
!       .DATA    Data to be passed to each S_RTN call
!       .S_RTN   Scanning routine to be called for each entry
!
! Routine value:
!
!       The value of S_RTN if it ever returns a non-zero value.
!       Zero if the queue runs out before non-zero from S_RTN.
!
! Side effects: none
!
!--

    begin

    bind routine
	SCAN_ROUTINE = .S_RTN;

    local
	ENTRY,
	RESULT,
	NEXT : ref Q_ENTRY;

!
! Lock the queue from concurrently running processes.
!

    while not LOCK (QUEUE[Q_SEMAPHORE])
    do 1;

!
! If the queue header is zero ... queue is empty.
! Initialize the queue header.
!

    if .(.QUEUE) eql 0
    then begin
         QUEUE[Q_FORWARD] = .QUEUE;
         QUEUE[Q_REVERSE] = .QUEUE;
         end;

!
! Clear the result value and point to the
! first entry on the queue.
!

    RESULT = 0;
    NEXT = .QUEUE[Q_FORWARD];

!
! Scan queue until end of queue or the scan
! routine returns a non zero value.
!

    while (ENTRY = .NEXT) neq .QUEUE
    do begin
       NEXT = .NEXT[Q_FORWARD];
       UNLOCK (QUEUE[Q_SEMAPHORE]);

       if (RESULT = SCAN_ROUTINE (.ENTRY, .DATA)) neq 0
       then exitloop;

       while not LOCK (QUEUE[Q_SEMAPHORE])
       do 1;
       end;

    UNLOCK (QUEUE[Q_SEMAPHORE]);        ! Unlock the queue

    return .RESULT;                     ! Return the result of scanning
    end;                                ! End of NMU$QUEUE_SCAN
%global_routine ('NMU$QUEUE_SCAN_EXTRACT', ENTRY: ref Q_ENTRY) : novalue =

!++
! Functional description:
!
!	This routine is used to extract a queue entry from
!	a queue while scanning the queue.  It is assumed
!	that the only queue being worked on is the one being
!	scanned.  It also is assumed that the entry being
!	extracted is the one currently being looked at by
!	the scanning routine.
!
!	ANY OTHER USE OF THIS ROUTINE CAN GIVE UNPREDICTABLE
!	RESULTS!
!
! Formal parameters:
!
!	.ENTRY	Address of queue entry to remove.
!
! Routine value: none
! Side effects: none
!
!--

    begin

    local
	NEXT_ENTRY : ref Q_ENTRY,
	PREVIOUS_ENTRY : ref Q_ENTRY;

    NEXT_ENTRY = .ENTRY[Q_FORWARD];
    PREVIOUS_ENTRY = .ENTRY[Q_REVERSE];
    NEXT_ENTRY[Q_REVERSE] = .PREVIOUS_ENTRY;
    PREVIOUS_ENTRY[Q_FORWARD] = .NEXT_ENTRY;

    end;					! End of NMU$QUEUE_SCAN_EXTRACT

%global_routine ('NMU$QUEUE_NEXT', QUEUE: ref Q_HEADER, ENTRY: ref Q_ENTRY) =

!++
!
! Functional description:
!
!	This routine will return the next entry in a queue.
!
!	At the first call, ENTRY should be zero. The routine will then return
!	the first element. On successive calls, ENTRY should be the entry 
!	returned on the previous call. NMU$QUEUE_NEXT will return the next
!	entry or 0 at the end of the queue.
!
! Formal parameters:
!
!	.QUEUE	Address of queue header
!	.ENTRY	Address of entry
!
! Routine value:
!
!	0	End of queue
!	ENTRY	Address of next entry in queue
!
!--

   begin

   local RESULT;

   if ..QUEUE eql 0
   then return 0                        ! No queue at all
   else begin
        ! Lock the queue from concurrently running processes
        while not LOCK(QUEUE[Q_SEMAPHORE]) do 1;
        if .ENTRY eql 0
        then RESULT = .QUEUE[Q_FORWARD] ! First entry
        else RESULT = .ENTRY[Q_FORWARD]; ! Get next entry
        if .RESULT eql .QUEUE
        then RESULT = 0;                ! At end of queue
        ! Unlock the queue
        UNLOCK(QUEUE[Q_SEMAPHORE]);
        end;

   return .RESULT;

   end;                                 ! End of NMU$QUEUE_NEXT

end						! End of module NMUQUE
eludom
! Local Modes:
! Mode:BLISS
! Auto Save Mode:2
! Comment Column:40
! Comment Rounding:+1
! End: