mirror of
https://github.com/PDP-10/stacken.git
synced 2026-04-20 00:43:22 +00:00
567 lines
14 KiB
Plaintext
567 lines
14 KiB
Plaintext
! PH4:<GLINDELL>NMUQUE.BLI.7 21-Nov-83 17:21:45, Edit by GLINDELL
|
||
!
|
||
! Ident 4.
|
||
! Add routine NMU$QUEUE_NEXT that returns the next entry of a queue
|
||
!
|
||
! NET:<VOBA.NML.DEVELOPMENT>NMUQUE.BLI.3 25-Mar-82 17:59:35, Edit by VOBA
|
||
!
|
||
! Ident 3.
|
||
! Add routine NMU$QUEUE_LENGTH to return the length (number of entries) of
|
||
! a queue.
|
||
!
|
||
! NET:<VOBA.NML.DEVELOPMENT>NMUQUE.BLI.5 4-Mar-82 14:19:09, Edit by VOBA
|
||
!
|
||
! Ident 2.
|
||
! Clean up code and update copyright date.
|
||
!
|
||
!NET:<DECNET20-V3P1.BASELEVEL-2.SOURCES>NMUQUE.BLI.4 12-Aug-81 10:47:34, Edit by JENNESS
|
||
!
|
||
! Update copyright notice.
|
||
! Clean up code, update to current coding conventions.
|
||
%title 'NMUQUE -- General Queue Management'
|
||
module NMUQUE (
|
||
ident = 'X00.04'
|
||
) =
|
||
begin
|
||
|
||
! COPYRIGHT (C) 1981, 1982 BY
|
||
! DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASSACHUSETTS 01754
|
||
!
|
||
! THIS SOFTWARE IS FURNISHED UNDER A LICENSE FOR USE ONLY ON A SINGLE
|
||
! COMPUTER SYSTEM AND MAY BE COPIED ONLY 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
|
||
! EXCEPT FOR USE ON SUCH SYSTEM AND TO ONE WHO AGREES TO THESE LICENSE
|
||
! TERMS. TITLE TO AND OWNERSHIP OF THE SOFTWARE SHALL AT ALL TIMES
|
||
! REMAIN IN DEC.
|
||
!
|
||
! THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE
|
||
! AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT
|
||
! CORPORATION.
|
||
!
|
||
! DEC ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS
|
||
! SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DEC.
|
||
!
|
||
|
||
!++
|
||
! 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:
|