C child read giving "resource temporarily unavailable"

14,685

That means that someone has set the standard input file descriptor as non-blocking.

(Resource temporarily unavailable is the error message corresponding to EAGAIN / EWOULDBLOCK, which is returned by read() only when non-blocking IO has been selected and there is no data to read).

Note that it's possible that the parent process set the file descriptor nonblocking before exec-ing your child process.

Some ideas for further investigation:

  • If you strace() the child process, which system call is returning EAGAIN? On which file descriptor number?

  • What's the output of printf("%d\n", fcntl(fileno(fpin), F_GETFL)); right before the failing fgets()?

Share:
14,685

Related videos on Youtube

Gary
Author by

Gary

Updated on April 20, 2022

Comments

  • Gary
    Gary about 2 years

    So I have a file stream from a parent process to a child - and most of the time it works fine. However, when reading from it multiple times quickly, using fgets() will return NULL and the error is set to "resource temporarily unavailable". The problem is intermittent - and running the script that does the reads will sometimes have fgets return NULL and sometimes wont.

    Could anyone help me stop this error from happening? Thanks!

    Edit: here is some code.. I'm not sure what other code would be helpful? there's quite a bit

    // this is the bit that gets a line from the child
    if( fgets( line, MAX_LINE_LENGTH, fpin ) == NULL ) {
        if( ferror(fpin) ) {
            perror("error on stream fpin");
        }
        free( line );
        return FAIL;
    }
    

    As requested, code that opens pipe and deals with child process..

    // set up pipes
    int readPipe[2]; // child -> parent communication
    int writePipe[2]; // parent -> child communication
    int errorPipe[2]; // child -> parent, to check for errors in exec
    
    /* create pipe */
    pipe( readPipe ); // error if return val < 1 for any
    pipe( writePipe );
    pipe( errorPipe );
    pid_t pid; /* process id when we fork */
    pid = fork(); /* create new child */
    
    if( pid == 0 ) { /* pid == 0 indicates child process */
    
        // close unused fds
        close( PARENT_READ );
        close( PARENT_WRITE );
        close( errorPipe[0] );
    
        dup2( CHILD_READ, 0 ); // replace stdin with pipe in
        dup2( CHILD_WRITE, 1 ); // replace stdout with pipe out
    
        /* replace child process with program to run */
        execvp(args[0], args);
    
        // if we get here, exec failed so inform the parent
        char *error_message = "exec failed";
        write( errorPipe[1], error_message, strlen(error_message)+1 );
        exit(-1);
    
    } 
    
  • Gary
    Gary almost 14 years
    No, stdin has not been set to non-blocking. If it helps at all, it seems to wait for the same amount of time as the timeout on a select statement I have further down before giving the error. I'll post some code now..
  • caf
    caf almost 14 years
    Well, that error message is only returned by read() for non-blocking file descriptors - I've updated my answer with some further ideas for investigation...
  • Gary
    Gary almost 14 years
    i don't think I can use strace, as I'm on a mac. If I can, could you explain how? Also, the second statement always returns 2 (but the file stream is not stdin in this case). Also, what might cause fgets() to return NULL but feof(stream) would return false? That is what happens when I don't get the "resource temporarily unavailable" problem
  • caf
    caf almost 14 years
    dtruss provides equivalent functionality on OS X (Leopard and later, anyway). Which pipes does the parent close?
  • Gary
    Gary almost 14 years
    the parent closes the childs read and write pipes, i'll look into dtruss. thanks