PATCH: aio_cancel() POSIX compliance
Amos Waterland
apw@us.ibm.com
Fri Jun 7 10:20:00 GMT 2002
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 ----
More information about the Libc-alpha
mailing list