This is the mail archive of the libc-alpha@sources.redhat.com mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [patch] aio_write


> > 4) If on completion of the __aio_enqueue_request errno==EINTR set
> > errno to 0 as this is in fact not an error and a residual of the
> > fact that the TEMP_FAILURE_RETRY macro does not reset errno when
> > pwrite is interrupted.  (Can this macro be changed? Should it?)
> 
> This looks broken.  errno is only defiend when the function fails and
> since it does not fail in this case why are you changing it?

Andreas:

Hi, I just wanted to jump in and explain what Tom meant.  Here is a
small test case that shows the behavior of concern for the pread(2)
case (see below for code listing for test0025.c):

    % ./test0025
    ./test0025: did not fail (ret: 0), but errno: 4
    n a m e s e r v

I believe that any syscall invocation wrapped in the TEMP_FAILURE_RETRY
macro will exhibit the same behavior: i.e. errno sometimes being left to
EINTR (#defined as 4), because the syscall was interrupted one more more
times before successful completion.

In aio_misc.c::handle_fildes_io(), the following code handles write
requests (lines 523-547):

    else if ((aiocbp->aiocb.aio_lio_opcode & 127) == LIO_WRITE)
       {
         if (aiocbp->aiocb.aio_lio_opcode & 128)
           aiocbp->aiocb.__return_value =
             TEMP_FAILURE_RETRY (__pwrite64 (fildes, (const void *)
                                 aiocbp->aiocb64.aio_buf,
                                 aiocbp->aiocb64.aio_nbytes,
                                 aiocbp->aiocb64.aio_offset));
         else
           aiocbp->aiocb.__return_value =
             TEMP_FAILURE_RETRY (pwrite (fildes, (const void *)
                                 aiocbp->aiocb.aio_buf,
                                 aiocbp->aiocb.aio_nbytes,
                                 aiocbp->aiocb.aio_offset));
       }

In unistd.h::TEMP_FAILURE_RETRY, the code loops while the wrapped
syscall is interrupted:

    # define TEMP_FAILURE_RETRY(expression)                     \
      (__extension__                                            \
        ({ long int __result;                                   \
           do __result = (long int) (expression);               \
           while (__result == -1L && errno == EINTR);           \
           __result; }))

The problem, I believe, is that errno is not reset to 0 when the syscall
actually makes it through without being interrupted.  I hope this makes
sense, thanks.

Amos Waterland


---- Begin test0025.c ----

/* Show that TEMP_FAILURE_RETRY does not reset errno if it is EINTR.
 * Amos Waterland <apw@us.ibm.com>
 * 14 June 2002
 */

#include <aio.h>
#include <error.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main( int argc, char *argv[] )
{
    const int BYTES = 8;
    int i, r, fd;
    char buff[BYTES];
    struct aiocb cb;
    
    if ((fd = open( "/etc/resolv.conf", O_RDONLY )) < 0)
        error( 1, errno, "opening file" );

    cb.aio_fildes = fd;
    cb.aio_offset = 0;
    cb.aio_buf = buff;
    cb.aio_nbytes = BYTES;
    cb.aio_reqprio = 0;
    cb.aio_sigevent.sigev_notify = SIGEV_NONE;

    errno = 0;
    if ((r = aio_read( &cb )))
        error( 1, errno, "reading from file" );

    if (r == 0 && errno != 0)
        error( 0, 0, "did not fail (ret: %i), but errno: %i", r, errno );

    while (aio_error( &cb ) == EINPROGRESS) { usleep( 10 ); }

    for (i = 0; i < BYTES; i++) { printf( "%c ", buff[i] ); } printf( "\n" );

    return 0;
}

---- End test0025.c ----


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]