Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I've currently got code that forks two processes. The first reads a http streaming radio and pushes the data down a pipe (opened with pipe() ) for the second process to read, decode and output to the sound card using OSS.

I've been trying to debug the decoding part (separate issue) and I've come across a situation where the pipe has a file descriptor of 0 when I print it out. As far as I can tell this means stdin. Is this a known problem with pipe, that it can accidentally open one of the standard file descriptors? If so, how do I get around it?

My pipe/fork code is below. There is quite a bit of other code, that I hope is irrelevant.

//this is the "switch channel" loop
while(1)
{


    /*create the pipes
    *
    * httpPipe is for transfer of the stream between the readProcess and the playProcess
    *
    * playPPipe is for transfer of commands from the main process to the playProcess
    *
    * readPPipe is for transfer of commands from the main process to the readProcess
    *
    */


    if(pipe(httpPipe) == -1)
    {
        cout << "ERROR:: Error creating httpPipe: " << endl;
    }

    if(pipe(PlayPPipe) == -1)
    {
        cout << "ERROR:: Error creating PlayPPipe: " << endl;
    }
    if(pipe(ReadPPipe) == -1)
    {
        cout << "ERROR:: Error creating ReadPPipe: " << endl;
    }


    cout << "httpPipe:" << httpPipe[0] << ":" << httpPipe[1] << endl;
    cout << "PlayPPipe:" << PlayPPipe[0] << ":" << PlayPPipe[1] << endl;
    cout << "ReadPPipe:" << ReadPPipe[0] << ":" << ReadPPipe[1] << endl;


    pid = fork();
    if(pid == 0)
    {
        /* we are in the readProcess
        *  this process uses libcurl to read the icestream from the url
        *  passed to it in urlList. It then writes this data to writeHttpPipe.
        *  this continues until the "q" command is sent to the process via
        *  readPPipe/readReadPPipe. when this happens the curl Callback function
        *  returns 0, and the process closes all fds/pipes it has access to and cleans
        *  up curl and exits.
        */
        rc = 0;

        close(httpPipe[0]);
        writeHttpPipe = httpPipe[1];

        close(ReadPPipe[1]);
        readReadPPipe = ReadPPipe[0];

        rc = readProcess(urlList.at(playListNum));
        if(rc > 0)
        {
            cout << "ERROR:: has occured in reading stream: " << urlList.at(playListNum) << endl;
            close(writeHttpPipe);
            close(readReadPPipe);
            exit(16);
        }


    }else if(pid > 0)
    {
        pid = fork();
        if(pid ==0)
        {
            /* we are in the PlayProcess
             * the playProcess initialises libmpg123 and the OSS sound subsystem.
             * It then reads from httpPipe[0]/readHttpPipe until it recieves a "q" command
             * via PlayPPipe[0]/readPlayPPipe. at which point it closes all fd's and cleans
             * up libmpg123 handles and exits.
             */
            close(httpPipe[1]);
            sleep(1);

            close(PlayPPipe[1]);
            readPlayPPipe = PlayPPipe[0];

            playProcess();
            exit(0);

        }else if(pid > 0)
        {
            /* This is the main process
             *  this process reads from stdin for commands.
             *  if these are valid commands it processes this command and
             *  sends the relevant commands to the readProccess and the PlayProcess via
             *  the PlayPPipe[1]/writePlayPPipe and ReadPPipe[1]/writeReadPPipe.
             *  It then does suitable clean up.
             */
            string command;

            //close ends of pipe that we dont use.
            close(ReadPPipe[0]);
            close(PlayPPipe[0]);
            close(httpPipe[0]);
            close(httpPipe[1]);

            //assign write ends of pipes to easier variables
            writeReadPPipe = ReadPPipe[1];
            writePlayPPipe = PlayPPipe[1];
            rc = 0;

            //wait for input
            while(1)
            {
                cin >> command;
                cout << command << endl;

                rc = 0;

                /* Next channel command. this sends a q command to
                 * readProccess and playProcess to tell them to cleanup and exit().
                 * then it breaks out of the loop, increments the playListNum and
                 * we start all over again. The two processes get forked, this time with a new channel
                 * and we wait for input.
                 */
                if(command == "n")
                {
                    rc = sendCommand("q");
                    if(rc != 0)
                    {
                        cout << "ERROR: failed to send command: " << command << ":" << endl;
                    }
                    break;
                }

                /* Quit program command.
                 * This sends a command to the two proceesses to cleanup and exit() and then exits.
                 *
                 */
                if(command == "q")
                {
                    rc = sendCommand("q");
                    if(rc != 0)
                    {
                        cout << "ERROR: failed to send command: " << command << ":" << endl;
                    }
                    exit(0);
                }

            }
        }else
        {
            cout << "ERROR:: some thing happened with the fork to playProcess..." << endl;
        }
    }else
    {
        cout << "ERROR:: some thing happened with the fork to readProcess..." << endl;
    }

    //clean up the pipes otherwise we get junk in them.
    close(writePlayPPipe);
    close(writeReadPPipe);
    delete json;


    //Parse JSON got from the above url into the list of urls so we can use it
    JsonConfig *json = new JsonConfig(parms->GetParameter("URL"));
    json->GetConfigJson();
    json->ParseJson();
    json->GetUrls(urlList);

    cout << "####---->UrlListLength: " << urlList.size() << endl;

    //increment which url in the list we are going to be playing next.
    playListNum++;


    //if the playlist is greater than or equal to the urlist size then we are back at the start of the list
    if(playListNum >= (int)urlList.size())
    {

        playListNum = 0;
    }

}

This loop is so that I can go through a list of radio stations. When 'n' is pressed it sends a command to the two child processes which shut them down cleanly, and then closes all the pipes and loops back around, opening all them up again and forking the two processes again.

The first time it goes through the loop it seems like this works, but on the second time around I get the following output.

URL: 192.168.0.5:9000/playlist
GetConfigJsonurl: 192.168.0.5:9000/playlist
httpPipe:3:4
PlayPPipe:5:6
ReadPPipe:7:8
GetConfigJsonurl: 192.168.0.5:9000/playlist
####---->UrlListLength: 2
httpPipe:0:4
PlayPPipe:7:8
ReadPPipe:9:10

So basically I would like to know how to stop pipe from opening up the std file descriptors.

share|improve this question

2 Answers 2

up vote 5 down vote accepted

A new file descriptor always occupies the lowest integer not already in use.

$ cat >test.c
main(){exit(open("/dev/null",0));}
^D
$ cc test.c
$ ./a.out; echo $?
3
$ ./a.out <&-; echo $?
0
$ ./a.out >&-; echo $?
1

The system doesn't care about "standard file descriptors" or anything like that. If file descriptor 0 is closed, then a new file descriptor will be assigned at 0.

Is there any place in your program or in how you're launching it that may be causing close(0)?

share|improve this answer

strace can give you a picture of what your executable is doing with file descriptors:

strace -f -e trace=file,desc,ipc -o /tmp/strace.txt /path/to/exe arg1 arg2...
share|improve this answer
    
+1 although this didn't answer my questions it came in very handy! –  Mark Underwood Jan 18 '11 at 7:42

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.