chiark / gitweb /
eglibc (2.11.3-4+deb6u3) squeeze-lts; urgency=medium
[eglibc.git] / sysdeps / pthread / aio_cancel.c
1 /* Cancel requests associated with given file descriptor.
2    Copyright (C) 1997, 1998, 2000, 2002, 2005 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, write to the Free
18    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20
21
22 /* We use an UGLY hack to prevent gcc from finding us cheating.  The
23    implementation of aio_cancel and aio_cancel64 are identical and so
24    we want to avoid code duplication by using aliases.  But gcc sees
25    the different parameter lists and prints a warning.  We define here
26    a function so that aio_cancel64 has no prototype.  */
27 #ifndef aio_cancel
28 #define aio_cancel64 XXX
29 #include <aio.h>
30 /* And undo the hack.  */
31 #undef aio_cancel64
32 #endif
33
34 #include <assert.h>
35 #include <errno.h>
36
37 #include <aio_misc.h>
38
39
40 int
41 aio_cancel (fildes, aiocbp)
42      int fildes;
43      struct aiocb *aiocbp;
44 {
45   struct requestlist *req = NULL;
46   int result = AIO_ALLDONE;
47
48   /* If fildes is invalid, error. */
49   if (fcntl (fildes, F_GETFL) < 0)
50     {
51       __set_errno (EBADF);
52       return -1;
53     }
54
55   /* Request the mutex.  */
56   pthread_mutex_lock (&__aio_requests_mutex);
57
58   /* We are asked to cancel a specific AIO request.  */
59   if (aiocbp != NULL)
60     {
61       /* If the AIO request is not for this descriptor it has no value
62          to look for the request block.  */
63       if (aiocbp->aio_fildes != fildes)
64         {
65           pthread_mutex_unlock (&__aio_requests_mutex);
66           __set_errno (EINVAL);
67           return -1;
68         }
69       else if (aiocbp->__error_code == EINPROGRESS)
70         {
71           struct requestlist *last = NULL;
72
73           req = __aio_find_req_fd (fildes);
74
75           if (req == NULL)
76             {
77             not_found:
78               pthread_mutex_unlock (&__aio_requests_mutex);
79               __set_errno (EINVAL);
80               return -1;
81             }
82
83           while (req->aiocbp != (aiocb_union *) aiocbp)
84             {
85               last = req;
86               req = req->next_prio;
87               if (req == NULL)
88                 goto not_found;
89             }
90
91           /* Don't remove the entry if a thread is already working on it.  */
92           if (req->running == allocated)
93             {
94               result = AIO_NOTCANCELED;
95               req = NULL;
96             }
97           else
98             {
99               /* We can remove the entry.  */
100               __aio_remove_request (last, req, 0);
101
102               result = AIO_CANCELED;
103
104               req->next_prio = NULL;
105             }
106         }
107     }
108   else
109     {
110       /* Find the beginning of the list of all requests for this
111          desriptor.  */
112       req = __aio_find_req_fd (fildes);
113
114       /* If any request is worked on by a thread it must be the first.
115          So either we can delete all requests or all but the first.  */
116       if (req != NULL)
117         {
118           if (req->running == allocated)
119             {
120               struct requestlist *old = req;
121               req = req->next_prio;
122               old->next_prio = NULL;
123
124               result = AIO_NOTCANCELED;
125
126               if (req != NULL)
127                 __aio_remove_request (old, req, 1);
128             }
129           else
130             {
131               result = AIO_CANCELED;
132
133               /* We can remove the entry.  */
134               __aio_remove_request (NULL, req, 1);
135             }
136         }
137     }
138
139   /* Mark requests as canceled and send signal.  */
140   while (req != NULL)
141     {
142       struct requestlist *old = req;
143       assert (req->running == yes || req->running == queued);
144       req->aiocbp->aiocb.__error_code = ECANCELED;
145       req->aiocbp->aiocb.__return_value = -1;
146       __aio_notify (req);
147       req = req->next_prio;
148       __aio_free_request (old);
149     }
150
151   /* Release the mutex.  */
152   pthread_mutex_unlock (&__aio_requests_mutex);
153
154   return result;
155 }
156
157 #ifndef aio_cancel
158 weak_alias (aio_cancel, aio_cancel64)
159 #endif