[net.unix-wizards] inter-process communication

dana@gatech.CSNET (Dana Eckart) (01/30/86)

I don't know if this has been asked before, but here goes anyway...

I am working on a project in which I wish to set up virtual machines
(modeled as processes) which communicate over a virtual network (the
ipc).  I am currently using the parent process to form a bi-directional
ring network through the use of "fork" and some pipes.  In this way,
I can have upwards of 20 machines (processes) in my network (at least 
under the current configuration of unix on the machine).

The problem occurs in the sending of messages through the pipes.  How do
I let the receiving process know that something is there?  I have used
"select" with busying waiting, and although this works, it is obviously
not very desirable.  "fcntl" was tried, until it was realized that unix
4.2bsd doesn't support it for SIGIO (although we are actually using
4.2BRL).  It has even come to the point where "kill" messages were sent
explicitly, only to realize that signals are not stacked (blocked) but
ORed with the current mask.  (Since there is a great deal of communication,
some sort of signal block seems to be a must in my application.)  I realize
that sockets were developed to handle this sort of thing, but they are
given little support in 4.2 (or at least it seems that way to me).  I would
prefer to use pipes if possible anyway.

Now for the question, does anyone have any experience in doing something
similiar to what I have described above?  More hopefully, has anyone "hacked"
on fcntl enough to get it to work for SIGIO (this of course seems the most
preferable solution to my problem)?  I am not a unix wiz by any means (I
hope I haven't botched the description of the problem either :-)), so any
help which could be offered would be greatly appreciated.

Thanks in advance...

--dana eckart (dana@gatech)

chris@umcp-cs.UUCP (Chris Torek) (02/02/86)

I am not sure about 4.2, but SIGIO works in 4.3, at least judging by
the kernel code.  But whether or not it works in 4.2 you will still
have to use a select loop in a signal handler, because (as you noted)
signals are not queued.

	#include <sys/types.h>
	#include <signal.h>
	#include <errno.h>

	#ifndef FD_ZERO		/* 4.2, alas */
	#define FD_ZERO(p)	((p)->fds_bits = 0)
	#define FD_SET(n, p)	((p)->fds_bits |= 1 << (n))
	#define FD_CLR(n, p)	((p)->fds_bits &= ~(1 << (n)))
	#define FD_ISSET(n, p)	((p)->fds_bits & (1 << (n)))
	#endif

	int sockets[N];		/* for some N */
	int nsockets;

	...
		signal(SIGIO, asyncinput);
	...

	/*
	 * Poll all the sockets to see who has input ready.
	 */
	asyncinput()
	{
		register int i, cc;
		int nfds = 0;
		fd_set inset, intemp;
		struct timeval tv;
		extern int errno;

		/*
		 * Initialise `inset', then set bits for the descriptors
		 * in which we are interested.  Also note the highest
		 * descriptor, and add one; this is the number of
		 * `interesting' descriptors in inset.  (Passing an
		 * exact value helps the kernel run us faster.)
		 */
		FD_ZERO(&inset);	/* init */
		for (i = 0; i < nsockets; i++) {
			FD_SET(sockets[i], &inset);
			if (sockets[i] >= nfds)
				nfds = sockets[i] + 1;
		}
		tv.tv_sec = 0;		/* poll */
		tv.tv_usec = 0;

		/*
		 * Select until there is no more input available.  Since
		 * select() clobbers its masks, we use a copy of inset.
		 * The select is done with a `poll' (time out immediately
		 * if nothing ready).
		 */
		for (;;) {
			intemp = inset;
			cc = select(max, &intemp, (fd_set *) 0, (fd_set *) 0,
				&tv);
			if (cc < 0) {
				if (errno == EINTR)
					continue;
				/* handle select error */
			}
			if (cc == 0)
				return;	/* none left (timed out) */
			for (i = 0; i < nsockets; i++)
				if (FD_ISSET(sockets[i], &intemp))
					readsocket(sockets[i]);
			/* all done with input, try again for more */
		}
	}

Something like the above should work with explicit `kill's to wake
up readers as well as with SIGIOs from the kernel.

Oh, important: you must use F_SETOWN before you will get any SIGIOs:

		me = getpid();
		/* or -getpid() for process group instead of single owner */
		for (i = 0; i < nsockets; i++)
			if (fcntl(sockets[i], F_SETOWN, mypid))
				oops();	/* handle error */

This is no doubt true in 4.2 as well.  (You can substitute an
ioctl(SIOCSPGRP) for F_SETOWN, though I think the former is clearer.)

You may get a performance increase by setting the select timeout
to a few milliseconds, depending on how much message passing goes
on versus how much computation.  Experiment a bit.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1415)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@mimsy.umd.edu