tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Regarding read behaviour of a FIFO



Hi Christos,

     Thanks a lot for your reply, I was desperately looking for one :)

     First of all, sorry that I can not reply to your mail as I am not
subscribed to the teck-kern mailing list and I did not get your reply
on my mail account. I got to know about this from teck-kern mailing
archives. So I am replying to my own mail. Can you please CC to my
gmail id when you reply?

     I have created a small program which uses a FIFO between a parent
and child process and I could reproduce the issue with this simple
program.

     I am attaching the program as well as the output of the same I
got. To start with, I was trying with small number of messages and I
did not see it that time so I increased the number of messages to 200
and then I saw it. You may want to change this if you cannot reproduce
the same.

Regards,
Bharat

Program:
========

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <sys/wait.h>

#define FIFO_FILE_PATH       "./fifo_file"
#define NUM_MESSAGES         200
#define MSG_SIZE             24
#define MESSAGE              "I am fine"

/*
 * _child_writer
 *
 * Function that runs in child context and opens and write to the FIFO.
 */

static int
_child_writer( void )
{
        int        ret;
        int        file_no;
        int        count;
        char       message[MSG_SIZE] = MESSAGE;

        /* Open the fifo in write-mode */
        do {
                file_no = open( FIFO_FILE_PATH, O_WRONLY, 0 );

                if ( file_no < 0 ) {
                        if ( errno == EINTR ) {
                                continue;
                        } else {
                                printf("Child: Failed to open the fifo in write 
mode: %d\n",
                                       errno );
                                exit( errno );
                        }
                }

                /* Read mode is opened */
                break;

        } while( 1 );

        for ( count = 0; count < NUM_MESSAGES; count++ ) {

                ret = write( file_no, message, MSG_SIZE);

                if ( ret < 0 ) {
                        printf("Child: Failed to write: %d\n", errno );
                        break;
                }

                sleep(1);
        }

        close( file_no );
        printf("Child: Closed the fifo file\n");
        exit(0);

}

/*
 * _sigchild_handler
 *
 * Called when a sigchild is delivered
 */
static void
_sigchild_handler( int    signo )
{

        if ( signo == SIGCHLD ) {
                printf("Got sigchild\n");
        } else {
                printf("Got %d signal\n", signo );
        }

}

/* Main of the program */
int
main(int argc, char **argv )
{
        pid_t              pid;
        int                ret;
        int                file_no;
        int                status;
        int                buf_size = MSG_SIZE;
        char               buf[MSG_SIZE];
        struct sigaction   action;

        /* Catch sigchild Signal */
        action.sa_sigaction = NULL;
        action.sa_handler   = _sigchild_handler;
        action.sa_flags     = 0;
        sigemptyset( &action.sa_mask );

        ret = sigaction( SIGCHLD, &action, NULL );

        if ( ret < 0 ) {
                printf("Failed to register for signal: %d\n", errno );
                exit(errno);
        }

        /* First create a fifo */
        ret = mkfifo( FIFO_FILE_PATH, S_IRUSR | S_IWUSR );

        if ( ret < 0 ) {
                printf("Failed to create fifo file. %d\n", errno );
                exit( errno );
        }

        pid = fork();

        if ( pid < 0 ) {
                printf("Failed to fork: %d\n", errno );
                exit( errno );
        } else if ( pid == 0 ) {

                /* Open the file in write mode so that subsequent read from 
parent side
                 * does not block the parent..
                 */
                file_no = open( FIFO_FILE_PATH, O_WRONLY, 0 );

                if ( file_no < 0 ) {
                        printf("Failed to open fifo in write mode in start: 
%d\n", errno );
                        exit(errno);
                }

                /* In child */
                _child_writer();
        }

        printf("Child pid is %d\n", pid );

        /* In parent */
        do {
                file_no = open( FIFO_FILE_PATH, O_RDONLY, 0 );

                if ( file_no < 0 ) {
                        if ( errno == EINTR ) {
                                continue;
                        } else {
                                printf("Failed to open the fifo in read mode: 
%d\n", errno );
                                exit( errno );
                        }
                }

                /* Read mode is opened */
                break;

        } while( 1 );

        sleep(10);
        printf("Was sleeping...\n");

        do {

                ret = read( file_no, buf, buf_size );

                if ( ret < 0 ) {
                        printf("Failed to read. %d\n", errno );
                        if ( errno == EINTR ) {
                                printf("Parent interrupted, continuing...\n" );
                                continue;
                        }

                        break;
                }

                if ( ret == 0 ) {
                        printf("Writers have closed, looks like we are done\n");
                        break;
                }

                printf("Received %d bytes message '%s'\n", ret, buf );

        } while(1);

        close( file_no );

        printf("We are done.. now reap the child\n");

        // Read the child...
        ret = waitpid( pid, &status, 0 );

        if ( ret < 0 ) {
                printf("Failed to reap the child\n");
        } else {
                printf("We are done completely\n");
        }

        exit(0);
}

Output:
======

# fifotest
Child pid is 282
Child: Closed the fifo file
Got sigchild
Was sleeping...
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Writers have closed, looks like we are done
We are done.. now reap the child
We are done completely
# rm fifo_file
#
#
# fifotest
Child pid is 334
Was sleeping...
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Received 24 bytes message 'I am fine'
Child: Closed the fifo file
Got sigchild
Failed to read. 4
Parent interrupted, continuing...


On Sun, Dec 18, 2011 at 9:22 PM, Bharat Joshi <bharat.josh%gmail.com@localhost> 
wrote:
> Hi,
>
>       It has been some time and I did not get any response for the
> below question.
>
>       I am not subscribed to the NetBSD tech-kern mailing list but I
> have been checking the mailing list archive to make sure that I have
> not missed any responses.
>
>       I disabled the code I had identified below in fifo_vnops.c and
> I could see that when read is called after receiving an EINTR, it
> returns zero and my parent program shows success.
>
>       Can someone please let me know if this make sense? or should I
> try something else? or should I be asking this in some other mailing
> list?
>
>       One question which I have been asking myself is that why
> someone else have not seen it. The only answer I could come up with
> is, that we are using FIFO which are names pipe (i.e. a file) and they
> are mostly used by two different processes. Parent-child normally uses
> PIPE or socket-pair to communicate and so may be no-one has seen this
> issue yet.
>
>       Thanks in advance.
>
> Regards,
> Bharat
>
> On Wed, Dec 7, 2011 at 9:52 PM, Bharat Joshi 
> <bharat.josh%gmail.com@localhost> wrote:
>> Hi,
>>
>>    I am seeing a strange behaviour with the read on a FIFO. Here is
>> what my application is doing:
>>
>> 1. Parent application is forking a child.
>> 2. In child, a FIFO is opened in write-mode. This is a dummy open to
>> make sure that the parent application does not block on open itself.
>> 3. Child application is exec'ed.
>> 4. In parent, a FIFO is opened in read-mode.  After this, it gets into
>> a loop where it calls read system call on this FIFO. This read blocks
>> as child application is yet to start writing.
>> 5. Child application opens the same FIFO again in write-mode and then
>> start writing.
>> 6. Parent process read whatever child process writes. Everything works
>> perfectly.
>> 7. Child application finally closes the FIFO once it is done. As there
>> is still the dummy write FIFO opened, nothing happens. Parent is
>> blocked on 'read' thinking there is more to come.
>> 8. Child exits and a signal SIGCHILD is delivered to parent.
>> 9. Parent process which was blocked on 'read' returns with EINTR.
>>
>>     Now once this happens, parent again calls 'read'. The code in
>> parent expects it to return 0 (EOF) if there is no more writers
>> available. In this case, even though no more writers are avilable,
>> parent gets blocked on 'read'. Please note that the parent process had
>> not reaped the child process yet.
>>
>>     I started debugging this and finally reached to a code in
>> fifo_read() in sys/miscfs/fifofs/fifo_vnops.c where if so_receive() on
>> read socket has not read anything, we reset the so_state for
>> CANTRECVMORE. Following code is available there:
>>
>>>>>
>>
>>        error = (*rso->so_receive)(rso, NULL, uio, NULL, NULL, NULL);
>>        /*
>>         * Clear EOF indication after first such return.
>>         */
>>        if (uio->uio_resid == startresid)
>>                rso->so_state &= ~SS_CANTRCVMORE;
>>
>>>>>
>>
>>     I think because of this code, when the read request comes again,
>> kernel does not return 0 and instead blocks on read.
>>
>>     With this, how will someone ever figure out when EINTR is coming
>> for a genuine interrupt or for a EOF.
>>
>>     If you need more details on this, please let me know.
>>
>> Thanks in advance,
>> Bharat


Home | Main Index | Thread Index | Old Index