about summary refs log tree commit diff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2001-02-08 08:23:46 +0000
committerUlrich Drepper <drepper@redhat.com>2001-02-08 08:23:46 +0000
commit7b4161bb50314582d70c48ca6dab0c0588c2d53e (patch)
tree83182ba400c1c1a55c9297ca54320ebba3b64d82
parentaf1d26ca92c3048a5c6eeceb04cea6326610818d (diff)
downloadglibc-7b4161bb50314582d70c48ca6dab0c0588c2d53e.tar.gz
glibc-7b4161bb50314582d70c48ca6dab0c0588c2d53e.tar.xz
glibc-7b4161bb50314582d70c48ca6dab0c0588c2d53e.zip
Document thread-related stream functions and contents of <stdio_ext.h>.
-rw-r--r--manual/llio.texi10
-rw-r--r--manual/stdio.texi466
2 files changed, 476 insertions, 0 deletions
diff --git a/manual/llio.texi b/manual/llio.texi
index acfc929164..4efb552b8f 100644
--- a/manual/llio.texi
+++ b/manual/llio.texi
@@ -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
diff --git a/manual/stdio.texi b/manual/stdio.texi
index b2f46ba460..80d70a1b77 100644
--- a/manual/stdio.texi
+++ b/manual/stdio.texi
@@ -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
 
@@ -389,6 +657,14 @@ 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})
 This is just like @code{fputc}, except that most systems implement it as
@@ -399,6 +675,14 @@ 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})
 The @code{putchar} function is equivalent to @code{putc} with
@@ -406,6 +690,14 @@ The @code{putchar} function is equivalent to @code{putc} with
 @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})
 The function @code{fputs} writes the string @var{s} to the stream
@@ -429,6 +721,16 @@ 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})
 The @code{puts} function writes the string @var{s} to the stream
@@ -485,6 +787,14 @@ the stream @var{stream} and returns its value, converted to an
 @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})
 This is just like @code{fgetc}, except that it is permissible (and
@@ -495,12 +805,28 @@ 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)
 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)}}.
@@ -644,6 +970,16 @@ 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})
 The function @code{gets} reads characters from the stream @code{stdin}
@@ -836,6 +1172,16 @@ 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})
 This function writes up to @var{count} objects of size @var{size} from
@@ -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
 
@@ -3073,6 +3429,16 @@ 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})
 The @code{ferror} function returns nonzero if and only if the error
@@ -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