kern/118287: [PATCH] tty write is not always atomic for small lines
Charles Hardin
chardin at 2wire.com
Tue Nov 27 10:00:05 PST 2007
>Number: 118287
>Category: kern
>Synopsis: [PATCH] tty write is not always atomic for small lines
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Tue Nov 27 18:00:02 UTC 2007
>Closed-Date:
>Last-Modified:
>Originator: Charles Hardin
>Release: FreedBSD-CURRENT
>Organization:
2Wire Inc.
>Environment:
>Description:
During test automation there has been some unexpected failures because output from different processes has been interspersed.
>How-To-Repeat:
Using the following test code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main(int argc, char **argv)
{
char buf[512];
int res, len;
if (daemon(0, 1) != 0) {
return 1;
}
len = snprintf(buf, sizeof(buf), "<This is writerd pid %d.>\n", getpid());
if (len >= sizeof(buf)) {
return 2;
}
while (1) {
res = write(1, buf, len);
if (res != len) {
return 3;
}
}
}
when running a couple copies of this, it sometimes prints out this:
<This is writerd pid 28.><This is writerd pid 30.>
<This is writerd pid 30.>
...more lines like that...
<This is writerd pid 30.>
<This is writerd pid 28.>
In other words, several writes from pid 30 happen in the middle of a write from
pid 28
>Fix:
So, the attached diff modifies the behavior of ttwrite to try and dump at least OBUFSIZ at a time in the clist so that lines shorter than OBUFSIZ should never be intermingled... This solves 99% of the cases and is easy enough for us to fix the user code to keep it solved...
Patch attached with submission follows:
Index: tty.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/tty.c,v
retrieving revision 1.273
diff -u -r1.273 tty.c
--- tty.c 20 Jul 2007 09:41:54 -0000 1.273
+++ tty.c 27 Nov 2007 17:49:13 -0000
@@ -2046,13 +2046,16 @@
int i, hiwat, cnt, error, s;
char obuf[OBUFSIZ];
- hiwat = tp->t_ohiwat;
cnt = uio->uio_resid;
error = 0;
cc = 0;
td = curthread;
p = td->td_proc;
loop:
+ /* set a slightly different hi water mark to transfer at least
+ * OBUFSIZ characters from the user write at a time.
+ */
+ hiwat = imax(tp->t_ohiwat - OBUFSIZ, tp->t_olowat);
s = spltty();
if (ISSET(tp->t_state, TS_ZOMBIE)) {
splx(s);
@@ -2165,7 +2168,7 @@
cp++;
cc--;
if (ISSET(tp->t_lflag, FLUSHO) ||
- tp->t_outq.c_cc > hiwat)
+ tp->t_outq.c_cc > tp->t_ohiwat)
goto ovhiwat;
continue;
}
@@ -2198,7 +2201,7 @@
goto loop;
}
if (ISSET(tp->t_lflag, FLUSHO) ||
- tp->t_outq.c_cc > hiwat)
+ tp->t_outq.c_cc > tp->t_ohiwat)
break;
}
ttstart(tp);
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list