Serialize write() calls on TTYs.

Just like the old TTY layer, the current MPSAFE TTY layer does not make
any attempt to serialize calls of write(). Data is copied into the
kernel in 256 (TTY_STACKBUF) byte chunks. If a write() call occurs at
the same time, the data may interleave. This is especially likely when
the TTY starts blocking, because the output queue reaches the high
watermark.

I've implemented this by adding a new flag, TTY_BUSY_OUT, which is used
to mark a TTY as having a thread stuck in write(). Because I don't want
non-blocking processes to be possibly blocked by a sleeping thread, I'm
still allowing it to bypass the protection. According to this message,
the Linux kernel returns EAGAIN in such cases, but I think that's a
little too restrictive:

	http://kerneltrap.org/index.php?q=mailarchive/linux-kernel/2007/5/2/85418/thread

PR:		kern/118287
This commit is contained in:
Ed Schouten 2009-02-11 16:28:49 +00:00
parent 54fffe2d67
commit c0086bf202
4 changed files with 37 additions and 6 deletions

View File

@ -438,15 +438,28 @@ ttydev_write(struct cdev *dev, struct uio *uio, int ioflag)
if (tp->t_termios.c_lflag & TOSTOP) {
error = tty_wait_background(tp, curthread, SIGTTOU);
if (error) {
tty_unlock(tp);
return (error);
}
if (error)
goto done;
}
error = ttydisc_write(tp, uio, ioflag);
tty_unlock(tp);
if (ioflag & IO_NDELAY && tp->t_flags & TF_BUSY_OUT) {
/* Allow non-blocking writes to bypass serialization. */
error = ttydisc_write(tp, uio, ioflag);
} else {
/* Serialize write() calls. */
while (tp->t_flags & TF_BUSY_OUT) {
error = tty_wait(tp, &tp->t_bgwait);
if (error)
goto done;
}
tp->t_flags |= TF_BUSY_OUT;
error = ttydisc_write(tp, uio, ioflag);
tp->t_flags &= ~TF_BUSY_OUT;
cv_broadcast(&tp->t_bgwait);
}
done: tty_unlock(tp);
return (error);
}
@ -1880,6 +1893,11 @@ static struct {
{ TF_ZOMBIE, 'Z' },
{ TF_HOOK, 's' },
/* Keep these together -> 'bi' and 'bo'. */
{ TF_BUSY, 'b' },
{ TF_BUSY_IN, 'i' },
{ TF_BUSY_OUT, 'o' },
{ 0, '\0'},
};

View File

@ -83,6 +83,9 @@ struct tty {
#define TF_BYPASS 0x04000 /* Optimized input path. */
#define TF_ZOMBIE 0x08000 /* Modem disconnect received. */
#define TF_HOOK 0x10000 /* TTY has hook attached. */
#define TF_BUSY_IN 0x20000 /* Process busy in read() -- not supported. */
#define TF_BUSY_OUT 0x40000 /* Process busy in write(). */
#define TF_BUSY (TF_BUSY_IN|TF_BUSY_OUT)
unsigned int t_revokecnt; /* (t) revoke() count. */
/* Buffering mechanisms. */

View File

@ -206,6 +206,11 @@ block mode input routine in use
connection lost
.It s
i/o being snooped
.It b
busy in
.Xr read 2
or
.Xr write 2
.El
.Pp
The

View File

@ -315,6 +315,11 @@ static struct {
{ TF_ZOMBIE, 'Z' },
{ TF_HOOK, 's' },
/* Keep these together -> 'bi' and 'bo'. */
{ TF_BUSY, 'b' },
{ TF_BUSY_IN, 'i' },
{ TF_BUSY_OUT, 'o' },
{ 0, '\0'},
};