From owner-svn-src-all@FreeBSD.ORG Wed Feb 11 16:28:49 2009 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id B0DDF1065674; Wed, 11 Feb 2009 16:28:49 +0000 (UTC) (envelope-from ed@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 9E8A98FC25; Wed, 11 Feb 2009 16:28:49 +0000 (UTC) (envelope-from ed@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n1BGSnjE030502; Wed, 11 Feb 2009 16:28:49 GMT (envelope-from ed@svn.freebsd.org) Received: (from ed@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n1BGSndA030498; Wed, 11 Feb 2009 16:28:49 GMT (envelope-from ed@svn.freebsd.org) Message-Id: <200902111628.n1BGSndA030498@svn.freebsd.org> From: Ed Schouten Date: Wed, 11 Feb 2009 16:28:49 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r188487 - in head: sys/kern sys/sys usr.sbin/pstat X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 11 Feb 2009 16:28:50 -0000 Author: ed Date: Wed Feb 11 16:28:49 2009 New Revision: 188487 URL: http://svn.freebsd.org/changeset/base/188487 Log: 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 Modified: head/sys/kern/tty.c head/sys/sys/tty.h head/usr.sbin/pstat/pstat.8 head/usr.sbin/pstat/pstat.c Modified: head/sys/kern/tty.c ============================================================================== --- head/sys/kern/tty.c Wed Feb 11 15:55:01 2009 (r188486) +++ head/sys/kern/tty.c Wed Feb 11 16:28:49 2009 (r188487) @@ -438,15 +438,28 @@ ttydev_write(struct cdev *dev, struct ui 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'}, }; Modified: head/sys/sys/tty.h ============================================================================== --- head/sys/sys/tty.h Wed Feb 11 15:55:01 2009 (r188486) +++ head/sys/sys/tty.h Wed Feb 11 16:28:49 2009 (r188487) @@ -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. */ Modified: head/usr.sbin/pstat/pstat.8 ============================================================================== --- head/usr.sbin/pstat/pstat.8 Wed Feb 11 15:55:01 2009 (r188486) +++ head/usr.sbin/pstat/pstat.8 Wed Feb 11 16:28:49 2009 (r188487) @@ -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 Modified: head/usr.sbin/pstat/pstat.c ============================================================================== --- head/usr.sbin/pstat/pstat.c Wed Feb 11 15:55:01 2009 (r188486) +++ head/usr.sbin/pstat/pstat.c Wed Feb 11 16:28:49 2009 (r188487) @@ -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'}, };