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]

PATCH: aio_cancel() POSIX compliance


This is a small patch to fix a POSIX compliance issue in aio_cancel().

1. The IEEE Std 1003.1-2001
(http://www.opengroup.org/onlinepubs/007904975/toc.htm) says
(http://www.opengroup.org/onlinepubs/007904975/functions/aio_cancel.html)
with respect to aio_cancel():

    int aio_cancel(int fildes, struct aiocb *aiocbp);

    If aiocbp is not NULL, then if fildes does not have the same value
    as the file descriptor with which the asynchronous operation was
    initiated, unspecified results occur.

2. and also:

    The value AIO_ALLDONE is returned if all of the operations have
    already completed. Otherwise, the function shall return -1 and set
    errno to indicate the error.

    The aio_cancel() function shall fail if:

    [EBADF] The fildes argument is not a valid file descriptor.

There is some ambiguity between [1] and [2]: if fildes does not have the
same value as aiocbp->aio_fildes AND filedes is not a valid file
descriptor, what should happen?  Right now, glibc returns AIO_ALLDONE
(#defined as 2) in any case that the two do not match, even if filedes
is invalid (see below for code listing for test0006.c):

    % ./test0006 | grep -v 0x0
    fildes: 0       aio_fildes: 1   return: 2       errno: 0
    fildes: -1      aio_fildes: 1   return: 2       errno: 0
    fildes: 0       aio_fildes: 0   return: -1      errno: 22
    fildes: -1      aio_fildes: -1  return: -1      errno: 22

My suggestion is that in any case in which fildes is invalid, -1 be
returned and errno set to EBADF.  When fildes is valid, but the
descriptors do not match, the user probably does not know what he or she
is doing, so I suggest that -1 be returned and errno set to EINVAL.

3. The IEEE Std 1003.1-2001 says:

    If aiocbp is NULL, then all outstanding cancelable asynchronous I/O
    requests against fildes shall be canceled.

Right now, glibc is returning AIO_ALLDONE in any case in which aiocbp is
NULL and it can't find fildes in its internal queue of file descriptors
for which a request is outstanding.

    % ./test0006 | grep 0x0
    fildes: 0       aio_fildes: 0x0 return: 2       errno: 0
    fildes: -1      aio_fildes: 0x0 return: 2       errno: 0

My suggestion is (again) that in any case that fildes is invalid, -1 be
returned and errno set to EBADF.

The Linux Standard Base (http://www.linuxbase.org) has a test suite that
is failing aio_cancel() because they try calling aio_cancel(fd+500,
NULL) and expect it to fail.  Here is a patch that effects the above
suggestions, and causes the aio_cancel() LSB test to pass.

---- Begin patch ----

Index: sysdeps/pthread/aio_cancel.c
===================================================================
RCS file: /cvs/glibc/libc/sysdeps/pthread/aio_cancel.c,v
retrieving revision 1.2
diff -u -r1.2 aio_cancel.c
--- sysdeps/pthread/aio_cancel.c	6 Jul 2001 04:56:02 -0000	1.2
+++ sysdeps/pthread/aio_cancel.c	5 Jun 2002 22:20:47 -0000
@@ -43,6 +43,20 @@
   struct requestlist *req = NULL;
   int result = AIO_ALLDONE;
 
+  /* If fildes is invalid, error. */
+  if (fcntl( fildes, F_GETFL ) < 0 )
+    {
+      __set_errno (EBADF);
+      return -1;
+    }
+
+  /* If the two file descriptors do not match, error. */
+  if (aiocbp != NULL && (fildes != aiocbp->aio_fildes))
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
   /* Request the mutex.  */
   pthread_mutex_lock (&__aio_requests_mutex);

---- End patch ----

---- Begin test0006.c ----

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

#define FMT "fildes: %i\taio_fildes: %i\treturn: %i\terrno: %i\n"
#define FMT2 "fildes: %i\taio_fildes: 0x0\treturn: %i\terrno: %i\n"

int main( int argc, char *argv[] )
{
    int r;
    int fildes;
    struct aiocb cb;

    cb.aio_fildes = fildes;
    cb.aio_offset = 0;
    cb.aio_buf = NULL;
    cb.aio_nbytes = 0;
    cb.aio_reqprio = 0;
    cb.aio_sigevent.sigev_notify = SIGEV_NONE;

    /* case: fildes != cb.aio_fildes and fildes is valid */
    errno = 0; fildes = 0; cb.aio_fildes = 1;
    r = aio_cancel( fildes, &cb );
    printf( FMT, fildes, cb.aio_fildes, r, errno );

    /* case: fildes != cb.aio_fildes and fildes is not valid */
    errno = 0; fildes = -1; cb.aio_fildes = 1;
    r = aio_cancel( fildes, &cb );
    printf( FMT, fildes, cb.aio_fildes, r, errno );

    /* case: fildes == cb.aio_fildes and fildes is valid */
    errno = 0; fildes = 0; cb.aio_fildes = 0;
    r = aio_cancel( fildes, &cb );
    printf( FMT, fildes, cb.aio_fildes, r, errno );

    /* case: fildes == cb.aio_fildes and fildes is not valid */
    errno = 0; fildes = -1; cb.aio_fildes = -1;
    r = aio_cancel( fildes, &cb );
    printf( FMT, fildes, cb.aio_fildes, r, errno );

    /* case: cb is null and fildes is valid */
    errno = 0; fildes = -1;
    r = aio_cancel( fildes, NULL );
    printf( FMT2, fildes, r, errno );

    /* case: cb is null and fildes is not valid */
    errno = 0; fildes = -1;
    r = aio_cancel( fildes, NULL );
    printf( FMT2, fildes, r, errno );

    return 0;
}

---- End test0006.c ----


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