[comp.unix.questions] Are terminal writes atomic?

stratton@hpcupt1.HP.COM (Jim Stratton) (09/24/89)

I have two processes doing simultaneous output to the same terminal using the
write system call.  Assume A does a write of 10 bytes while B does a write
of 30 bytes.  Can I be assured that A's and B's output will not be inter-
mixed?  I understand that for pipes, they won't be mixed.  How about terminals?
--
Jim Stratton		hplabs.hp.com!hpcupt1!stratton

spolsky-joel@CS.YALE.EDU (Joel Spolsky) (10/02/89)

In article <-286379999@hpcupt1.HP.COM> stratton@hpcupt1.HP.COM (Jim Stratton) writes:
>I have two processes doing simultaneous output to the same terminal using the
>write system call.  Assume A does a write of 10 bytes while B does a write
>of 30 bytes.  Can I be assured that A's and B's output will not be inter-
>mixed?  I understand that for pipes, they won't be mixed.  How about terminals?
>--
>Jim Stratton		hplabs.hp.com!hpcupt1!stratton


I think this is safe. A while ago I wrote a little program that runs
on a Unix host, and puts the time, date, and warns you if you get mail
in the status line of TVI950's or VT100's. This program runs quitely
in the background, and every once in a while sends the necessary
string to the terminal. Under extensive testing, it never interfered
with whatever foreground process was running, even when it had to
write a whole 80 character string to the status line every second. The
write() commands were preserved atomically.

Now, this is on Sun-OS 4.0, it might not work on your system, and I
don't know how to "prove" that it always works, but it has for me.

+----------------+----------------------------------------------------------+
|  Joel Spolsky  | bitnet: spolsky@yalecs.bitnet     uucp: ...!yale!spolsky |
|                | internet: spolsky@cs.yale.edu     voicenet: 203-436-1538 |
+----------------+----------------------------------------------------------+
                                                      #include <disclaimer.h>

mark@promark.UUCP (Mark J. DeFilippis) (10/03/89)

In article <1118@cs.yale.edu>, spolsky-joel@CS.YALE.EDU (Joel Spolsky) writes:
> I think this is safe. A while ago I wrote a little program that runs
> on a Unix host, and puts the time, date, and warns you if you get mail
> in the status line of TVI950's or VT100's.
> write() commands were preserved atomically.
> 

How about we take this further.  The answer to this question is an
undocumented feature of write() under Unix.  Several Authors note
that write() is atomic under Unix and that it is undocumented.
One is Marc J. Rochkind in his book _Advanced Unix Programming_,
Prentice-Hall.  Writes are Atomic, no matter what you are writing to,
even terminals.

However, if you have two processes writing to the same device simultaneously,
you cannot guarantee which one will preceed the other, (assuming no
formal communication  between the two processes course).

-- 
Adelphi University, Garden City, NY 11530                   (516) 663-1170
Department of Mathematics and Computer Science
                                 markd@adelphi.UUCP  or  mark@promark.UUCP
                      UUCP:      ...philabs!sbcs!bnlux0!adelphi!markd

chris@mimsy.UUCP (Chris Torek) (10/04/89)

In article <186@promark.UUCP> mark@promark.UUCP (Mark J. DeFilippis) writes:
>How about we take this further.  The answer to this question is an
>undocumented feature of write() under Unix.  Several Authors note
>that write() is atomic under Unix and that it is undocumented.
>One is Marc J. Rochkind in his book _Advanced Unix Programming_,
>Prentice-Hall.  Writes are Atomic, no matter what you are writing to,
>even terminals.

Of course, it might be undocumented because it is false.

On Berkeley systems (4BSD, at least), writes to character devices are
not locked at the syscall level, and hence could be reentered if the
driver (cdevsw[].d_write) function sleeps.  Tty writes all go through
`ttwrite()', which has two ways of sleeping: if the tty output queue
is over the `high water' mark, or if the machine runs out of clist
blocks.

The sleep queues are priority-FIFO, so if two processes sleep for the
same reason, the first one wins when a wakeup() happens (since they are
sleeping at the same priority).  But if one sleeps on lbolt while
another is sleeping on outq/high-water-mark (if this condition is even
possible), they might wake up in the `wrong' order and intermix
output.

Anyway, I am not going to try to figure out whether it never happens,
just remark that it is at least theoretically possible.  `If it ain't
documented, don't trust it'.  (Of course even if it is documented,
you might do well not to trust it anyway.)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

clyde@hitech.ht.oz (Clyde Smith-Stubbs) (10/06/89)

From article <186@promark.UUCP>, by mark@promark.UUCP (Mark J. DeFilippis):
> In article <1118@cs.yale.edu>, spolsky-joel@CS.YALE.EDU (Joel Spolsky) writes:
>> I think this is safe. A while ago I wrote a little program that runs
> 
> How about we take this further.  The answer to this question is an
> undocumented feature of write() under Unix.  Several Authors note
> that write() is atomic under Unix and that it is undocumented.

Rubbish! Writes to terminals under Unix are not, and have never been,
in any way atomic. In many cases they will be atomic, but there
is nothing in the structure of the system to guarantee this. It is easy
to demonstrate a situation where they are not atomic. Try the following
program: (If run on e.g. the memory mapped display of a 386 PC then the
writes will be atomic - but on a serial terminal, or anything that uses
buffering and interrupts, they will not be).

char x[25][61];
main()
{
	char	c;
	int	i, j;

	if(fork())
		c = 'A';
	else
		c = '.';
	for(i = 0 ; i != 25 ; i++) {
		for (j = 0 ; j != 60 ; j++)
			x[i][j] = c;
		x[i][j] = '\n';
	}
	for(;;)
		write(1, x, sizeof(x));
}

For the explanation, here is the mail I sent to Jim Stratton after his
original posting:

From clyde Tue Sep 26 14:32:58 1989
To: stratton@hpcupt1.HP.COM

Subject: Re: Are terminal writes atomic?

stratton@hpcupt1.HP.COM (Jim Stratton):
> I have two processes doing simultaneous output to the same terminal using the
> write system call.  Assume A does a write of 10 bytes while B does a write
> of 30 bytes.  Can I be assured that A's and B's output will not be inter-
> mixed?  I understand that for pipes, they won't be mixed.  How about terminals?

No, you can't assume that. It depends on how much output is going to the
terminal. If the terminal output queue reaches the high water mark the current
process will be suspended. When the queue drops to the low water mark all
processes waiting on that terminal will be woken. Which one gets to write some
more output first is indeterminate.
------------------------
Clyde Smith-Stubbs
HI-TECH Software, P.O. Box 103, ALDERLEY, QLD, 4051, AUSTRALIA.

ACSnet:		clyde@hitech.ht.oz
INTERNET:	clyde@hitech.ht.oz.au		PHONE:	+61 7 300 5011
UUCP:		uunet!hitech.ht.oz.au!clyde	FAX:	+61 7 300 5246
-- 
Clyde Smith-Stubbs
HI-TECH Software, P.O. Box 103, ALDERLEY, QLD, 4051, AUSTRALIA.
INTERNET:	clyde@hitech.ht.oz.au		PHONE:	+61 7 300 5011
UUCP:		uunet!hitech.ht.oz.au!clyde	FAX:	+61 7 300 5246

mark@promark.UUCP (Mark J. DeFilippis) (10/08/89)

In article <19972@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes:
> In article <186@promark.UUCP> mark@promark.UUCP (Mark J. DeFilippis) writes:
> >How about we take this further.  The answer to this question is an
> >undocumented feature of write() under Unix.  Several Authors note this
> 
> Of course, it might be undocumented because it is false.
> 
> On Berkeley systems (4BSD, at least), writes to character devices are

Indeed I should have qualified my statement, however almost everyone is
familiar with Rochkind's _Advanced Unix Programming_ book, and they are
aware it is a SYSTEM V book, not a 4BSD Unix book.
Under System V, it is a known undocumented item.  By undocumented, I mean
it was left out of the documentation and under ALL true Unix System V systems,
atomic writes at the system call level are guaranteed. Yes, 4BSD is different
and causes much grief with which I am familiar with.  That is why I am glad
that most porting I do is from 4.XBSD to System V, and not the other
way around!  I assume you don't get out from under 4.XBSD that often huh?

-- 
Adelphi University, Garden City, NY 11530                   (516) 663-1170
Department of Mathematics and Computer Science
                                 markd@adelphi.UUCP  or  mark@promark.UUCP
                      UUCP:      ...philabs!sbcs!bnlux0!adelphi!markd

cpcahil@virtech.UUCP (Conor P. Cahill) (10/08/89)

In article <191@promark.UUCP>, mark@promark.UUCP (Mark J. DeFilippis) writes:
> In article <19972@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes:
> > In article <186@promark.UUCP> mark@promark.UUCP (Mark J. DeFilippis) writes:
> > >How about we take this further.  The answer to this question is an
> > >undocumented feature of write() under Unix.  Several Authors note this
> > 
> > Of course, it might be undocumented because it is false.
> > 
> > On Berkeley systems (4BSD, at least), writes to character devices are
> 
> Indeed I should have qualified my statement, however almost everyone is
> familiar with Rochkind's _Advanced Unix Programming_ book, and they are
> aware it is a SYSTEM V book, not a 4BSD Unix book.
> Under System V, it is a known undocumented item.  By undocumented, I mean
> it was left out of the documentation and under ALL true Unix System V systems,
> atomic writes at the system call level are guaranteed.

NO THIS IS NOT TRUE. Writes are not atomic.  To prove the point I threw the 
following example program together:

	#define BUFSIZE 2048
	main()
	{
		char	buffer[BUFSIZE+1];
		int	i;

		if( fork() == 0 )
		{
			for(i=0; i < BUFSIZE; i++)
				buffer[i] = '0';
			buffer[i++] = '\n';

			write(1,buffer,i);
			exit(0);
		}
		for(i=0; i < BUFSIZE; i++)
			buffer[i] = '1';
		buffer[i++] = '\n';

		write(1,buffer,i);
		exit(0);
	}

On my "true" system V (AT&T System V/386 Release 3.2) this resulted in 
mixed output.  I don't care what someones book says, the real thing says
that it is not atomic.

Try this on your system and see what you get.  

-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9247	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

wgb@tntdev.tnt.COM (William G. Bunton) (10/08/89)

On 7 Oct 89 19:17:44 GMT,
mark@promark.UUCP (Mark J. DeFilippis) said:
Mark> Summary: I should have qualifed this...

Mark> In article <19972@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes:
> In article <186@promark.UUCP> mark@promark.UUCP (Mark J. DeFilippis) writes:
> >How about we take this further.  The answer to this question is an
> >undocumented feature of write() under Unix.  Several Authors note this
> 
> Of course, it might be undocumented because it is false.
> 
> On Berkeley systems (4BSD, at least), writes to character devices are

Mark> Indeed I should have qualified my statement, however almost
Mark> everyone is familiar with Rochkind's _Advanced Unix Programming_
Mark> book, and they are aware it is a SYSTEM V book, not a 4BSD Unix
Mark> book.  Under System V, it is a known undocumented item.  By
Mark> undocumented, I mean it was left out of the documentation and
Mark> under ALL true Unix System V systems, atomic writes at the
Mark> system call level are guaranteed. Yes, 4BSD is different and
Mark> causes much grief with which I am familiar with.  That is why I
Mark> am glad that most porting I do is from 4.XBSD to System V, and
Mark> not the other way around!  I assume you don't get out from under
Mark> 4.XBSD that often huh?

But Mark, it isn't true under System V, either.  Bach says (Design of
the UNIX Operating System) section 10.3.2, page 33:

"Output data could also be garbled at a terminal because a writing
process may sleep in the middle of a *write* system call while waiting
for previous output data to drain from the system.  The kernel could
schedule other processes that *write* the terminal before the original
process is rescheduled.  Because of this case, the kernel does *not*
guarantee that the contents of the data buffer to be output by a
*write* system call appear contiguously on the terminal."

Note the emphasis is his, not mine.  I think this is why atomic
terminal writes are not documented for System V: because they are not
guaranteed atomic.

Bill
-- 
William G. Bunton                                        wgb@tntdev.tnt.com
Tools & Techniques, Inc. Austin, TX        {cs.utexas.edu,uunet}!tntdev!wgb

mark@promark.UUCP (Mark J. DeFilippis) (10/09/89)

In article <411@hitech.ht.oz>, clyde@hitech.ht.oz (Clyde Smith-Stubbs) writes:
> From article <186@promark.UUCP>, by mark@promark.UUCP (Mark J. DeFilippis):
> > In article <1118@cs.yale.edu>, spolsky-joel@CS.YALE.EDU (Joel Spolsky) writes:
> >> I think this is safe. A while ago I wrote a little program that runs
> > 
> > How about we take this further.  The answer to this question is an
> > undocumented feature of write() under Unix.  Several Authors note
> > that write() is atomic under Unix and that it is undocumented.
> 
> Rubbish! Writes to terminals under Unix are not, and have never been,
> in any way atomic. In many cases they will be atomic, but there
> is nothing in the structure of the system to guarantee this. It is easy
> [program followed]

Sorry, Under my Unix system V, and my Xenix system as well as
SCO UNIX system V, your program yeilds atomic writes.  However,
this is a coeincidence.  Someone else provided a program 3 articles
after yours which woke me up.
Plus my boss said to me, "Mark, where is your mind? Remember that
application you wrote 3 months ago and the semaphores you had to use to
control simulatneous access by multiple writes?"

I went back to the Rochkind book I mentioned, which I should have done in
the first place, to see where my neural net got it's cross circuit.
He states:

"It is presumably a goal of the /usr/group standards effort to document
important properties like the atomicity of creat, open, and write, But their
proposed standard does not do so.  If this omission is deliberate - that is,
a conforming implimentation does _not_ have to ensure that these systems
calls are atomic, then the standard is seriously defective."

This is a footnote in the book when discussing "The Unix manual fails to
state that writes to files opened with O_APPEND are atomic." However vendors
are only bound by the manual for their implimentation.  "Whats worse, even
a system that doesn't force open and write to be atomic will still act
that way 99 percent of the time, making the bug maddeningly elusive."

A totally different story. Sorry about the confusion, and thanks to those
whose minds were on guard for setting me straight.  I should have known
this stuff anyway, since I have had to impliment semaphores for exactly this
reason in the past.  Sometimes the mind wanders, thats one of the reasons
why we have auto accidents...

Again, my apologies 
-- 
Adelphi University, Garden City, NY 11530                   (516) 663-1170
Department of Mathematics and Computer Science
                                 markd@adelphi.UUCP  or  mark@promark.UUCP
                      UUCP:      ...philabs!sbcs!bnlux0!adelphi!markd

guy@auspex.auspex.com (Guy Harris) (10/10/89)

>Indeed I should have qualified my statement, however almost everyone is
>familiar with Rochkind's _Advanced Unix Programming_ book, and they are
>aware it is a SYSTEM V book, not a 4BSD Unix book.
>Under System V, it is a known undocumented item.  By undocumented, I mean
>it was left out of the documentation and under ALL true Unix System V systems,
>atomic writes at the system call level are guaranteed.

And you believe that, in fact, *terminal* writes are atomic on S5?  I
don't - and I've checked the S5R3 code.  While S5 *does*, in fact, lock
the inode on "read"s and "write"s in some cases - as does 4.3BSD, in
fact - neither of them do so if the file is a character special file,
which terminals are.  Chris Torek's scenario appears to apply to S5 as
well.