[comp.unix.wizards] I need a SysV select

jpayne@cs.rochester.edu (Jonathan Payne) (05/17/88)

Hi.  The simple version of my question is, is there an equivalent
function in SysV for BSD's select()?

If the answer is no, here's what I am trying to do.  I want to get input
from either the keyboard or from some other file description.  I don't
want to sit around polling the two, because that would be ridiculous.  Is
there any reasonable way to do that on SysV?  (Actually, the question
should be, is there anyway to do that on non-bsd systems?)

Thanks for any suggestions.

Jonathan Payne

ekrell@hector.UUCP (Eduardo Krell) (05/17/88)

In article <9738@sol.ARPA> jpayne@rochester.UUCP writes:

>Hi.  The simple version of my question is, is there an equivalent
>function in SysV for BSD's select()?

The simple version of my answer is NO.

>If the answer is no, here's what I am trying to do.  I want to get input
>from either the keyboard or from some other file description.

System V Release 3 and up have a poll() system call which acts like
select(), but works only on stream file descriptors.  Currently, the
tty driver is not streams-based (it will be in the future), so poll()
won't help you either.
    
    Eduardo Krell                   AT&T Bell Laboratories, Murray Hill, NJ

    UUCP: {ihnp4,ucbvax}!ulysses!ekrell		ARPA: ekrell@ulysses.att.com

gwyn@brl-smoke.ARPA (Doug Gwyn ) (05/17/88)

In article <9738@sol.ARPA> jpayne@cs.rochester.edu (Jonathan Payne) writes:
>I want to get input
>from either the keyboard or from some other file description.  I don't
>want to sit around polling the two, because that would be ridiculous.

If you set MIN and TIME to 0 in the terminal handler, then an attempt
to read from the terminal with no data available will return immediately.
There is nothing analogous for ordinary files.

tim@amdcad.AMD.COM (Tim Olson) (05/17/88)

In article <10293@ulysses.homer.nj.att.com> ekrell@hector (Eduardo Krell) writes:
| In article <9738@sol.ARPA> jpayne@rochester.UUCP writes:
| 
| >Hi.  The simple version of my question is, is there an equivalent
| >function in SysV for BSD's select()?
| 
| The simple version of my answer is NO.
| 
| >If the answer is no, here's what I am trying to do.  I want to get input
| >from either the keyboard or from some other file description.
| 
| System V Release 3 and up have a poll() system call which acts like
| select(), but works only on stream file descriptors.  Currently, the
| tty driver is not streams-based (it will be in the future), so poll()
| won't help you either.
|     

The only way I have found to do this kind of thing under SYSV is to
restructure the program to have a child process dedicated for each fd of
the select(), and have them communicate through shared memory, or
perhaps named pipes.

	-- Tim Olson
	Advanced Micro Devices
	(tim@amdcad.amd.com)

jds@mimsy.UUCP (James DaSilva) (05/17/88)

In article <7904@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn) writes:
>In article <9738@sol.ARPA> jpayne@cs.rochester.edu (Jonathan Payne) writes:
>>I want to get input
>>from either the keyboard or from some other file description.  I don't
>>want to sit around polling the two, because that would be ridiculous.
>
>If you set MIN and TIME to 0 in the terminal handler, then an attempt
>to read from the terminal with no data available will return immediately.
>There is nothing analogous for ordinary files.

That's just his point, Doug.  Sure, once you call ioctl to set things up
to return immediately if no data is present, the polling loop looks something
like this:

	for(;;) {
		if(size1 = read(fd1,buffer1,MAX))
			do_something_with(buffer1,size1);
		if(size2 = read(fd2,buffer2,MAX))
			do_something_with(buffer2,size2);
	}

(Ignore the fact that this simple example doesn't handle error returns from
 read.  You get the point).

This REALLY eats CPU time. If nothing is pending, it will use as much CPU as
the kernel is willing to give it.  Not very friendly.

The natural way to handle this in System V is to use two processes, each of
which is waiting on one file descriptor.  You can then use shared memory
and/or signals, semaphores or message queues to get the data around, to taste.

					- Jaime

----------------------------------------------------------------------
usenet:   uunet!mimsy!jds 				James da Silva
internet: jds@cs.umd.edu
      "Stand on each other's shoulders, not on each other's toes."

charles@c3engr.UUCP (Charles Green) (05/21/88)

In article <11536@mimsy.UUCP> jds@mimsy.umd.edu (James da Silva) writes:
>>In article <9738@sol.ARPA> jpayne@cs.rochester.edu (Jonathan Payne) writes:
>>>I want to get input
>>>from either the keyboard or from some other file description.  I don't
>>>want to sit around polling the two, because that would be ridiculous.

>The natural way to handle this in System V is to use two processes, each of
>which is waiting on one file descriptor.  You can then use shared memory
>and/or signals, semaphores or message queues to get the data around, to taste.

My favorite solution is to have several small "multiplexor" processes, all
identical but exec()ed with a unique numeric argument, reading their respective
stdins and all writing into the same pipe that's read by the main process.
When one of the multiplexor processes completes a read(), he does a single
write() to the pipe containing his unique ID, a byte count, and the data.

The main process sleeps on a read() of the pipe of a size sufficient to pick up
the "header" (ID and byte count).  When he gets one, he issues another read()
to pick up the data.

This scheme works because a write() to a pipe is atomic; data from the other
multiplexor processes won't be interspersed with it (as opposed to TTYs...)
However, you have to be able to accept data from all "channels" simultaneously;
you can't selectively read data from one channel and not another.

	fd >----> [mux] >--
			   \
	fd >----> [mux] >---+--> (pipe) >--> [main process]
			   /
	fd >----> [mux] >--
-- 
#ident	"@(#).signature	1.5 :~charles/s..signature 04/27/88 21:40:43"
charles@c3pe.UUCP				charles_green%c3gate@c3pe

csch@tmpmbx.UUCP (Clemens Schrimpe) (05/22/88)

jpayne@cs.rochester.edu (Jonathan Payne) writes:
{} 
{} Hi.  The simple version of my question is, is there an equivalent
{} function in SysV for BSD's select()?
{} 
{} If the answer is no, here's what I am trying to do.  I want to get input
{} from either the keyboard or from some other file description.  I don't
{} want to sit around polling the two, because that would be ridiculous.  Is
{} there any reasonable way to do that on SysV?  (Actually, the question
{} should be, is there anyway to do that on non-bsd systems?)
1) The answer is NO :-(
2) The answer is YES :-)

There is a way to work around that problem - but not unless
you are willing to hack your kernel. 

One possible way is to build a device-driver, if you don't have
tha capability to hack the list of system calls. 

OK: Here're my thoughts:

	Reduced to the main problem, the thing you'd like to know is,
	whether a read/write on a filedescriptor will block or not.

	Having a way to determine this, you can write a simple loop in
	the kernel checking this for each fd requested and if nothing
	happened, goto sleep by either using delay() or timeout(), sleep(),
	wakeup().

	/* arg contains a bitmask as in BSD-select(2) */
	for (;;)
	{
		mask = 0;
		for (fd=0; fd < 8*sizeof(arg); ++fd)
		{
			if ( !(arg & (1<<fd)))
				continue;

			if (check(fd))
				mask |= 1<<fd;
		}
		if (mask)
			return(mask);
		delay(Hz/10);		/* 1/10 sec idle */
	}

	OK - now: how to determine, if there is data available on a fd;

	Having the fd, you can step into the list in the user-structure
	named u.u_ofile[], which is of type filep_t. In the file-structure
	you'll find a pointer to the related inode-structure.

	OK - if you have this, you can now determine the TYPE of the file:

	- An ordinary file is always read/writeable - mark this fd!
	- A named pipe is readable, if it's size stated in the inode-structure
	  is >0 and writeable if it's size is less then than the maximum size
	  of a named pipe (10240 on Xenix ???).
	- A character-device is more difficult:

***	  The facts stated from hereon in the posting refer to the behavior
***	  of SCO Xenix 2.2 and are not neccessarily compatible with SYS V!

	The device, to which the fd belongs to could be found out by
	getting the major and minor device numbers out of the first to bytes
	in the block-list of the above named inode-structure. Having the major
	device number you can look up the array of tty-structures from the
	cdevsw[] table.
	Now you index that array with the minor device number and finally get 
	the tty-structure. (Uff :-)

	Having this you can look, how many bytes are pending in the in/output
	queues and decide, what to do.

	NOTE: This is no fun - even if you have device drivers, indexing
	      their tty-structures not with the minor device number. And
	      that's mostly the case, where higher bits the minor-# state
	      the type of device being used. 

	If you only want to know about the availability of data on the
	controlling tty, you should refer to the related tty-structre
	via the pointer provided in the user-structure named u.u_ttyp!

Not an easy way - isn't it ???? ]:-}

AGAIN:	These are only thoughts - I tried all this and it all works on SCO,
	but I never (!!!) made a complete select() out of this. So all
	the stuff was only used fragmentarily.

For those of you reading this article in comp.unix.wizards: please respond
to me via email, because comp.unix.wizards is often too full for me so I
skip many articles ...

Clemens Schrimpe, netmbx GbR (Berlin, West-Germany)

UUCP: csch@tmpmbx = Europe: ...!unido!tmpmbx!csch, USA: ...!pyramid!tmpmbx!csch
BITNET:	csch@db0tui6	csch@tub.BITNET
PHONE:	+49-30-332 40 15
FAX:	+49-30-361 40 93
TELEX:	(066)+186672 net d
BTX:	0303325016-0003
MODEM:	+49-30-332 50 16 (V.22/V.22bis), +49-30-331 30 76/40 72 (V.21)
	Username: gast
X.25:	not stated herein (too many hackers around :-)

allbery@ncoast.UUCP (Brandon S. Allbery) (05/25/88)

As quoted from <7904@brl-smoke.ARPA> by gwyn@brl-smoke.ARPA (Doug Gwyn ):
+---------------
| In article <9738@sol.ARPA> jpayne@cs.rochester.edu (Jonathan Payne) writes:
| >I want to get input
| >from either the keyboard or from some other file description.  I don't
| >want to sit around polling the two, because that would be ridiculous.
| 
| If you set MIN and TIME to 0 in the terminal handler, then an attempt
| to read from the terminal with no data available will return immediately.
| There is nothing analogous for ordinary files.
+---------------

But that still leaves him polling.

Jon:  It's a bit ironic; the closest thing to a solution is something I've
been planning to do to "portsrv" in the Jove distribution.

Have your files opened by subprocesses:  one process per file.  They should
communicate with the parent process via a message queue.  Each does blocking
reads; when the read succeeds, the process should package it up in a message
with an ID field unique to the file/process (you can use dev/inode, process
ID, or anything else you choose as long as it's unique to each process).

The parent program then does a blocking msgrcv on the message queue.  When a
message comes in, the parent can examine the ID field to determine which
file it got the data from, and process it as appropriate.  If another
message comes in while the parent is processing, it will remain on the queue
until the parent gets around to issuing another msgrcv.

This is, alas, restricted to System V (I can think of some places where it'd
be useful on ncoast, but ncoast is System III).  There is *no* general
solution for System III, Xenix 3 or V7.  (You *could* use a FIFO to fake a
message queue under System III/Xenix 3, but now you're getting into nasty
complications.  And it's far easier to set up a two-way message queue than
it is to coordinate multiple FIFOs in a two-way connection, if you need it.
And FIFOs still aren't in pre-System III *nixes.)
-- 
	      Brandon S. Allbery, moderator of comp.sources.misc
	{well!hoptoad,uunet!marque,cbosgd,sun!mandrill}!ncoast!allbery
Delphi: ALLBERY						     MCI Mail: BALLBERY

gwyn@brl-smoke.ARPA (Doug Gwyn ) (05/25/88)

In article <7812@ncoast.UUCP> allbery@ncoast.UUCP (Brandon S. Allbery) writes:
>| If you set MIN and TIME to 0 in the terminal handler, then an attempt
>But that still leaves him polling.

Look, this is JOVE we're talking about, for Chrissakes!
The needed functionality is to "peek" to see if there is keyboard
input every so often while in the middle of a screen update loop,
so unnecessary screen output can be avoided.  The solution I gave
works just fine for that.  All these more complex schemes people
have been proposing are far less efficient.

ckl@uwbln.UUCP (Christoph Kuenkel) (05/26/88)

> jpayne@cs.rochester.edu (Jonathan Payne) writes:
> {} 
> {} Hi.  The simple version of my question is, is there an equivalent
> {} function in SysV for BSD's select()?
> {} If the answer is no, here's what I am trying to do.  I want to get input
> {} from either the keyboard or from some other file description.  I don't
> {} want to sit around polling the two, because that would be ridiculous.  Is
> {} there any reasonable way to do that on SysV?  
A blocking syscall blocks a process. so, if you like to wait for several
events at the same time, you need several processes. a solution to your
problem would be to fork off a watchdog that reads the keyboard and signals
his daddy when input arrives. the parent may then collect what had been read 
using system V ipc (msges, fifos or whatever). this works quite good unless
interrupted system call are a problem. also note that signals may get lost
in system 5 (upto rel 2).
if your have several input sources, you should setup a watchdog for any source
and establish something like a protocol between the watchdogs and the main
process. the watchdogs would then send requests to the main proc containing
the data received. the main process would block on a single input queue only.
if tty input is the most interesting thing, you should modify the watchdog
so that it only reads from the tty when requested by the main process. the
main process would do a time-out read from the tty and accept watchdog input
only if a time-out occured.

alvitar@madhat.UUCP (Phil Harbison) (05/27/88)

In article <2643@c3engr.UUCP>, charles@c3engr.UUCP (Charles Green) writes:
> 
> My favorite solution is to have several small "multiplexor" processes,
> all identical but exec()ed with a unique numeric argument, reading their
> respective stdins ... When one of the multiplexor processes completes a
> read(), he does a single write() to the pipe containing his unique ID,
> a byte count, and the data.
> 

I use a similar approach on my version of emacs to implement subprocesses
running in emacs windows.  It is a major win on the Sys5 version since the
previous approach used lots of CPU time doing NODELAY reads on the keyboard
and childs stdout pipe.  Another big win is I only have one version of the
code that runs on v7, BSD, and USG flavors of UNIX.  A nice side effect is
that polling the keyboard is simple, since I can do an fstat to discover
how much data is in the IPC pipe.  If anyone wants example code, drop me
a note in the mail.


-- 
Live: Phil Harbison
USPS: 3409 Grassfort Drive, Huntsville, AL 35805-5421
UUCP: clyde!madhat!alvitar
PSTN: 205-881-4317 or 205-830-4310x210