stop pipe () abrindo stdin

2

Atualmente, tenho código que bifurca dois processos. O primeiro lê um rádio de streaming http e envia os dados por um pipe (aberto com pipe() ) para o segundo processo ler, decodificar e gerar saída para a placa de som usando OSS.

Eu tenho tentado depurar a parte de decodificação (problema separado) e me deparei com uma situação em que o pipe tem um descritor de arquivo de 0 quando eu imprimo. Tanto quanto eu posso dizer isso significa stdin. Este é um problema conhecido com pipe, que pode acidentalmente abrir um dos descritores de arquivo padrão? Se sim, como posso contornar isso?

Meu código de pipe / fork está abaixo. Há um pouco de outro código, que eu espero que seja irrelevante.

//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 don't 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;
    }

}

Esse loop é para que eu possa passar por uma lista de estações de rádio. Quando 'n' é pressionado, envia um comando para os dois processos-filhos que os encerram de maneira limpa e, em seguida, fecha todos os tubos e loops, abrindo-os novamente e forjando os dois processos novamente.

A primeira vez que passa pelo loop parece que isso funciona, mas na segunda vez eu recebo a seguinte saída.

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

Então, basicamente, eu gostaria de saber como parar o pipe ao abrir os descritores de arquivos std.

    
por Mark Underwood 16.01.2011 / 07:00

2 respostas

5

Um novo descritor de arquivo sempre ocupa o menor inteiro que ainda não está em uso.

$ 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

O sistema não se preocupa com "descritores de arquivo padrão" ou qualquer coisa assim. Se o descritor de arquivo 0 estiver fechado, um novo descritor de arquivo será atribuído em 0.

Existe algum lugar em seu programa ou em como você o está lançando que pode estar causando close(0) ?

    
por 16.01.2011 / 07:33
2

O Strace pode fornecer uma imagem do que seu executável está fazendo com os descritores de arquivos:

strace -f -e trace=file,desc,ipc -o /tmp/strace.txt /path/to/exe arg1 arg2...
    
por 16.01.2011 / 10:28