[comp.sys.amiga] IPC ... How about this for a shared port standard?

dillon@CORY.BERKELEY.EDU (Matt Dillon) (03/14/88)

	This would be part of a generic run-time library.  Note that
	it makes no assumptions as the format of the messages.  No
	code as yet (just comments), but I see no difficulties.  

	I'm hoping that by taking this just a little at a time, we can
	come up with something that everyone will agree on.

					-Matt

/*
 *  PORTS.C	Matthew Dillon, Public Domain.
 *
 *	SHARED PORT FUNCTION SUPPORT.  These very powerful functions
 *	handle an extended port structure facility.  They are completely
 *	generic and make no assumptions as to the contents or format of
 *	any queued messages (except that they are headed by a Message
 *	structure).
 *
 *
 *	port =	OpenSharedPort(name, "<access>", type)
 *
 *		access string:	c   -create it if it doesn't exit, access
 *				     it if it does (even if not currently
 *				     owned).  Non-existance means "does
 *				     not exist or exists but not owned".
 *
 *				u   -unique (used with "c").  Qualify the
 *				     name with ".??" (some number) to create
 *				     a unique port name.  The passed 'name'
 *				     variable must have enough room to hold
 *				     the qualification.
 *
 *				o   -OWN the port.  Call fails if the port
 *				     cannot be owned immediately.  The port
 *				     will be made into a PA_SIGNAL port.
 *				     This is so you do not need to make a
 *				     OwnSharedPort() call.
 *
 *		NULL is returned on error.  Usually occurs when "c" is
 *		not specified and port does not exist or has no master.
 *
 *		'type' is a longword port-type field used to ensure that
 *		the client and master are talking the same protocol.  If
 *		the port exists and 'type' doesn't match up, NULL is
 *		returned.  For instance, my system would set type to
 *		'SIRC', whereas Pete's may set it to 'PCMS' or something.
 *		This way, his system doesn't get confused with mine.
 *		(This is all assuming we use the same library support)
 *
 *		If the port doesn't exist and "c" is specified, the type
 *		is set by the argument.
 *
 *		A type of (0) matches any type.  This is usually not used
 *		in conjunction with "c".
 *
 *		The name actually placed in the port's ln_Name field (on
 *		port creation) is an allocated duplicate with slight
 *		modifications to prevent accidental access of non-extended
 *		ports.
 *
 *	type  = GetPortType(port)
 *
 *		Return the port type.  Usually used in conjunction with
 *		OpenSharedPort(name, "", 0) to get the type of a port.
 *
 *	error = SetPortVacume(port, function)
 *
 *		Set the vacume cleaner for the port.  An error is returned
 *		if the port already has a vacume cleaner.  The vacume
 *		cleaner function is called (*function)(port) under Forbid()
 *		in the context of the last task to close the port when
 *		there are still messages pending on the port.
 *
 *		NOTE: if ((void *)())(-1L) is specified as the function,
 *		an internal function is used which returns any queued
 *		messages.  Since we don't know the structure of the
 *		message, we do not attempt to modify any sub-fields.
 *		THIS IS THE DEFAULT!
 *
 *		NOTE: The vacume cleaner is considered owned by somebody
 *		if set to some real function (not NULL and not -1).
 *
 *		To use this correctly, you probably want your "PutSharedMsg"
 *		routine to pre-set the io_Error (or whatever) to an error
 *		condition.
 *
 *	error = OwnSharedPort(port, mp_SigTask, mp_Flags)
 *
 *		Immediately become the owner of a port rather than a
 *		client of the port.  Fails if the port already has an owner.
 *
 *		If mp_Flags == PA_SIGNAL, mp_SigTask is ignored and
 *		your task id is used automatically.
 *
 *
 *	(void)  QueueOwnRequest(port, ior)
 *
 *		Queue a request to become the owner of a port.	If the
 *		port currently has no owner, your message will immediately
 *		be returned and you will have ownership.  On return, you
 *		MUST check the io_Error field.	If < 0, the request failed
 *		and you do NOT own the port.   The IORequest must contain
 *		the following fields set.
 *
 *		io_Message.mn_Node.ln_Pri = priority for queue
 *		io_Message.mn_ReplyPort   = replyport to return message
 *					    when ownership is achieved.
 *		io_Unit 		  = mp_SigTask for port.  can be
 *					    NULL if mp_Flags = PA_SIGNAL.
 *		io_Flags		  = mp_Flags (PA_????)
 *		io_Error		  = (reserved)
 *		io_Device		  = (reserved)
 *
 *		io_Message.mn_Node.ln_Name= (available for personal use)
 *		io_Command		  = (available for personal use)
 *
 *	(void)  DisownSharedPort(port)
 *
 *		You must currently own the port.  Ownership is removed and
 *		you become a client to the port.  Additionaly, any
 *		ownership requests made by you via QueueOwnRequest()
 *		are returned with io_Error = -1
 *
 *		Ownership falls to the next person queued to own the
 *		port, if anybody.
 *
 *	(void)  CloseSharedPort(port)
 *
 *		close a port you openned.  IF you own the port
 *		DisownSharedPort() will be automatically called.  Any
 *		ownership requests made by you via QueueOwnRequest()
 *		will be returned with io_Error = -1.
 *
 *		Ownership falls to the next task in the ownership
 *		request queue.	If there is NOBODY left to own the
 *		port, the vacume cleaner function will be called.  NOTE:
 *		you can set the vacume cleaner function to NULL if you
 *		wish.
 *
 *		If the reference count is 0 and no messages exist in
 *		the port's queue, the port will be deallocated.  If
 *		messages remain, the port will not be deallocated.
 *
 *	(void)  FixPortSignal(port)
 *
 *		If any requests are present on the specified port, the
 *		owner is signaled (used to ensure the signal associated
 *		with a port is set if requests exist).  Works even if
 *		you aren't the owner, the port isn't owned, or the
 *		port isn't PA_SIGNAL (i.e. becomes a nop() function).
 *
 *		This call will work with normal port's as well as extended
 *		ports.
 */