summaryrefslogtreecommitdiff
path: root/rtkaio/sysdeps/unix/sysv/linux/kaio_cancel.c
diff options
context:
space:
mode:
Diffstat (limited to 'rtkaio/sysdeps/unix/sysv/linux/kaio_cancel.c')
-rw-r--r--rtkaio/sysdeps/unix/sysv/linux/kaio_cancel.c238
1 files changed, 238 insertions, 0 deletions
diff --git a/rtkaio/sysdeps/unix/sysv/linux/kaio_cancel.c b/rtkaio/sysdeps/unix/sysv/linux/kaio_cancel.c
new file mode 100644
index 0000000000..19d7e1b16d
--- /dev/null
+++ b/rtkaio/sysdeps/unix/sysv/linux/kaio_cancel.c
@@ -0,0 +1,238 @@
+/* Cancel requests associated with given file descriptor.
+ Copyright (C) 1997, 1998, 2000, 2002, 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/* We use an UGLY hack to prevent gcc from finding us cheating. The
+ implementation of aio_cancel and aio_cancel64 are identical and so
+ we want to avoid code duplication by using aliases. But gcc sees
+ the different parameter lists and prints a warning. We define here
+ a function so that aio_cancel64 has no prototype. */
+#ifndef aio_cancel
+#define aio_cancel64 XXX
+#include <aio.h>
+/* And undo the hack. */
+#undef aio_cancel64
+#endif
+
+#include <kaio_misc.h>
+
+#ifndef USE_KAIO
+#include <aio_cancel.c>
+#else
+
+#include <assert.h>
+#include <errno.h>
+
+int
+aio_cancel (fildes, aiocbp)
+ int fildes;
+ struct aiocb *aiocbp;
+{
+ struct requestlist *req = NULL;
+ int result = AIO_ALLDONE;
+
+ /* If fildes is invalid, error. */
+ if (fcntl (fildes, F_GETFL) < 0)
+ {
+ __set_errno (EBADF);
+ return -1;
+ }
+
+ /* Request the mutex. */
+ pthread_mutex_lock (&__aio_requests_mutex);
+
+ /* We are asked to cancel a specific AIO request. */
+ if (aiocbp != NULL)
+ {
+ /* If the AIO request is not for this descriptor it has no value
+ to look for the request block. */
+ if (aiocbp->aio_fildes != fildes)
+ {
+ pthread_mutex_unlock (&__aio_requests_mutex);
+ __set_errno (EINVAL);
+ return -1;
+ }
+ else if (aiocbp->__error_code == EINPROGRESS)
+ {
+ struct requestlist *last = NULL;
+
+ req = __aio_find_req_fd (fildes);
+
+ if (req != NULL)
+ while (req->aiocbp != (aiocb_union *) aiocbp)
+ {
+ last = req;
+ req = req->next_prio;
+ if (req == NULL)
+ break;
+ }
+
+ if (req != NULL)
+ {
+ /* Don't remove the entry if a thread is already working on
+ it. */
+ if (req->running == allocated)
+ {
+ result = AIO_NOTCANCELED;
+ req = NULL;
+ }
+ else
+ {
+ /* We can remove the entry. */
+ __aio_remove_request (last, req, 0);
+
+ result = AIO_CANCELED;
+
+ req->next_prio = NULL;
+ }
+ }
+ else
+ {
+ /* Try kernel requests. */
+ req = __aio_find_req ((aiocb_union *) aiocbp);
+
+ if (req == NULL)
+ {
+ pthread_mutex_unlock (&__aio_requests_mutex);
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ assert (req->kioctx != KCTX_NONE);
+
+ /* If kernel is working on it, try cancelling it. */
+ if (req->running == allocated)
+ {
+ struct kio_event ev;
+ INTERNAL_SYSCALL_DECL (err);
+ int res;
+
+ res = INTERNAL_SYSCALL (io_cancel, err, 3, __aio_kioctx,
+ &req->kiocb, &ev);
+ if (INTERNAL_SYSCALL_ERROR_P (res, err))
+ {
+ result = AIO_NOTCANCELED;
+ req = NULL;
+ }
+ else
+ req->running = queued;
+ }
+ if (req != NULL)
+ {
+ /* We can remove the entry. */
+ __aio_remove_krequest (req);
+ result = AIO_CANCELED;
+ req->next_prio = NULL;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Find the beginning of the list of all requests for this
+ desriptor. */
+ req = __aio_find_req_fd (fildes);
+
+ /* If any request is worked on by a thread it must be the first.
+ So either we can delete all requests or all but the first. */
+ if (req != NULL)
+ {
+ if (req->running == allocated)
+ {
+ struct requestlist *old = req;
+ req = req->next_prio;
+ old->next_prio = NULL;
+
+ result = AIO_NOTCANCELED;
+
+ if (req != NULL)
+ __aio_remove_request (old, req, 1);
+ }
+ else
+ {
+ result = AIO_CANCELED;
+
+ /* We can remove the entry. */
+ __aio_remove_request (NULL, req, 1);
+ }
+ }
+
+ if (result != AIO_NOTCANCELED)
+ {
+ /* Try to cancel kernel requests. */
+ struct requestlist *kreq = __aio_find_kreq_fd (fildes);
+
+ while (kreq)
+ {
+ struct requestlist *next;
+
+ /* If kernel is working on it, try cancelling it. */
+ if (kreq->running == allocated)
+ {
+ struct kio_event ev;
+ INTERNAL_SYSCALL_DECL (err);
+ int res;
+
+ res = INTERNAL_SYSCALL (io_cancel, err, 3, __aio_kioctx,
+ &kreq->kiocb, &ev);
+ if (INTERNAL_SYSCALL_ERROR_P (res, err))
+ {
+ result = AIO_NOTCANCELED;
+ break;
+ }
+ else
+ kreq->running = queued;
+ }
+ next = kreq->next_prio;
+ __aio_remove_krequest (kreq);
+ result = AIO_CANCELED;
+ kreq->next_prio = NULL;
+ assert (kreq->running == yes || kreq->running == queued);
+ kreq->aiocbp->aiocb.__error_code = ECANCELED;
+ kreq->aiocbp->aiocb.__return_value = -1;
+ __aio_notify (kreq);
+ __aio_free_request (kreq);
+ kreq = next;
+ }
+ }
+ }
+
+ /* Mark requests as canceled and send signal. */
+ while (req != NULL)
+ {
+ struct requestlist *old = req;
+ assert (req->running == yes || req->running == queued);
+ req->aiocbp->aiocb.__error_code = ECANCELED;
+ req->aiocbp->aiocb.__return_value = -1;
+ __aio_notify (req);
+ req = req->next_prio;
+ __aio_free_request (old);
+ }
+
+ /* Release the mutex. */
+ pthread_mutex_unlock (&__aio_requests_mutex);
+
+ return result;
+}
+
+#ifndef aio_cancel
+weak_alias (aio_cancel, aio_cancel64)
+#endif
+
+#endif