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_suspend() POSIX compliance


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 ----


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