fileno(stdin) versus STDIN_FILENO and friends

Peter Dufault dufault at hda.com
Sat Mar 12 21:29:45 UTC 2011


On Mar 12, 2011, at 12:02 , Ralf Corsepius wrote:

>> I think it would make more sense if stdin, stdout, and stderr are always files 0, 1, and 2,
> This is not safe to assume. stdin, stdout and stderr are FILE*'s and can 
> be redirected, repopened or even be closed.

You are correct.  Note that the reference you provided says about STDIN_FILENO, STDOUT_FILENO, and STDERR_FILENO (emphasis of "**" added):

"[CX] 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: opt-start.gif
Type: image/gif
Size: 69 bytes
Desc: not available
URL: <http://lists.rtems.org/pipermail/users/attachments/20110312/4f622464/attachment-0001.gif>
-------------- next part --------------
 The following symbolic values in <unistd.h> define the file descriptors that shall be associated with the C-language stdin, stdout, and stderr **when the application is started**:"

So 0, 1, and 2 AKA STDIN_FILENO, STDOUT_FILENO, and STDERR_FILENO are in effect when an application starts.  I assume application means process. I also notice that it says:

"Normally, there are three open streams with constant pointers declared in the <stdio.h> header and associated with the standard open files."

"Normally" is a weasel-word I wouldn't expect in a standard.  I'm not sure what they mean by constant, since those file pointers aren't declared const and you can compile:

        stderr = (FILE *)0;

without any complaint.

> 
>> that the underlying files are switched at context switch time, and that threads inherit whatever underlying files the creating thread may have dup'd them to.  Next in line would be to inherit the parent file descriptors.
>> 
>> Does anyone know about what the standards say about:
>> 
>> - stdin, stdout, stderr,
>> - file descriptors 0, 1, 2,
>> - STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO
>> 
>> and how this should play with pthreads?
> FILE* are per-process and not per-thread.

Except that stdin, stdout, and stderr are per-thread on RTEMS.  One thread can change the file descriptor underlying its stderr file pointer and it doesn't affect other threads stderr, including threads that are descendants of the one that did the change.  I haven't verified it, but I assume the complete context of the file pointer (seek pointers, etc) are switched.

"telnet" changes it's stderr to the stderr of the session, but descendants of that revert to the console (assuming that is what is opened on file descriptor 2).

Consider the following, with two commands added to the RTEMS shell, one to print the filenos for stdin, stdout, and stderr and the second to print "Hello world" to the stderr thread after becoming a thread, i.e.:

static void *hello(void *arg)
{
    fprintf(stderr, "Hello stderr!\n");
    return (void *)0;
}
static int
hello_stderr(int argc, char **argv)
{
    pthread_t t;
    pthread_create(&t, 0, hello, 0);
    return 0;
}

When run from the console the output is:

[/] # filenos                                                                                                                                                                                                                             
fileno(stdin),  STDIN_FILENO:  0 0                                                                                                                                                                                                         
fileno(stdout), STDOUT_FILENO: 1 1                                                                                                                                                                                                         
fileno(stderr), STDERR_FILENO: 2 2                                                                                                                                                                                                         
[/] # hello                                                                                                                                                                                                                               
[/] # Hello stderr!                                                                                                                                                                                                                       

When run from telnet the output is:

[/] # filenos
fileno(stdin),  STDIN_FILENO:  7 0
fileno(stdout), STDOUT_FILENO: 8 1
fileno(stderr), STDERR_FILENO: 9 2
[/] # hello
[/] # 

And you see this on the console:

syslog: telnetd: accepted connection from 192.168.240.6 on /dev/pty0                                                                                                                                                                       
Hello stderr!                                                                                                                                                                                                                             

So, stdin, stdout, and stderr are redirected per-thread, but descendants of the threads revert to 0, 1, and 2.  Is this in described by any standard?  If not, and we're just dealing with undefined behavior, is there any reason not to make it optional that descendants of a thread inherit the file descriptors for stdin, stdout, and stderr from the parent thread?  I'd find that behavior a lot more convenient, for example, threads started from telnet where the stderr went to the telnet window would still go to the telnet window.  I consider it important to route stdout and stderr to reasonable places, for example, an error log in a window some place, and I'm trying to setup an environment for less experienced users where things work well.

Peter
-----------------
Peter Dufault
HD Associates, Inc.      Software and System Engineering



More information about the users mailing list