Subject: Re: tty dialin/dialout [PROPOSAL]
To: Paul A Vixie <paul@vix.com>
From: Charles M. Hannum <mycroft@mit.edu>
List: tech-kern
Date: 03/21/1998 07:00:10
[Skip to the `DANGER WILL ROBINSON!' if you only care about the actual
proposal.]


>> The problem with this is that it's highly dependent on timing.  If
>> getty starts to open the port while tip is running and has
>> successfully connected, it succeeds.  This is bad.
>
> This part I don't get.  Why would it succeed if another process has the
> port open?

Nothing prevents multiple processes from opening the same port.  To
make the getty block in this case, you'd need an additional state bit
indicating whether the device is currently open for dialin or dialout.
This would have to be set at the end of the open routine in the
successful case, based on whether O_NONBLOCK was set.

Of course, if you do this, then you really do have all the same logic
you'd have for SunOS-style split devices.  The only question is
whether you get that bit from the open flags, the minor number, or
somewhere else.  My inclination is to get it from the minor number,
since that doesn't pervert the meaning of the open flags, and it's
what most people expect now.


Also, I'll point out that I'm really guessing as to what the intent
was in 4.4.  The only thing that's really clear is that either it
wasn't trying to deal with this at all, or it was doing so in a
severely half-assed way that didn't actually work.  The only part
that's actually documented is the transition to WOPEN, and from WOPEN
to ISOPEN.  The 4.4 book is completely silent on the rest, and doesn't
even pay lipservice to so-called `bidirectional' ports.


[DANGER WILL ROBINSON!]

I'd suggest the following implementation:

* Rename the existing ttyopen() to ttylopen() (similar to
  ttyclose()/ttylcose()).

* Move the logic to wait for carrier into a new ttyopen(), which
  drivers then call rather than doing this themselves.

* Pass a bit to ttyopen() (derived whatever source we agree upon --
  THE SAME IN ALL DRIVERS) indicating whether this is a dialin or
  dialout open.

* Put the logic for handling dialin/dialout all inside ttyopen() and
  ttyclose().  Given the addition of TS_DIALIN and TS_DIALOUT bits,
  and assuming that ttyclose() just clears them, I believe the
  following is a sufficient implementation of ttyopen():

int
ttyopen(tp, dialout)
	struct tty *tp;
	int dialout;
{
	int s;

	s = spltty();

        if (dialout) {
		/*
		 * If we're opening for dialout use, there must not be any
		 * active dialin users.
		 */
		if (ISSET(tp->t_state, TS_DIALIN)) {
			splx(s);
			return (EBUSY);
		}
		SET(tp->t_state, TS_DIALOUT);
	} else {
		/*
		 * If we're opening for dialin use, wait for any dialout users
		 * to close the tty, and then wait for carrier.
		 */
		while (ISSET(tp->t_state, TS_DIALOUT) ||
		       (!ISSET(tp->t_state, TS_CARR_ON) && 
			!ISSET(tp->t_cflag, CLOCAL | MDMBUF))) {
			tp->t_wopen++;
			error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,
			    ttopen, 0);
			tp->t_wopen--;
			if (error) {
				splx(s);
				return (error);
			}
		}
		SET(tp->t_state, TS_DIALIN);
	}

	splx(s);
	return (0);
}

* (Actually, only two of TS_ISOPEN, TS_DIALIN and TS_DIALOUT are
  necessary, but I put them both in for demonstrational purposes.)