Document thread-related stream functions and contents of <stdio_ext.h>.

This commit is contained in:
Ulrich Drepper 2001-02-08 08:23:46 +00:00
parent af1d26ca92
commit 7b4161bb50
2 changed files with 476 additions and 0 deletions

View File

@ -849,6 +849,16 @@ is not valid) or if @var{stream} does not do I/O to a file,
@code{fileno} returns @math{-1}.
@end deftypefun
@comment stdio.h
@comment GNU
@deftypefun int fileno_unlocked (FILE *@var{stream})
The @code{fileno_unlocked} function is equivalent to the @code{fileno}
function except that it does not implicitly lock the stream if the state
is @code{FSETLOCKING_INTERNAL}.
This function is a GNU extension.
@end deftypefun
@cindex standard file descriptors
@cindex file descriptors, standard
There are also symbolic constants defined in @file{unistd.h} for the

View File

@ -17,6 +17,7 @@ representing a communications channel to a file, device, or process.
devices are created for you.
* Opening Streams:: How to create a stream to talk to a file.
* Closing Streams:: Close a stream when you are finished with it.
* Streams and Threads:: Issues with streams in threaded programs.
* Simple Output:: Unformatted output by characters and lines.
* Character Input:: Unformatted input by characters and words.
* Line Input:: Reading a line or a record from a stream.
@ -369,6 +370,273 @@ might not be closed properly. Buffered output might not be flushed and
files may be incomplete. For more information on buffering of streams,
see @ref{Stream Buffering}.
In some situations it is useful to know whether a given stream is
available for reading or writing. This information is normally not
available and would have have to be remembered separately. Solaris
introduced a few functions to get this information from the stream
descriptor and these functions are also available in the GNU C library.
@comment stdio_ext.h
@comment GNU
@deftypefun int __freadable (FILE *@var{stream})
The @code{__freadable} function determines whether the stream
@var{stream} was opened to allow reading. In this case the return value
is nonzero. For write-only streams the function returns zero.
This function is declared in @file{stdio_ext.h}.
@end deftypefun
@comment stdio_ext.h
@comment GNU
@deftypefun int __fwritaable (FILE *@var{stream})
The @code{__fwritable} function determines whether the stream
@var{stream} was opened to allow writing. In this case the return value
is nonzero. For read-only streams the function returns zero.
This function is declared in @file{stdio_ext.h}.
@end deftypefun
For a slightly different kind of problems there are two more functions.
They provide even finer-grained information.
@comment stdio_ext.h
@comment GNU
@deftypefun int __freading (FILE *@var{stream})
The @code{__freading} function determines whether the stream
@var{stream} was last read from or whether it is opened read-only. In
this case the return value is nonzero, otherwise it is zero.
Determining whether a stream opened for reading and writing was last
used for writing allows to draw conclusions about the content about the
buffer, among other things.
This function is declared in @file{stdio_ext.h}.
@end deftypefun
@comment stdio_ext.h
@comment GNU
@deftypefun int __fwriting (FILE *@var{stream})
The @code{__fwriting} function determines whether the stream
@var{stream} was last written to or whether it is opened write-only. In
this case the return value is nonzero, otherwise it is zero.
This function is declared in @file{stdio_ext.h}.
@end deftypefun
@node Streams and Threads
@section Streams and Threads
@cindex threads
@cindex multi-threaded application
Streams can be used in multi-threaded applications in the same way they
are used in single-threaded applications. But the programmer must be
aware of a the possible complications. It is important to know about
these also if the program one writes never use threads since the design
and implementation of many stream functions is heavily influenced by the
requierements added by multi-threaded programming.
The POSIX standard requires that by default the stream operations are
atomic. I.e., issueing two stream operations for the same stream in two
threads at the same time will cause the operations to be executed as if
they were issued sequentially. The buffer operations performed while
reading or writing are protected from other uses of the same stream. To
do this each stream has an internal lock object which has to be
(implicitly) acquired before any work can be done.
But there are situations where this is not enough and there are also
situations where this is not wanted. The implicit locking is not enough
if the program requires more than one stream function call to happen
atomically. One example would be if an output line a program wants to
generate is created by several function calls. The functions by
themselves would ensure only atomicity of their own operation, but not
atomicity over all the function calls. For this it is necessary to
perform the stream locking in the application code.
@comment stdio.h
@comment POSIX
@deftypefun void flockfile (FILE *@var{stream})
The @code{flockfile} function acquires the internal locking object
associated with the stream @var{stream}. This ensure that no other
thread can explicitly through @code{flockfile}/@code{ftrylockfile} or
implicit through a call of a stream function lock the stream. The
thread will block until the lock is acquired. An explicit call to
@code{funlockfile} has to be used to release the lock.
@end deftypefun
@comment stdio.h
@comment POSIX
@deftypefun int ftrylockfile (FILE *@var{stream})
The@code{ftrylockfile} function tries to acquire the internal locking
object associated with the stream @var{stream} just like
@code{flockfile}. But unlike @code{flockfile} this function does not
block if the lock is not available. @code{ftrylockfile} returns zero if
the lock was successfully acquired. Otherwise the stream is locked by
another thread.
@end deftypefun
@comment stdio.h
@comment POSIX
@deftypefun void funlockfile (FILE *@var{stream})
The @code{funlockfile} function releases the internal locking object of
the stream @var{stream}. The stream must have been locked before by a
call to @code{flockfile} or a successful call of @code{ftrylockfile}.
The implicit locking performed by the stream operations do not count.
The @code{funlockfile} function does not return an error status and the
behavior of a call for a stream which is not locked by the current
thread is undefined.
@end deftypefun
The following example shows how the functions above can be used to
generate an output line atomically even in multi-threaded applications
(yes, the same job could be done with one @code{fprintf} call but it is
sometimes not possible):
@smallexample
FILE *fp;
@{
...
flockfile (fp);
fputs ("This is test number ", fp);
fprintf (fp, "%d\n", test);
funlockfile (fp)
@}
@end smallexample
Without the explicit locking it would be possible for another thread to
use the stream @var{fp} after the @code{fputs} call return and before
@code{fprintf} was called with the result that the number does not
follow the word @samp{number}.
From this description it might already be clear that the locking objects
in streams are no simple mutexes. Since locking the same stream twice
in the same thread is allowed the locking objects must be equivalent to
recursive mutexes. These mutexes keep track of the owner and the number
of times the lock is acquired. The same number of @code{funlockfile}
calls by the same threads is necessary to unlock the stream completely.
For instance:
@smallexample
void
foo (FILE *fp)
@{
ftrylockfile (fp);
fputs ("in foo\n", fp);
/* @r{This is very wrong!!!} */
funlockfile (fp);
@}
@end smallexample
It is important here that the @code{funlockfile} function is only called
if the @code{ftrylockfile} function succeeded in locking the stream. It
is therefore always wrong to ignore the result of @code{ftrylockfile}.
And it makes no sense since otherwise one would use @code{flockfile}.
The result of code like that above is that either @code{funlockfile}
tries to free a stream hasn't been locked by the current thread or it
frees the stream prematurely. The code should look like this:
@smallexample
void
foo (FILE *fp)
@{
if (ftrylockfile (fp) == 0)
@{
fputs ("in foo\n", fp);
funlockfile (fp);
@}
@}
@end smallexample
Now that we covered why it is necessary to have these locking it is
necessary to talk about siuations when locking is unwanted and what can
be done. The locking operations (explicit or implicit) don't come for
free. Even if a lock is not taken the cost is not zero. The operations
which have to be performed require memory operations which are save in
multi-processor environments. With the many local caches involved in
such systems this is quite costly. So it is best to avoid the locking
completely if it is known that the code using the stream is never used
in a context where more than one thread can use the stream at one time.
This can be determined most of the time for application code; for
library code which can be used in many contexts one should default to be
conservative and use locking.
There are two basic mechanisms to avoid locking. The first is to use
the @code{_unlocked} variants of the stream operations. The POSIX
standard defines quite a few of those and the GNU library adds a few
more. These variants of the functions behave just like the functions
with the name without the suffix except that they are not locking the
stream. Using these functions is very desirable since they are
potentially very much faster. This is not only because the locking
operation itself is avoided. More importantly, functions like
@code{putc} and @code{getc} are very simple and tradionally (before the
introduction of threads) were implemented as macros which are very fast
if the buffer is not empty. With locking required these functions are
now no macros anymore (the code generated would be too much). But these
macros are still available with the same functionality under the new
names @code{putc_unlocked} and @code{getc_unlocked}. This possibly huge
difference of speed also suggests the use of the @code{_unlocked}
functions even if locking is required. The difference is that the
locking then has to be performed in the program:
@smallexample
void
foo (FILE *fp, char *buf)
@{
flockfile (fp);
while (*buf != '/')
putc_unlocked (*buf++, fp);
funlockfile (fp);
@}
@end smallexample
If in this example the @code{putc} function would be used and the
explicit locking would be missing the @code{putc} function would have to
acquire the lock in every call, potentially many times depending on when
the loop terminates. Writing it the way illustrated above allows the
@code{putc_unlocked} macro to be used which means no locking and direct
manipulation of the buffer of the stream.
A second way to avoid locking is by using a non-standard function which
was introduced in Solaris and is available in the GNU C library as well.
@comment stdio_ext.h
@comment GNU
@deftypefun int __fsetlocking (FILE *@var{stream}, int @var{type})
The @code{__fsetlocking} function can be used to select whether the
stream operations will implicitly acquire the locking object of the
stream @var{stream}. By default this is done but it can be disabled and
reinstated using this function. There are three values defined for the
@var{type} parameter.
@vtable @code
@item FSETLOCKING_INTERNAL
The stream @code{stream} will from now on use the default internal
locking. Every stream operation with exception of the @code{_unlocked}
variants will implicitly lock the stream.
@item FSETLOCKING_BYCALLER
After the @code{__fsetlocking} function returns the user is responsible
for locking the stream. None of the stream operations will implicitly
do this anymore until the state is set back to
@code{FSETLOCKING_INTERNAL}.
@item FSETLOCKING_QUERY
@code{__fsetlocking} only queries the current locking state of the
stream. The return value will be @code{FSETLOCKING_INTERNAL} or
@code{FSETLOCKING_BYCALLER} depending on the state.
@end vtable
The return value of @code{__fsetlocking} is either
@code{FSETLOCKING_INTERNAL} or @code{FSETLOCKING_BYCALLER} depending on
the state of the stream before the call.
This function and the values for the @var{type} parameter are declared
in @file{stdio_ext.h}.
@end deftypefun
This function is especially useful when program code has to be used
which is written without knowledge about the @code{_unlocked} functions
(or if the programmer was to lazy to use them).
@node Simple Output
@section Simple Output by Characters or Lines
@ -388,6 +656,14 @@ The @code{fputc} function converts the character @var{c} to type
character @var{c} is returned.
@end deftypefun
@comment stdio.h
@comment POSIX
@deftypefun int fputc_unlocked (int @var{c}, FILE *@var{stream})
The @code{fputc_unlocked} function is equivalent to the @code{fputc}
function except that it does not implicitly lock the stream if the state
is @code{FSETLOCKING_INTERNAL}.
@end deftypefun
@comment stdio.h
@comment ISO
@deftypefun int putc (int @var{c}, FILE *@var{stream})
@ -398,6 +674,14 @@ general rule for macros. @code{putc} is usually the best function to
use for writing a single character.
@end deftypefun
@comment stdio.h
@comment POSIX
@deftypefun int putc_unlocked (int @var{c}, FILE *@var{stream})
The @code{putc_unlocked} function is equivalent to the @code{putc}
function except that it does not implicitly lock the stream if the state
is @code{FSETLOCKING_INTERNAL}.
@end deftypefun
@comment stdio.h
@comment ISO
@deftypefun int putchar (int @var{c})
@ -405,6 +689,14 @@ The @code{putchar} function is equivalent to @code{putc} with
@code{stdout} as the value of the @var{stream} argument.
@end deftypefun
@comment stdio.h
@comment POSIX
@deftypefun int putchar_unlocked (int @var{c})
The @code{putchar_unlocked} function is equivalent to the @code{putchar}
function except that it does not implicitly lock the stream if the state
is @code{FSETLOCKING_INTERNAL}.
@end deftypefun
@comment stdio.h
@comment ISO
@deftypefun int fputs (const char *@var{s}, FILE *@var{stream})
@ -428,6 +720,16 @@ fputs ("hungry?\n", stdout);
outputs the text @samp{Are you hungry?} followed by a newline.
@end deftypefun
@comment stdio.h
@comment GNU
@deftypefun int fputs_unlocked (const char *@var{s}, FILE *@var{stream})
The @code{fputs_unlocked} function is equivalent to the @code{fputs}
function except that it does not implicitly lock the stream if the state
is @code{FSETLOCKING_INTERNAL}.
This function is a GNU extension.
@end deftypefun
@comment stdio.h
@comment ISO
@deftypefun int puts (const char *@var{s})
@ -484,6 +786,14 @@ the stream @var{stream} and returns its value, converted to an
@code{EOF} is returned instead.
@end deftypefun
@comment stdio.h
@comment POSIX
@deftypefun int fgetc_unlocked (FILE *@var{stream})
The @code{fgetc_unlocked} function is equivalent to the @code{fgetc}
function except that it does not implicitly lock the stream if the state
is @code{FSETLOCKING_INTERNAL}.
@end deftypefun
@comment stdio.h
@comment ISO
@deftypefun int getc (FILE *@var{stream})
@ -494,6 +804,14 @@ optimized, so it is usually the best function to use to read a single
character.
@end deftypefun
@comment stdio.h
@comment POSIX
@deftypefun int getc_unlocked (FILE *@var{stream})
The @code{getc_unlocked} function is equivalent to the @code{getc}
function except that it does not implicitly lock the stream if the state
is @code{FSETLOCKING_INTERNAL}.
@end deftypefun
@comment stdio.h
@comment ISO
@deftypefun int getchar (void)
@ -501,6 +819,14 @@ The @code{getchar} function is equivalent to @code{getc} with @code{stdin}
as the value of the @var{stream} argument.
@end deftypefun
@comment stdio.h
@comment POSIX
@deftypefun int getchar_unlocked (void)
The @code{getchar_unlocked} function is equivalent to the @code{getchar}
function except that it does not implicitly lock the stream if the state
is @code{FSETLOCKING_INTERNAL}.
@end deftypefun
Here is an example of a function that does input using @code{fgetc}. It
would work just as well using @code{getc} instead, or using
@code{getchar ()} instead of @w{@code{fgetc (stdin)}}.
@ -643,6 +969,16 @@ a null character, you should either handle it properly or print a clear
error message. We recommend using @code{getline} instead of @code{fgets}.
@end deftypefun
@comment stdio.h
@comment GNU
@deftypefun {char *} fgets_unlocked (char *@var{s}, int @var{count}, FILE *@var{stream})
The @code{fgets_unlocked} function is equivalent to the @code{fgets}
function except that it does not implicitly lock the stream if the state
is @code{FSETLOCKING_INTERNAL}.
This function is a GNU extension.
@end deftypefun
@comment stdio.h
@comment ISO
@deftypefn {Deprecated function} {char *} gets (char *@var{s})
@ -835,6 +1171,16 @@ returns the number of complete objects read, and discards the partial
object. Therefore, the stream remains at the actual end of the file.
@end deftypefun
@comment stdio.h
@comment GNU
@deftypefun size_t fread_unlocked (void *@var{data}, size_t @var{size}, size_t @var{count}, FILE *@var{stream})
The @code{fread_unlocked} function is equivalent to the @code{fread}
function except that it does not implicitly lock the stream if the state
is @code{FSETLOCKING_INTERNAL}.
This function is a GNU extension.
@end deftypefun
@comment stdio.h
@comment ISO
@deftypefun size_t fwrite (const void *@var{data}, size_t @var{size}, size_t @var{count}, FILE *@var{stream})
@ -844,6 +1190,16 @@ normally @var{count}, if the call succeeds. Any other value indicates
some sort of error, such as running out of space.
@end deftypefun
@comment stdio.h
@comment GNU
@deftypefun size_t fwrite_unlocked (const void *@var{data}, size_t @var{size}, size_t @var{count}, FILE *@var{stream})
The @code{fwrite_unlocked} function is equivalent to the @code{fwrite}
function except that it does not implicitly lock the stream if the state
is @code{FSETLOCKING_INTERNAL}.
This function is a GNU extension.
@end deftypefun
@node Formatted Output
@section Formatted Output
@ -3072,6 +3428,16 @@ The @code{feof} function returns nonzero if and only if the end-of-file
indicator for the stream @var{stream} is set.
@end deftypefun
@comment stdio.h
@comment GNU
@deftypefun int feof_unlocked (FILE *@var{stream})
The @code{feof_unlocked} function is equivalent to the @code{feof}
function except that it does not implicitly lock the stream if the state
is @code{FSETLOCKING_INTERNAL}.
This function is a GNU extension.
@end deftypefun
@comment stdio.h
@comment ISO
@deftypefun int ferror (FILE *@var{stream})
@ -3080,6 +3446,16 @@ indicator for the stream @var{stream} is set, indicating that an error
has occurred on a previous operation on the stream.
@end deftypefun
@comment stdio.h
@comment GNU
@deftypefun int ferror_unlocked (FILE *@var{stream})
The @code{ferror_unlocked} function is equivalent to the @code{ferror}
function except that it does not implicitly lock the stream if the state
is @code{FSETLOCKING_INTERNAL}.
This function is a GNU extension.
@end deftypefun
In addition to setting the error indicator associated with the stream,
the functions that operate on streams also set @code{errno} in the same
way as the corresponding low-level functions that operate on file
@ -3106,6 +3482,16 @@ The file positioning functions (@pxref{File Positioning}) also clear the
end-of-file indicator for the stream.
@end deftypefun
@comment stdio.h
@comment GNU
@deftypefun void clearerr_unlocked (FILE *@var{stream})
The @code{clearerr_unlocked} function is equivalent to the @code{clearerr}
function except that it does not implicitly lock the stream if the state
is @code{FSETLOCKING_INTERNAL}.
This function is a GNU extension.
@end deftypefun
Note that it is @emph{not} correct to just clear the error flag and retry
a failed stream operation. After a failed write, any number of
characters since the last buffer flush may have been committed to the
@ -3634,12 +4020,55 @@ This function returns @code{EOF} if a write error occurs, or zero
otherwise.
@end deftypefun
@comment stdio.h
@comment POSIX
@deftypefun int fflush_unlocked (FILE *@var{stream})
The @code{fflush_unlocked} function is equivalent to the @code{fflush}
function except that it does not implicitly lock the stream if the state
is @code{FSETLOCKING_INTERNAL}.
@end deftypefun
The @code{fflush} function can be used to flush all streams currently
opened. While this is useful in some situations it does often more than
necessary since it might be done in situations when terminal input is
required and the program wants to be sure that all output is visible on
the terminal. But this means that only line buffered streams have to be
flushed. Solaris introduced a function especially for this. It was
always available in the GNU C library in some form but never officially
exported.
@comment stdio.h
@comment GNU
@deftypefun void _flushlbf (void)
The @code{_flushlbf} function flushes all line buffered streams
currently opened.
This function is declared in the @file{stdio_ext.h} header.
@end deftypefun
@strong{Compatibility Note:} Some brain-damaged operating systems have
been known to be so thoroughly fixated on line-oriented input and output
that flushing a line buffered stream causes a newline to be written!
Fortunately, this ``feature'' seems to be becoming less common. You do
not need to worry about this in the GNU system.
In some situations it might be useful to not flush the output pending
for a stream but instead simply forget it. If transmission is costly
and the output is not needed anymore this is valid reasoning. In this
situation a non-standard function introduced in Solaris and available in
the GNU C library can be used.
@comment stdio_ext.h
@comment GNU
@deftypefun void __fpurge (FILE *@var{stream})
The @code{__fpurge} function causes the buffer of the stream
@var{stream} to be emptied. If the stream is currently in read mode all
input in the buffer is lost. If the stream is in output mode the
buffered output is not written to the device (or whatever other
underlying storage) and the buffer the cleared.
This function is declared in @file{stdio_ext.h}.
@end deftypefun
@node Controlling Buffering
@subsection Controlling Which Kind of Buffering
@ -3764,6 +4193,43 @@ This function is provided for compatibility with old BSD code. Use
@code{setvbuf} instead.
@end deftypefun
It is possible to query whether a given stream is line buffered or not
using a non-standard function introduced in Solaris and available in the
GNU C library.
@comment stdio_ext.h
@comment GNU
@deftypefun int __flbf (FILE *@var{stream})
The @code{__flbf} function will return a nonzero value in case the
stream @var{stream} is line buffered. Otherwise the return value is
zero.
This function is declared in the @file{stdio_ext.h} header.
@end deftypefun
Two more extensions allow to determine the size of the buffer and how
much of it is used. These functions were also introduced in Solaris.
@comment stdio_ext.h
@comment GNU
@deftypefun size_t __fbufsize (FILE *@var{stream})
The @code{__fbufsize} function return the size of the buffer in the
stream @var{stream}. This value can be used to optimize the use of the
stream.
This function is declared in the @file{stdio_ext.h} header.
@end deftypefun
@comment stdio_ext.h
@comment GNU
@deftypefun size_t __fpending (FILE *@var{stream})
The @code{__fpending} function returns the number of bytes currently in
the output buffer. This function should not be used on buffers in read
mode or opened read-only.
This function is declared in the @file{stdio_ext.h} header.
@end deftypefun
@node Other Kinds of Streams
@section Other Kinds of Streams