about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog22
-rw-r--r--rt/aio_misc.c99
-rw-r--r--rt/aio_misc.h7
-rw-r--r--rt/tst-aio.c109
4 files changed, 200 insertions, 37 deletions
diff --git a/ChangeLog b/ChangeLog
index 3b9deb208c..e9dc264e6b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2000-07-26  Andreas Jaeger  <aj@suse.de>
+
+	* rt/tst-aio.c: Add tests for aio_fsync and aio_cancel.
+	(do_wait): Test requests with aio_return.
+	(do_test): Change callers of do_wait.
+
+2000-07-27  Ulrich Drepper  <drepper@redhat.com>
+
+	* rt/aio_misc.c (__aio_remove_request): New function.  Handle removing
+	from request list.  Don't do the list handling here, call
+	__aio_remove_request.
+	* rt/aio_misc.h: Add prototype for __aio_remove_request.
+	* rt/aio_cancel.c: Don't assume __aio_find_req_fd succeeds since the
+	request might already be processed.  Don't do the list handling
+	here, call __aio_remove_request.
+
+	* rt/aio_misc.c: Don't depend on aio_reqprio field for LIO_SYNC and
+	LIO_DSYNC.
+
+	* rt/aio_misc.c: Add comment explaining why writer memory barriers
+	are missing.
+
 2000-07-27  Greg McGary  <greg@mcgary.org>
 
 	* sysdeps/generic/bp-checks.h (BOUNDED_N): Make it work for void*.
diff --git a/rt/aio_misc.c b/rt/aio_misc.c
index a9fe3591c5..af3e90f881 100644
--- a/rt/aio_misc.c
+++ b/rt/aio_misc.c
@@ -205,6 +205,64 @@ __aio_find_req_fd (int fildes)
 }
 
 
+void
+internal_function
+__aio_remove_request (struct requestlist *last, struct requestlist *req,
+		      int all)
+{
+  if (last != NULL)
+    last->next_prio = req->next_prio;
+  else
+    {
+      if (all || req->next_prio == NULL)
+	{
+	  if (req->last_fd != NULL)
+	    req->last_fd->next_fd = req->next_fd;
+	  else
+	    requests = req->next_fd;
+	  if (req->next_fd != NULL)
+	    req->next_fd->last_fd = req->last_fd;
+	}
+      else
+	{
+	  if (req->last_fd != NULL)
+	    req->last_fd->next_fd = req->next_prio;
+	  else
+	    requests = req->next_prio;
+
+	  if (req->next_fd != NULL)
+	    req->next_fd->last_fd = req->next_prio;
+
+	  req->next_prio->last_fd = req->last_fd;
+	  req->next_prio->next_fd = req->next_fd;
+
+	  /* Mark this entry as runnable.  */
+	  req->next_prio->running = yes;
+	}
+
+      if (req->running == yes)
+	{
+	  struct requestlist *runp = runlist;
+
+	  last = NULL;
+	  while (runp != NULL)
+	    {
+	      if (runp == req)
+		{
+		  if (last == NULL)
+		    runlist = runp->next_run;
+		  else
+		    last->next_run = runp->next_run;
+		  break;
+		}
+	      last = runp;
+	      runp = runp->next_run;
+	    }
+	}
+    }
+}
+
+
 /* The thread handler.  */
 static void *handle_fildes_io (void *arg);
 
@@ -246,8 +304,10 @@ __aio_enqueue_request (aiocb_union *aiocbp, int operation)
   struct requestlist *last, *runp, *newp;
   int running = no;
 
-  if (aiocbp->aiocb.aio_reqprio < 0
-      || aiocbp->aiocb.aio_reqprio > AIO_PRIO_DELTA_MAX)
+  if (operation == LIO_SYNC || operation == LIO_DSYNC)
+    aiocbp->aiocb.aio_reqprio = 0;
+  else if (aiocbp->aiocb.aio_reqprio < 0
+	   || aiocbp->aiocb.aio_reqprio > AIO_PRIO_DELTA_MAX)
     {
       /* Invalid priority value.  */
       __set_errno (EINVAL);
@@ -507,6 +567,14 @@ handle_fildes_io (void *arg)
 	  /* Get the mutex.  */
 	  pthread_mutex_lock (&__aio_requests_mutex);
 
+	  /* In theory we would need here a write memory barrier since the
+	     callers test using aio_error() whether the request finished
+	     and once this value != EINPROGRESS the field __return_value
+	     must be committed to memory.
+
+	     But since the pthread_mutex_lock call involves write memory
+	     barriers as well it is not necessary.  */
+
 	  if (aiocbp->aiocb.__return_value == -1)
 	    aiocbp->aiocb.__error_code = errno;
 	  else
@@ -517,30 +585,9 @@ handle_fildes_io (void *arg)
 	  __aio_notify (runp);
 
 	  /* Now dequeue the current request.  */
-	  if (runp->next_prio == NULL)
-	    {
-	      /* No outstanding request for this descriptor.  Remove this
-		 descriptor from the list.  */
-	      if (runp->next_fd != NULL)
-		runp->next_fd->last_fd = runp->last_fd;
-	      if (runp->last_fd != NULL)
-		runp->last_fd->next_fd = runp->next_fd;
-	      else
-		requests = runp->next_fd;
-	    }
-	  else
-	    {
-	      runp->next_prio->last_fd = runp->last_fd;
-	      runp->next_prio->next_fd = runp->next_fd;
-	      runp->next_prio->running = yes;
-	      if (runp->next_fd != NULL)
-		runp->next_fd->last_fd = runp->next_prio;
-	      if (runp->last_fd != NULL)
-		runp->last_fd->next_fd = runp->next_prio;
-	      else
-		requests = runp->next_prio;
-	      add_request_to_runlist (runp->next_prio);
-	    }
+	  __aio_remove_request (NULL, runp, 0);
+	  if (runp->next_prio != NULL)
+	    add_request_to_runlist (runp->next_prio);
 
 	  /* Free the old element.  */
 	  __aio_free_request (runp);
diff --git a/rt/aio_misc.h b/rt/aio_misc.h
index e3c93bef36..eda06541e6 100644
--- a/rt/aio_misc.h
+++ b/rt/aio_misc.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997, 1999 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1999, 2000 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -104,6 +104,11 @@ extern struct requestlist *__aio_find_req (aiocb_union *elem)
 /* Find request entry for given file descriptor.  */
 extern struct requestlist *__aio_find_req_fd (int fildes) internal_function;
 
+/* Remove request from the list.  */
+extern void __aio_remove_request (struct requestlist *last,
+				  struct requestlist *req, int all)
+     internal_function;
+
 /* Release the entry for the request.  */
 extern void __aio_free_request (struct requestlist *req) internal_function;
 
diff --git a/rt/tst-aio.c b/rt/tst-aio.c
index 9a83a2779f..8a6f103871 100644
--- a/rt/tst-aio.c
+++ b/rt/tst-aio.c
@@ -100,23 +100,38 @@ test_file (const void *buf, size_t size, int fd, const char *msg)
 }
 
 
-void
-do_wait (struct aiocb **cbp, size_t nent)
+int
+do_wait (struct aiocb **cbp, size_t nent, int allowed_err)
 {
   int go_on;
+  size_t cnt;
+  int result = 0;
+
   do
     {
-      size_t cnt;
-
       aio_suspend ((const struct aiocb *const *) cbp, nent, NULL);
       go_on = 0;
       for (cnt = 0; cnt < nent; ++cnt)
-	if (cbp[cnt] != NULL && aio_error (cbp[cnt]) == EINPROGRESS)
-	  go_on = 1;
-	else
-	  cbp[cnt] = NULL;
+	if (cbp[cnt] != NULL)
+	  {
+	    if (aio_error (cbp[cnt]) == EINPROGRESS)
+	      go_on = 1;
+	    else
+	      {
+		if (aio_return (cbp[cnt]) == -1
+		    && (allowed_err == 0
+			|| aio_error (cbp[cnt]) != allowed_err))
+		  {
+		    error (0, aio_error (cbp[cnt]), "Operation failed\n");
+		    result = 1;
+		  }
+		cbp[cnt] = NULL;
+	      }
+	  }
     }
   while (go_on);
+
+  return result;
 }
 
 
@@ -124,7 +139,9 @@ int
 do_test (int argc, char *argv[])
 {
   struct aiocb cbs[10];
+  struct aiocb cbs_fsync;
   struct aiocb *cbp[10];
+  struct aiocb *cbp_fsync[1];
   char buf[1000];
   size_t cnt;
   int result = 0;
@@ -146,7 +163,7 @@ do_test (int argc, char *argv[])
   for (cnt = 10; cnt > 0; )
     aio_write (cbp[--cnt]);
   /* Wait 'til the results are there.  */
-  do_wait (cbp, 10);
+  result |= do_wait (cbp, 10, 0);
   /* Test this.  */
   result |= test_file (buf, sizeof (buf), fd, "aio_write");
 
@@ -160,7 +177,7 @@ do_test (int argc, char *argv[])
       aio_read (cbp[cnt]);
     }
   /* Wait 'til the results are there.  */
-  do_wait (cbp, 10);
+  result |= do_wait (cbp, 10, 0);
   /* Test this.  */
   for (cnt = 0; cnt < 1000; ++cnt)
     if (buf[cnt] != '0' + (cnt / 100))
@@ -191,5 +208,77 @@ do_test (int argc, char *argv[])
   /* ...and immediately test it since we started it in wait mode.  */
   result |= test_file (buf, sizeof (buf), fd, "lio_listio (write)");
 
+  /* Test aio_fsync.  */
+  cbs_fsync.aio_fildes = fd;
+  cbs_fsync.aio_sigevent.sigev_notify = SIGEV_NONE;
+  cbp_fsync[0] = &cbs_fsync;
+
+  /* Remove the test file contents first.  */
+  if (ftruncate (fd, 0) < 0)
+    {
+      error (0, errno, "ftruncate failed\n");
+      result = 1;
+    }
+
+  /* Write again.  */
+  for (cnt = 10; cnt > 0; )
+    aio_write (cbp[--cnt]);
+
+  if (aio_fsync (O_SYNC, &cbs_fsync) < 0)
+    {
+      error (0, errno, "aio_fsync failed\n");
+      result = 1;
+    }
+  result |= do_wait (cbp_fsync, 1, 0);
+
+  /* ...and test since all data should be on disk now.  */
+  result |= test_file (buf, sizeof (buf), fd, "aio_fsync (aio_write)");
+
+  /* Test aio_cancel.  */
+  /* Remove the test file contents first.  */
+  if (ftruncate (fd, 0) < 0)
+    {
+      error (0, errno, "ftruncate failed\n");
+      result = 1;
+    }
+
+  /* Write again.  */
+  for (cnt = 10; cnt > 0; )
+    aio_write (cbp[--cnt]);
+
+  /* Cancel all requests.  */
+  if (aio_cancel (fd, NULL) == -1)
+    printf ("aio_cancel (fd, NULL) cannot cancel anything\n");
+
+  result |= do_wait (cbp, 10, ECANCELED);
+
+  /* Another test for aio_cancel.  */
+  /* Remove the test file contents first.  */
+  if (ftruncate (fd, 0) < 0)
+    {
+      error (0, errno, "ftruncate failed\n");
+      result = 1;
+    }
+
+  /* Write again.  */
+  for (cnt = 10; cnt > 0; )
+    {
+      --cnt;
+      cbp[cnt] = &cbs[cnt];
+      aio_write (cbp[cnt]);
+    }
+  puts ("finished3");
+
+  /* Cancel all requests.  */
+  for (cnt = 10; cnt > 0; )
+    if (aio_cancel (fd, cbp[--cnt]) == -1)
+      /* This is not an error.  The request can simply be finished.  */
+      printf ("aio_cancel (fd, cbp[%Zd]) cannot be canceled\n", cnt);
+  puts ("finished2");
+
+  result |= do_wait (cbp, 10, ECANCELED);
+
+  puts ("finished");
+
   return result;
 }