			VSDRV for RSX-11M V3.2

_Introduction_

RSX-11M V3.2 provides several means for communication between tasks.  Among
these are global event flags, common memory, and the send/receive data
directives.  The latter provide for data transfer from one task to another,
but restrict the amount of data to 13 words per transfer.  RSX-11M-Plus
allows variable-length data blocks of up to 256 words in length; this
feature is not provided with RSX-11M, because it requires support for
secondary executive pool, which RSX-11M does not have.
Because a "variable length send/receive" function can be useful in a number
of applications, a simple driver has been written to provide some of the
same functionality.  The RSX-11M device name for this driver is VS:, and its
features are as follows:
The driver is actually a queue manager, which has its own private pool of
dynamic memory.  (This pool is assembled to a minimum size, and may be
expanded when the driver is loaded, using LOA VS:/SIZE=x for a total driver
size of  x  words.)  Functions provided include: create a queue, put a message
in a queue, get a message from a queue, and delete a queue.  Each queue has
a six-character name.  When a task accesses a queue, it specifies the queue
name.  By default, each task can access a queue whose name is the same as
the task's name.  If selected when the driver is built, a protection feature
prevents non-privileged tasks from creating, deleting, or getting messages
from any queue other than the default queue.  Queues are created explicitly
through driver QIO calls, and are always accessed in FIFO (first in-first
out) order.  A task can cause its "get message" request to wait until a
message has been put into the queue.

_Functions, Parameters, Status Codes_

Here is a list of the QIO function codes recognized by the VS: driver.
Function codes are in octal.

IO.KIL		(0012)	Cancel all waiting read requests for this task.
IO.WLB		(0400)	Put a message into any existing queue.
IO.RLB		(1000)	Get a message from a queue.
IO.RLB!SF.WAI	(1200)	Wait for a message to be put into a queue, and get it.
IO.ATT		(1400)	Device attach -- ignored.
IO.DET		(2000)	Device detach -- ignored.
IO.CRQ		(2400)	Create a message queue.
IO.DLQ		(3000)	Delete a message queue and all queued messages.
IO.DMP		(3400)	For debugging, dump a snapshot of the driver's pool.

The six-word QIO parameter list is used by VS: as follows:

Word 1 -- Buffer address (with IO.WLB, IO.RLB, IO.DMP)
Word 2 -- Buffer length in bytes (with IO.WLB, IO.RLB, IO.DMP)
Word 3 -- First word of RAD50 queue name (with IO.WLB; for privileged tasks,
		also with IO.RLB, IO.CRQ, IO.DLQ)
Word 4 -- Second word of RAD50 queue name (with same functions as word 3)
Word 5 -- Unused
Word 6 -- Unused

Notes:
   *	Buffers used with VS: must be aligned on word boundaries.
   *	The "read" function returns the name of the sending task (in RAD50
	representation) in the first two words of the buffer.  Thus, if you
	are expecting messages of up to  N  bytes in length, you must provide
	at least  N+4  bytes of buffer space for a "read" operation.

Status codes that can be returned by VS: in the first word of the I/O status
block include:

IS.SUC	(+1.)	Successful completion; second word of IOSB is a byte count.
IE.ABO	(-15.)	Operation aborted due to IO.KIL or I/O rundown at task exit.
IE.PRI	(-16.)	Privilege violation--unprivileged task attempted to create,
		delete, or read a queue other than its default, or attempted
		to do an IO.DMP function (only if protection enabled).
IE.QNF	(-101.)	Queue not found.
IE.QEX	(-102.)	Queue already exists (on attempt to create a queue).
IE.NMS	(-103.)	No more space in VS: private pool.
IE.RAW	(-104.)	Read already waiting on queue (for IO.RLB!SF.WAI).
IE.NOM	(-105.)	No message available in queue (for IO.RLB without SF.WAI).
IE.UBS	(-106.)	User buffer is too small to hold entire message (or to hold
		entire driver pool, for IO.DMP).

_Disadvantages and advantages of VS:, compared with variable send/receive_

Disadvantages of VS:
	1.  One or more LUN's must be set aside for use with VS:  (one for
		each simultaneous outstanding wait on a queue).  Variable
		send/receive requires no LUN's at all.
	2.  VS: driver and pool occupy additional memory space, which cannot
		be used for other purposes when VS: is not in use.  Variable
		send/receive code is part of the exec, and pool space is part
		of the exec's secondary pool, usable by other components.
	3.  VS: requires that queues be created and deleted explicitly.
		Variable send/receive has a queue automatically created for
		each task.
	4.  If a task does a read-and-wait function, it cannot be
		checkpointed.  A task that is waiting on a receive-data AST
		can be checkpointed.

Advantages of VS:
	1.  VS: can be used under RSX-11M, which does not support variable
		send/receive or secondary exec pool; the only cost in terms
		of exec resources is the I/O packet required for each request.
	2.  VS: queues exist independent of tasks in the system.  When a task
		exits, no messages are deleted (not even from the task's
		"default" queue); queues can still be "flushed" by deleting
		and immediately re-creating them.
	3.  VS: allows a task to manipulate several queues of messages, while
		variable send/receive provides only one queue per task.  With
		VS:, tasks can "share" queues (under some protocol established
		among them) if the application requires.

Features that might be nice, but ...
	1.  VS: does not allow messages to be retrieved in random order, nor
		does it allow a message to be examined and put back into the
		queue.
	2.  VS: does not provide any way for automatically flushing a queue
		when a task exits (see advantage 2, however); this might be
		a useful feature in some cases.
	3.  VS: does not restrict queue or message sizes beyond physical
		limitations due to pool size.  It might be useful to have
		restrictions on the number of messages in a queue, or the
		size of an individual message.  Currently, any task, either
		maliciously or due to a bug, can fill up VS: pool with
		messages put into a queue that is not being read, thus causing
		legitimate messages to be rejected due to lack of space.
		Some kind of "active/dormant" flag within each queue could be
		used to determine whether messages can be queued, without
		disturbing those messages that are already in the queue.
		Other possible solutions include:  some form of timeout count
		on each message; restricted access to queues (by UIC, list of
		task names, ???); all of these have additional disadvantages
		as well.
	4.  (Add your own to this list, and send them to me, John Osudar!)

_Topics for advanced users_

These topics are not covered here, but you may want to think about them (if
you know what they are!):
	1.  How to use the QIO AST mechanism to emulate a "receive data AST"
	2.  How to design protocols for communication among tasks using VS:

_Use of VS: from FORTRAN_

Here are some notes on using VS: from a FORTRAN program.  This information can
also be found in the RSX-11M/M-PLUS Executive Reference Manual.

(1)  Setting up the QIO parameter list
	The QIO parameter list is an array of six integers.  The VS: driver
	uses these six words as described previously.
	To create the parameter list, use a statement like this:
		INTEGER IPARM(6)
	To put a buffer address into the first word, use the library
	subroutine GETADR, like this:
		CALL GETADR(IPARM(1),IBUFER)
	(Here, IBUFER is the name of the buffer array that is used to transfer
	messages between the driver and the task.)
	To put a buffer size into the second word, use a simple assignment
	statement:
		IPARM(2)=124
	(This tells the driver that 124. bytes of storage are available in
	the buffer on a read request, or that the message being sent is 124.
	bytes long, on a write request.  This would require that the buffer
	array be declared to contain at least 124/2 = 62 words, e.g.
		INTEGER IBUFER(62)
	or the equivalent.)
	To put a RAD50 queue name into the third and fourth words, you must
	create a two-word integer array containing the queue name, and set
	the name into the array with a DATA statement, like this:
		INTEGER QNAME(2)
		DATA QNAME/3RMYQ,3RUE5/
	(The constant form 3Rxxx is like 3Hxxx or 'xxx' but creates a RAD50
	representation of the character string.  In this case, QNAME(1) will
	contain the string 'MYQ', and QNAME(2) will contain 'UE5', which
	together form the name of the queue 'MYQUE5'.)
	Then, you put the queue name into the parameter list with two simple
	assignments:
		IPARM(3)=QNAME(1)
		IPARM(4)=QNAME(2)
	(There are other ways to do this, especially for cases where the queue
	name is not constant, but may be determined when the program is run.
	Consult the FORTRAN User's Guide for subroutines that convert ASCII
	character strings to RAD50, if you need them.)
	Note that you do not need to set up the first two words of the
	parameter list unless you are doing a "read" or "write" function, and
	that the third and fourth words can be set to zeroes if you want to
	use your task's default queue name (same as the task name).

(2)	Assigning a unit to the VS: driver
	In order to access the VS: driver, you must have a logical unit
	assigned to it.  This can be done when you build your task, with an
	option like this:
		ASG=VS:3
	(which assigns LUN 3 to the VS: driver)
	Also, you can do this with a subroutine call within your program:
		CALL ASNLUN(3,'VS',0)
	Here, you specify the LUN as the first parameter; the other parameters
	must be 'VS' and 0 as shown.
	You can assign as many LUN's to the VS: driver as you need.  In
	particular, if your program will be waiting for messages from more
	than one queue at a time (with the IO.RLB!SF.WAI function), then you
	must have as many LUN's assigned as there will be simultaneous waits.

(3)	Doing the actual operation
	To do the operation, you call one of the library subroutines QIO or
	WTQIO.  In both cases, the calls are identical:
		CALL WTQIO(fnc,lun,[efn],,[isb],[prl][,ids])
	The parameters enclosed in [...] are optional, but commas must be
	included as shown, even if some parameters are left out.
	The parameters are:
		fnc	One of the octal function codes, specified in FORTRAN
			with a leading  "  to signify "octal"; e.g.  "1200
		lun	The logical unit number on which to perform this
			operation.  The LUN must be assigned to VS: already.
		efn	An event flag number.  Event flags are single-bit
			flags that can be used to signal the occurrence of
			certain events, in this case the completion of the
			requested operation.  You should probably use "local"
			event flags here (event flags used only by your task);
			these flags are numbered from 1 to 32.  It is through
			the event flag that you determine when the operation
			has been completed.
		isb	The name of a two-word array, the I/O status block,
			which receives a status code in the low byte of the
			first word, and a byte count in the second word.  The
			status code should be +1 for successful operations.
			The byte count tells you how long the message is when
			you do a "read", and should equal your message length
			when you do a "write".
		prl	The name of the six-word parameter list array.
		ids	An integer variable into which the system places a
			"directive status"; if you have made any mistakes, or
			if some condition has occurred that has prevented your
			request from being passed to the VS: driver, this word
			will contain an error code.  Normal completion should
			produce a +1 status.
	The difference between using the QIO and WTQIO calls is this:  WTQIO
	will not return control to your program until the operation has been
	completed, while QIO will return as soon as the operation has been set
	up and sent to the VS: driver.  Look at the Executive Reference Manual
	for subroutines that test event flag status, or stop/wait for event
	flags to be set, if you are planning on using the QIO call instead of
	the WTQIO call.
