Ambiguous sentence in POSIX onlinepubs 11.1.11

Bruce Evans brde at
Fri Mar 28 16:06:39 PDT 2008

On Fri, 28 Mar 2008, Ed Schouten wrote:

> The last couple of days I've been reading the POSIX onlinepubs now and
> then to find out how my new mpsafe TTY implementation conforms to POSIX.

Also run a conformance test.  I tested the sio and cy drivers with NIST
PCTS.  POSIX now has its own conformance tests but I haven't tried those.

> In section 11.1.11, there is the following sentence:
> 	"The last process to close a terminal device file shall cause
> 	any output to be sent to the device and any input to be
> 	discarded."
> This sentence is quite ambiguous. It could mean:
> 	"The last process to close a terminal device file shall cause
> 	any output to be sent to the device, [but] any input to be
> 	discarded."
> but it could also mean:
> 	"The last process to close a terminal device file shall cause
> 	any output [which still has] to be sent to the device and any
> 	input to be discarded."
> I know FreeBSD currently implements the first behaviour. It drains
> output on closure, but how can we know for sure this is the correct
> behaviour?

I think it means the first behaviour.  If it meant flushing output then
it shouldn't say "to be sent to the device".  Anyway, waiting for output
to drain has been the default in BSD since at least 1988, and standards
shouldn't change that.

The rationale in 1966 contradicts the above slightly (though POSIX.1-1996
says the above too).  From the PCTS source code quoting POSIX.memble
(the quote matches POSIX.1-1996 B.7.1.11):

     			POSIX.1 is silent on whether a close() will block on waiting
     			for transmission to drain, or even if a close() might cause
     			a flush of pending output.  If the application is concerned
     			about this, it should call the appropriate function, such as
     			tcdrain(), to ensure the desired behavior.

This contradicts both interpretations of the standard, since if the standard
requires output to be sent then sending it but flushing it is an unreasonable
interpretation, while if the standard requires flushing then it is not

The standard is only silent on whether sending requires full blocking like
tcdrain() would do and BSD almost does (old BSD can block forever, wasting
lots of phone connection or modem resources, but FreeBSD has a timeout;
the implementation of this timeout is not quite right, since it affects
tcdrain() (not just last-close from exit() where it is most needed), and
it gives an undocumented errno for tcdrain()).

The rationale in POSIX.1.2001-draf7 is quite different from the above:

2823 A.11.1.11Closing a Terminal Device File
2824              IEEE Std 1003.1-200x does not specify that a close( ) on a terminal device file include the
2825              equivalent of a call to tcflow(fd,TCOON).
2826              An implementation that discards output at the time close( ) is called after reporting the return
2827              value to the write( ) call that data was written does not conform with IEEE Std 1003.1-200x. An
2828              application has functions such as tcdrain( ), tcflush( ), and tcflow( ) available to obtain the detailed
2829              behavior it requires with respect to flushing of output.
2830              At the time of the last close on a terminal device, an application relinquishes any ability to exert
2831              flow control via tcflow( ).

This mentions tcflow() but not tcdrain().  I interpret this as meaning
that the wording is now considered unambiguous and unsilent, since
tcflow() is irrelevant if the output must be flushed, but tcflow() is
very relevant if the output has been stopped by tcflow(...TCOOF) --
then the program has asked for an infinite blockage.

Ah, it gives one case where output must not be flushed -- if write() has
succeeded.  This covers the usual case of buffered writes.  I don't see
how there can be any output "to be sent" unless a previous buffered
write has queued it and has succeeded, except possibly in some non-POSIX
exceptional cases involving things like revoke().  Otherwise, last-close
cannot be called while there are writes in progress.

11.1.11 in .2001-draft7 and 7.1.11 in .1996 also require HUPCL to work.
The timing of asserting HUP (dropping DTR) is unclear.  The receiver
is required to flush input when it sees the HUP so draining output
after asserting HUP would be useless.  BSD drains output first.

The PCTS sources (file 7.1.1_69.c) have more comments about this.  The
test seems to cover generation of hangup on the sender according to
HUPCL and the receiver's processing of hangup.  Hmm, one of the comments
claims that draining/flushing of output is irrelevant in the HUPCL
case, since the receiver is required to flush input.  But this depends
on the timing.  The receiver is quite likely to handle hangup
asynchronously before handling all input, so it would flush input even
if the sender generates the hangup synchronously after flushing all the
output, but it might not.


More information about the freebsd-standards mailing list