From 92806ee99d2e2d93b3e5ed39a0932dbefb58c725 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Thu, 27 Jul 2000 09:43:12 +0000 Subject: Update. 2000-07-26 Andreas Jaeger * 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 * 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. --- rt/aio_misc.c | 99 ++++++++++++++++++++++++++++++++++++++-------------- rt/aio_misc.h | 7 +++- rt/tst-aio.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 178 insertions(+), 37 deletions(-) (limited to 'rt') 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; } -- cgit v1.2.3