Thread: select, named pipe and O_RDONLY

  1. #1
    Registered User
    Join Date
    Jun 2009
    Posts
    2

    select, named pipe and O_RDONLY

    hello!
    this little program get named fifo as arguments and print whatever someone will write into the pipes. Example:

    Code:
    mkfifo fifo1
    mkfifo fifo2
    ./es1 fifo1 fifo2
    
    cat > fifo1
    write here and my program will print out the lines
    i used a select to block onto the pipes. the strange thing is that, if i open the pipe in rdonly, and i write a char into the pipe (with cat, e.g.) and quit that program (ctrl+c on cat), select stucks and say that the named pipe is still ready for reading: so i continue to read 0 bytes from it (and cpu goes to 99%). but if i open the pipe in RDWR, select (and the whole program) goes normal (it will block if i quit cat). why?

    thank you very much

  2. #2
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    I'm far from an expert on this, but perhaps when you CTRL-C cat it doesn't close the pipe properly. What happens if you use CTRL-D to quit cat instead (which should result in normal exit)?

    [edit] By the way, post your code here on CBoard. More people will be inclined to help that way, and the code won't disappear. Here it is for posterity's sake.
    Code:
    /* Scrivere un programma C che prese in input da riga comando il pathname 
     * di molteplici FIFO (almeno 1, numero imprecisato) metta in output tutt
     * o cio' che arriva da qualsiasi di esse. Il programma non deve usare fo
     * rk ma una chiamata a scelta fra select o poll.
     */
    
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <sys/select.h>
    #include <limits.h>
    
    #define BUFFER PIPE_BUF
    
    int max(int a[], int num_elements)
    {
       int i, max = a[0];
       for (i=0; i<num_elements; i++)
       {
         if (a[i] > max)
         {
            max = a[i];
         }
       }
       return (max);
    }
    
    
    int main(int argc, char **argv)
    {
        register int i;
        int* fifos;
        int ready_fd;
        int nfds;
        int buff_count,count;
        fd_set fdset,tmpset;
        char buff[BUFFER];
        struct stat buf_fstat;
    
    //    buff = (char *)malloc(sizeof(char)*4096);
    
        if (argc==1) /* wrong usage of args*/
        {
            printf("Usage: ./a.out 1st-fifo-path [2nd-fifo-path] ... [n-fifo-path]\n");
            return(-1);
        }
        else /* right usage of args */
        {
            FD_ZERO(&fdset); /* clear the fd_set */
            fifos = (int*) malloc(sizeof(int) * (argc-1));
    
            for (i=0;i<argc-1;i++)
            {
                if ((fifos[i] = open(argv[i+1],O_RDWR|O_NONBLOCK))<0)
                {
                    perror("open");
                    return(-2);
                }
                else
                {
                    if (fstat(fifos[i],&buf_fstat))
                        perror("fstat");
                    else if (! S_ISFIFO(buf_fstat.st_mode))
                    {
                            printf("%s is not a pipe. Aborting\n",argv[i+1]);
                            return(-2);
                    }
                    else
                        FD_SET(fifos[i],&fdset);
                }
            }
    
            nfds = max(fifos,(argc-1))+1;
            memcpy((void *) &tmpset,(void *) &fdset, sizeof(fd_set));
    
            while (1)
            {
                /* we will use timeout=NULL to block indefinitely */
                if ((ready_fd = select(nfds,&fdset,NULL,NULL,NULL))<0)
                    perror("select");
                else
                {
                    #ifdef DEBUG
                        printf("ready fd: %d\n",ready_fd);
                    #endif
                    for (i=0,count=0;count<ready_fd||i<=(argc-1);i++)
                    {
                        if (FD_ISSET(fifos[i],&fdset))
                        {
                            count++;
                            #ifdef DEBUG
                                printf("fifo: %d\n",i);
                            #endif
                            if ((buff_count=read(fifos[i],&buff,BUFFER))<0) 
                                perror("read");
                            else
                            {
                                #ifdef DEBUG
                                    printf("read %d bytes\n",buff_count);
                                #endif
                                if (write(STDOUT_FILENO, buff, sizeof(char) * (unsigned int) buff_count)<0)
                                    perror("write");
                            }
                        }      
                    }
                    memcpy((void *) &fdset,(void *) &tmpset, sizeof(fd_set));
                }
            }
        }
    }
    [/edit]
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  3. #3
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Using O_NONBLOCK with select() is almost never the right thing to do. You want BLOCKING reads, and you are relying on select() to tell you when a read operation would NOT block. Remove O_NONBLOCK and see what happens.

    I'm not at all surprised that select() immediately returns when O_NONBLOCK is set. It's somewhat of a mystery why it does something different when opening in O_RDWR. I imagine that you're simply seeing unspecified behavior, triggered by the weirdness of opening a read-only end of a pipe in read-write mode. Don't do that!
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  4. #4
    Registered User
    Join Date
    Sep 2004
    Location
    California
    Posts
    3,268
    Using O_NONBLOCK with select() is almost never the right thing to do.
    This may be true with files, but it's definitely not true with socket file descriptors.

  5. #5
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by bithub View Post
    This may be true with files, but it's definitely not true with socket file descriptors.
    True. The interface is stupid and broken.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  6. #6
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by brewbuck View Post
    True. The interface is stupid and broken.
    Oh, now you tell us
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  7. #7
    Registered User
    Join Date
    Jun 2009
    Posts
    2
    Quote Originally Posted by brewbuck View Post
    Using O_NONBLOCK with select() is almost never the right thing to do. You want BLOCKING reads, and you are relying on select() to tell you when a read operation would NOT block. Remove O_NONBLOCK and see what happens.
    if i remove the O_NONBLOCK flag, open stucks waiting for fifo1 be ready.

  8. #8
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by MK27 View Post
    Oh, now you tell us
    It wasn't relevant. He's using pipes, not sockets.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  9. #9
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by alexfranci View Post
    if i remove the O_NONBLOCK flag, open stucks waiting for fifo1 be ready.
    Sounds like the proper behavior to me.

    You could open in nonblock mode, then use fcntl() to set it to blocking mode after that.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

Popular pages Recent additions subscribe to a feed

Tags for this Thread