From 7b4161bb50314582d70c48ca6dab0c0588c2d53e Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Thu, 8 Feb 2001 08:23:46 +0000 Subject: Document thread-related stream functions and contents of . --- manual/stdio.texi | 466 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 466 insertions(+) (limited to 'manual/stdio.texi') 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 @@ -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 -- cgit 1.4.1