PATCH: aio_suspend() POSIX compliance
Amos Waterland
apw@us.ibm.com
Thu Jun 13 15:59:00 GMT 2002
This is a small patch to fix a POSIX compliance issue in aio_suspend().
The IEEE Std 1003.1-2001
(http://www.opengroup.org/onlinepubs/007904975/toc.htm) says
(http://www.opengroup.org/onlinepubs/007904975/functions/aio_suspend.html)
with respect to aio_suspend():
int aio_suspend(const struct aiocb * const list[], int nent,
const struct timespec *timeout);
If any of the aiocb structures in the list correspond to completed
asynchronous I/O operations (that is, the error status for the operation
is not equal to [EINPROGRESS]) at the time of the call, the function
shall return without suspending the calling thread.
1. Right now, glibc does not detect when one element of a list of two or
more aiocb structures is completed at the time of the call, and proceeds to
suspend the calling thread (see below for code listing for test0019.c):
% ./test0019
n a m e s e r v
./test0019: timed out: ret: -1, errno: 11
I suggest that aio_suspend detect this condition.
Here is the patch (authored by Tom Gall and Amos Waterland of IBM LTC).
---- Begin patch ----
Index: sysdeps/pthread/aio_suspend.c
===================================================================
RCS file: /cvs/glibc/libc/sysdeps/pthread/aio_suspend.c,v
retrieving revision 1.2
diff -u -r1.2 aio_suspend.c
--- sysdeps/pthread/aio_suspend.c 6 Jul 2001 04:56:02 -0000 1.2
+++ sysdeps/pthread/aio_suspend.c 13 Jun 2002 15:57:54 -0000
@@ -49,6 +49,7 @@
int result = 0;
int dummy;
int none = 1;
+ int do_not_suspend = 0;
/* Request the mutex. */
pthread_mutex_lock (&__aio_requests_mutex);
@@ -56,8 +57,15 @@
/* There is not yet a finished request. Signal the request that
we are working for it. */
for (cnt = 0; cnt < nent; ++cnt)
- if (list[cnt] != NULL && list[cnt]->__error_code == EINPROGRESS)
+ if (list[cnt] != NULL)
{
+ /* This element has already completed, so we must not suspend thread. */
+ if (list[cnt]->__error_code != EINPROGRESS)
+ {
+ do_not_suspend = 1;
+ continue;
+ }
+
requestlist[cnt] = __aio_find_req ((aiocb_union *) list[cnt]);
if (requestlist[cnt] != NULL)
@@ -83,7 +91,8 @@
pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &oldstate);
if (timeout == NULL)
- result = pthread_cond_wait (&cond, &__aio_requests_mutex);
+ if (do_not_suspend) result = 0;
+ else result = pthread_cond_wait (&cond, &__aio_requests_mutex);
else
{
/* We have to convert the relative timeout value into an
@@ -100,8 +109,9 @@
abstime.tv_sec += 1;
}
- result = pthread_cond_timedwait (&cond, &__aio_requests_mutex,
- &abstime);
+ if (do_not_suspend) result = 0;
+ else result = pthread_cond_timedwait (&cond, &__aio_requests_mutex,
+ &abstime);
}
/* Now remove the entry in the waiting list for all requests
---- End patch ----
---- Begin test0019.c ----
/* Show that aio_suspend() does not detect that a list element is already done.
* Amos Waterland <apw@us.ibm.com>
* 12 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, ELEMS = 2;
int i, r, fd;
char buff[BYTES];
struct timespec timeout;
struct aiocb cb0, cb1;
struct aiocb *list[ELEMS];
if ((fd = open( "/etc/resolv.conf", O_RDONLY )) < 0)
error( 1, errno, "opening file" );
cb0.aio_fildes = fd;
cb0.aio_offset = 0;
cb0.aio_buf = buff;
cb0.aio_nbytes = BYTES;
cb0.aio_reqprio = 0;
cb0.aio_sigevent.sigev_notify = SIGEV_NONE;
if ((r = aio_read( &cb0 )))
error( 1, errno, "reading from file" );
while (aio_error( &(cb0) ) == EINPROGRESS) { usleep( 10 ); }
for (i = 0; i < BYTES; i++) { printf( "%c ", buff[i] ); } printf( "\n" );
/* At this point, the first read is completed, so start another one on
* stdin, which will not complete unless the user inputs something.
*/
cb1.aio_fildes = 0;
cb1.aio_offset = 0;
cb1.aio_buf = buff;
cb1.aio_nbytes = BYTES;
cb1.aio_reqprio = 0;
cb1.aio_sigevent.sigev_notify = SIGEV_NONE;
if ((r = aio_read( &cb1 )))
error( 1, errno, "reading from file" );
/* Now call aio_suspend with the two reads. It should return
* immediately according to the POSIX spec.
*/
list[0] = &cb0;
list[1] = &cb1;
timeout.tv_sec = 3;
timeout.tv_nsec = 0;
r = aio_suspend( (const struct aiocb *const *)list, ELEMS, &timeout );
if (r == -1 || errno == EAGAIN)
error( 1, 0, "timed out: ret: %i, errno: %i", r, errno );
return 0;
}
---- End test0019.c ----
More information about the Libc-alpha
mailing list