mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-27 02:14:19 +00:00
447 lines
13 KiB
TeX
447 lines
13 KiB
TeX
.MB +5
|
||
.MT -3
|
||
.LL 65
|
||
.PN 53
|
||
.HE MP/M User's Guide
|
||
.FT (All Information Herein is Proprietary to Digital Research.)
|
||
.sp
|
||
.pp
|
||
2.3 Queue and Process Descriptor Data Structures
|
||
.pp
|
||
This section contains a description of the queue and process
|
||
descriptor data structures used by the MP/M Extended Disk Operating
|
||
System (XDOS).
|
||
.sp
|
||
.ce
|
||
QUEUE DATA STRUCTURES
|
||
.pp
|
||
A queue is a first in first out (FIFO) mechanism which has been
|
||
implemented in MP/M to provide several essential functions in a
|
||
multi-tasking environment. Queues can be used for the communication
|
||
of messages between processes, to synchronize processes, and to provide
|
||
mutual exclusion.
|
||
.pp
|
||
MP/M has been designed to simplify queue management for both user
|
||
and system processes. In fact, queues are treated in a manner
|
||
similar to disk files. Queues can be created, opened, written to,
|
||
read from, and deleted.
|
||
.pp
|
||
A few illustrations should suffice to describe applications
|
||
for queues:
|
||
.pp
|
||
COMMUNICATION:
|
||
.pp
|
||
A queue can be used for communication to provide a FIFO list of
|
||
messages produced by a producer for consumption by a consumer.
|
||
For example, consider a data logging application where
|
||
data is continuously received via a serial communication link and is to
|
||
be written to a disk file. This would be a difficult application
|
||
for a sequential operating system such as CP/M because arriving
|
||
serial data would be lost while buffers were being written to
|
||
disk. Under MP/M a queue could be used by the producer to send
|
||
blocks of received serial data (or simply buffer pointers) to a consumer
|
||
which would write the blocks on disk. MP/M supports concurrency of
|
||
these operations, allowing the producer to quickly write a buffer to
|
||
the queue and then resume monitoring the serial input.
|
||
.pp
|
||
SYNCHRONIZATION:
|
||
.pp
|
||
When a process attempts to read a message at a queue and there are
|
||
no messages posted at the queue, the process is placed in a priority
|
||
ordered list of processes waiting for messages at the queue. The
|
||
process will remain in that state until a message arrives. Thus
|
||
synchronization of processes can be achieved, allowing the waiting
|
||
(DQing) process to continue execution when a message is sent to
|
||
the queue.
|
||
.cp 20
|
||
.pp
|
||
MUTUAL EXCLUSION:
|
||
.pp
|
||
A queue can also be used for mutual exclusion.
|
||
Mutual exclusion messages generally have a length of zero. A good
|
||
example of mutual exclusion is that which is used by MP/M to
|
||
control access to the printer. A queue is created (MXList)
|
||
and sent one message. When the printer is to be used by the spooler
|
||
or by entering a control-P (^P) at the console an attempt is
|
||
made to read the message from the list mutual exclusion queue.
|
||
This attempt is made using the MP/M conditional read queue function.
|
||
If the message is available, that is it has not been consumed by
|
||
some other process, it is read and the printer is used. When finished
|
||
with the printer,
|
||
the message is written back to the list mutual exclusion queue.
|
||
If the message is not available the user who entered the ^P
|
||
receives a message indicating that the printer is busy.
|
||
In the case of the spooler, it waits until the printer is available
|
||
before continuing.
|
||
.sp
|
||
.ce
|
||
QUEUE DATA STRUCTURES
|
||
.SP
|
||
.pp
|
||
The queue data structures include the queue control block and the user
|
||
queue control block. There are two types of queue control blocks,
|
||
circular or linked. The type of queue control block used depends upon
|
||
the message size. Message sizes of 0 to 2 bytes use circular queues
|
||
while message sizes of 3 or more bytes use linked queues.
|
||
.sp
|
||
.ce
|
||
CIRCULAR QUEUES
|
||
.pp
|
||
The following example illustrates how to setup a queue control block
|
||
for a circular queue with 80 messages of a one byte length.
|
||
Each example in this section will be shown both in PL/M and assembly
|
||
language.
|
||
.cp 17
|
||
.LI
|
||
|
||
PL/M:
|
||
|
||
DECLARE CIRCULAR$QUEUE STRUCTURE (
|
||
QL ADDRESS,
|
||
NAME(8) BYTE,
|
||
MSGLEN ADDRESS,
|
||
NMBMSGS ADDRESS,
|
||
DQPH ADDRESS,
|
||
NQPH ADDRESS,
|
||
MSG$IN ADDRESS,
|
||
MSG$OUT ADDRESS,
|
||
MSG$CNT ADDRESS,
|
||
BUFFER (80) BYTE )
|
||
INITIAL (0,'CIRCQUE ',1,80);
|
||
.ad
|
||
.cp 14
|
||
.li
|
||
|
||
Assembly Language:
|
||
|
||
CRCQUE:
|
||
DS 2 ; QL
|
||
DB 'CIRCQUE ' ; NAME
|
||
DW 1 ; MSGLEN
|
||
DW 80 ; NMBMSGS
|
||
DS 2 ; DQPH
|
||
DS 2 ; NQPH
|
||
DS 2 ; MSGIN
|
||
DS 2 ; MSGOUT
|
||
DS 2 ; MSGCNT
|
||
BUFFER: DS 80 ; BUFFER
|
||
|
||
.AD
|
||
The elements of the circular queue shown above are defined
|
||
as follows:
|
||
.LI
|
||
|
||
QL = 2 byte link, set by system
|
||
NAME = 8 ASCII character queue name,
|
||
set by user
|
||
MSGLEN = 2 bytes, length of message,
|
||
set by user
|
||
NMBMSGS = 2 bytes, number of messages,
|
||
set by user
|
||
DQPH = 2 bytes, DQ process head,
|
||
set by system
|
||
NQPH = 2 bytes, NQ process head,
|
||
set by system
|
||
MSG$IN = 2 bytes, pointer to next
|
||
message in, set by system
|
||
MSG$OUT = 2 bytes, pointer to next
|
||
message out, set by system
|
||
MSG$CNT = 2 bytes, number of messages
|
||
in the queue, set by system
|
||
BUFFER = n bytes, where n is equal to
|
||
the message length times the
|
||
number of messages, space
|
||
allocated by user, set by system
|
||
|
||
Note: Mutual exclusion queues require
|
||
a two byte buffer for the owner process
|
||
descriptor address.
|
||
|
||
Queue Overhead = 24 bytes
|
||
|
||
|
||
.AD
|
||
.sp
|
||
.ce
|
||
LINKED QUEUES
|
||
.pp
|
||
The following example illustrates how to setup a queue control block
|
||
for a linked queue containing 4 messages, each 33 bytes in length:
|
||
.cp 16
|
||
.LI
|
||
|
||
PL/M:
|
||
|
||
DECLARE LINKED$QUEUE STRUCTURE (
|
||
QL ADDRESS,
|
||
NAME (8) BYTE,
|
||
MSGLEN ADDRESS,
|
||
NMBMSGS ADDRESS,
|
||
DQPH ADDRESS,
|
||
NQPH ADDRESS,
|
||
MH ADDRESS,
|
||
MT ADDRESS,
|
||
BH ADDRESS,
|
||
BUFFER (140) BYTE )
|
||
INITIAL (0,'LNKQUE ',33,4);
|
||
.ad
|
||
.cp 21
|
||
.li
|
||
|
||
Assembly Language:
|
||
|
||
LNKQUE:
|
||
DS 2 ; QL
|
||
DB 'LNKQUE ' ; NAME
|
||
DW 33 ; MSGLEN
|
||
DW 4 ; NMBMSGS
|
||
DS 2 ; DQPH
|
||
DS 2 ; NQPH
|
||
DS 2 ; MH
|
||
DS 2 ; MT
|
||
DS 2 ; BH
|
||
BUFFER: DS 2 ; MSG #1 LINK
|
||
DS 33 ; MSG #1 DATA
|
||
DS 2 ; MSG #2 LINK
|
||
DS 33 ; MSG #2 DATA
|
||
DS 2 ; MSG #3 LINK
|
||
DS 33 ; MSG #3 DATA
|
||
DS 2 ; MSG #4 LINK
|
||
DS 33 ; MSG #4 DATA
|
||
|
||
.AD
|
||
The elements of the linked queue shown above are defined
|
||
as follows:
|
||
.LI
|
||
|
||
QL = 2 byte link, set by system
|
||
NAME = 8 ASCII character queue name,
|
||
set by user
|
||
MSGLEN = 2 bytes, length of message,
|
||
set by user
|
||
NMBMSGS = 2 bytes, number of messages,
|
||
set by user
|
||
DQPH = 2 bytes, DQ process head,
|
||
set by system
|
||
NQPH = 2 bytes, NQ process head,
|
||
set by system
|
||
MH = 2 bytes, message head,
|
||
set by system
|
||
MT = 2 bytes, message tail,
|
||
set by system
|
||
BH = 2 bytes, buffer head,
|
||
set by system
|
||
BUFFER = n bytes where n is equal to
|
||
the message length plus two,
|
||
times the number of messages,
|
||
space allocated by the user,
|
||
set by the system
|
||
|
||
.AD
|
||
.sp
|
||
.ce
|
||
USER QUEUE CONTROL BLOCK
|
||
.pp
|
||
The user queue control block data structure is used to provide
|
||
read/write access to queues in much the same manner that a file
|
||
control block provides access to a disk file. Queues are "opened",
|
||
an operation which fills in the actual queue control block address,
|
||
and then can be read from or written to.
|
||
.pp
|
||
If the actual queue address is known it can be filled in the
|
||
pointer field of the user queue control block, the 8 byte name
|
||
field can be omitted, and an open operation is not required in
|
||
order to access the queue.
|
||
.pp
|
||
The following example illustrates a user queue control block:
|
||
.cp 9
|
||
.LI
|
||
|
||
PL/M:
|
||
|
||
DECLARE USER$QUEUE$CONTROL$BLOCK STRUCTURE (
|
||
POINTER ADDRESS,
|
||
MSGADR ADDRESS,
|
||
NAME (8) BYTE )
|
||
INITIAL (0,.BUFFER,'SPOOL ');
|
||
|
||
DECLARE BUFFER (33) BYTE;
|
||
.ad
|
||
.cp 11
|
||
.li
|
||
|
||
Assembly Language:
|
||
|
||
UQCB:
|
||
DS 2 ; POINTER
|
||
DW BUFFER ; MSGADR
|
||
DB 'SPOOL ' ; NAME
|
||
|
||
BUFFER:
|
||
DS 33 ; BUFFER
|
||
|
||
.AD
|
||
.cp 14
|
||
.pp
|
||
The elements of the user queue control block shown above are defined
|
||
as follows:
|
||
.LI
|
||
|
||
POINTER = 2 bytes, set by system to address of
|
||
actual queue during an open queue
|
||
operation, or set by the user if the
|
||
actual queue address is known
|
||
MSGADR = 2 bytes, address of user buffer,
|
||
set by user
|
||
NAME = 8 bytes, ASCII queue name,
|
||
set by user, may be omitted if the
|
||
pointer field is set by the user
|
||
|
||
.AD
|
||
.sp
|
||
.ce
|
||
QUEUE NAMING CONVENTIONS
|
||
.pp
|
||
The following conventions should be used in the naming of
|
||
queues. Queues which are to be directly written to by the
|
||
Terminal Message Process (TMP) via the Command Line
|
||
Interpreter (CLI) must have an upper case ASCII name. Thus
|
||
when an operator enters the queue name followed by a
|
||
command tail at a console, the command tail is written to
|
||
the queue.
|
||
.pp
|
||
In order to make a queue inaccessible by a user at a
|
||
console it must contain at least one lower case character.
|
||
Mutual exclusion queues should be named upper case 'MX'
|
||
followed by 1 to 6 additional ASCII characters. These
|
||
queues are treated specially in that they must have a two
|
||
byte buffer in which MP/M places the address of the process
|
||
descriptor owning the mutual exclusion message.
|
||
.cp 35
|
||
.sp
|
||
.ce
|
||
PROCESS DESCRIPTOR
|
||
.pp
|
||
Each process in the MP/M system has a process descriptor which
|
||
defines all the characteristics of the process. The following
|
||
example illustrates the process descriptor:
|
||
.cp 28
|
||
.LI
|
||
|
||
PL/M:
|
||
|
||
DECLARE CNS$HNDLR STRUCTURE (
|
||
PL ADDRESS,
|
||
STATUS BYTE,
|
||
PRIORITY BYTE,
|
||
STKPTR ADDRESS,
|
||
NAME (8) BYTE,
|
||
CONSOLE BYTE,
|
||
MEMSEG BYTE,
|
||
B ADDRESS,
|
||
THREAD ADDRESS,
|
||
DISK$SET$DMA ADDRESS,
|
||
DISK$SLCT BYTE,
|
||
DCNT ADDRESS,
|
||
SEARCHL BYTE,
|
||
SEARCHA ADDRESS,
|
||
DRVACT ADDRESS,
|
||
REGISTERS (20) BYTE,
|
||
SCRATCH (2) BYTE )
|
||
INITIAL (0,0,200,.CNS$STK(19),
|
||
'CNS ',1,0FFH);
|
||
|
||
DECLARE CNS$STK (20) ADDRESS INITIAL (
|
||
0C7C7H,0C7C7H,0C7C7H,0C7C7H,0C7C7H,0C7C7H,
|
||
0C7C7H,0C7C7H,0C7C7H,0C7C7H,0C7C7H,0C7C7H,
|
||
0C7C7H,0C7C7H,0C7C7H,0C7C7H,0C7C7H,0C7C7H,
|
||
0C7C7H,STRT$CNS);
|
||
.ad
|
||
.cp 28
|
||
.li
|
||
|
||
Assembly Language:
|
||
|
||
CNSHND:
|
||
DW 0 ; PL
|
||
DB 0 ; STATUS
|
||
DB 200 ; PRIORITY
|
||
DW CNSTK+38 ;STKPTR
|
||
DB 'CNS ' ; NAME
|
||
DB 0 ; CONSOLE
|
||
DB 0FFH ; MEMSEG (FF = resident)
|
||
DS 2 ; B
|
||
DS 2 ; THREAD
|
||
DS 2 ; DISK SET DMA
|
||
DS 1 ; DISK SLCT
|
||
DS 2 ; DCNT
|
||
DS 1 ; SEARCHL
|
||
DS 2 ; SEARCHA
|
||
DS 2 ; DRVACT
|
||
DS 20 ; REGISTERS
|
||
DS 2 ; SCRATCH
|
||
|
||
CNSTK:
|
||
DW 0C7C7H,0C7C7H,0C7C7H,0C7C7H
|
||
DW 0C7C7H,0C7C7H,0C7C7H,0C7C7H
|
||
DW 0C7C7H,0C7C7H,0C7C7H,0C7C7H
|
||
DW 0C7C7H,0C7C7H,0C7C7H,0C7C7H
|
||
DW 0C7C7H,0C7C7H,0C7C7H
|
||
DW CNSPR ; CNSTK+38 = PROCEDURE ADR
|
||
.AD
|
||
.pp
|
||
The elements of the process descriptor shown above are defined
|
||
as follows:
|
||
.LI
|
||
|
||
PL = 2 byte link field, initially set by
|
||
user to address of next process
|
||
descriptor, or zero if no more
|
||
STATUS = 1 byte, process status, set by system
|
||
PRIORITY = 1 byte, process priority, set by user
|
||
STKPTR = 2 bytes, stack pointer, initially set
|
||
by user
|
||
NAME = 8 bytes, ASCII process name, set by user
|
||
|
||
The high order bit of each byte of the
|
||
process name is reserved for use by the
|
||
system. The high order bit of the first
|
||
byte (identified as NAME(0)') "on" indicates
|
||
that the process is performing direct
|
||
console BIOS calls and that MP/M is to
|
||
ignore all control characters. It is also
|
||
used to suppress the normal console status
|
||
check done when BDOS disk functions are
|
||
invoked. This bit may be set by the user.
|
||
|
||
CONSOLE = 1 byte, console to be used by process,
|
||
set by user
|
||
MEMSEG = 1 byte, memory segment table index
|
||
B = 2 bytes, system scatch area
|
||
THREAD = 2 bytes, process list thread, set
|
||
by system
|
||
DISK$SET$DMA = 2 bytes, default DMA address, set by user
|
||
DISK$SLCT = 1 byte, default disk/user code
|
||
DCNT = 2 bytes, system scratch byte
|
||
SEARCHL = 1 byte, system scratch byte
|
||
SEARCHA = 2 bytes, system scratch bytes
|
||
DRVACT = 2 bytes, 16 bit vector of drives being
|
||
accessed by the process
|
||
REGISTERS =20 bytes, 8080 / Z80 register save area
|
||
SCRATCH = 2 bytes, system scratch bytes
|
||
|
||
.AD
|
||
.sp
|
||
.ce
|
||
PROCESS NAMING CONVENTIONS
|
||
.pp
|
||
The following conventions should be used in the naming of
|
||
processes. Processes which wait on queues that are to be
|
||
sent command tails from the TMPs are given the console
|
||
resource if their name matches that of the queue which they
|
||
are reading.
|
||
Processes which are to be protected from abortion by an
|
||
operator using the ABORT command must have at least one
|
||
lower case character in the process name.
|
||
.br
|
||
|