2.5-18.1
[glibc.git] / rtkaio / sysdeps / unix / sysv / linux / kaio_suspend.c
blob2400c5223cbf98b4701f6da794cf74a340dcd7ee
1 /* Suspend until termination of a requests.
2 Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003, 2006
3 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
5 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
7 The GNU C Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 The GNU C Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with the GNU C Library; if not, write to the Free
19 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307 USA. */
23 /* We use an UGLY hack to prevent gcc from finding us cheating. The
24 implementations of aio_suspend and aio_suspend64 are identical and so
25 we want to avoid code duplication by using aliases. But gcc sees
26 the different parameter lists and prints a warning. We define here
27 a function so that aio_suspend64 has no prototype. */
28 #define aio_suspend64 XXX
29 #include <aio.h>
30 /* And undo the hack. */
31 #undef aio_suspend64
33 #include <kaio_misc.h>
35 #ifndef USE_KAIO
36 #include <aio_suspend.c>
37 #else
39 #include <assert.h>
40 #include <errno.h>
41 #include <stdbool.h>
42 #include <stdlib.h>
43 #include <sys/time.h>
45 #include <bits/libc-lock.h>
46 #include <sysdep-cancel.h>
49 struct clparam
51 const struct aiocb *const *list;
52 struct waitlist *waitlist;
53 struct requestlist **requestlist;
54 #ifndef DONT_NEED_AIO_MISC_COND
55 pthread_cond_t *cond;
56 #endif
57 int nent;
61 static void
62 cleanup (void *arg)
64 #ifdef DONT_NEED_AIO_MISC_COND
65 /* Acquire the mutex. If pthread_cond_*wait is used this would
66 happen implicitly. */
67 pthread_mutex_lock (&__aio_requests_mutex);
68 #endif
70 const struct clparam *param = (const struct clparam *) arg;
72 /* Now remove the entry in the waiting list for all requests
73 which didn't terminate. */
74 int cnt = param->nent;
75 while (cnt-- > 0)
76 if (param->list[cnt] != NULL
77 && param->list[cnt]->__error_code == EINPROGRESS)
79 struct waitlist **listp;
81 assert (param->requestlist[cnt] != NULL);
83 /* There is the chance that we cannot find our entry anymore. This
84 could happen if the request terminated and restarted again. */
85 listp = &param->requestlist[cnt]->waiting;
86 while (*listp != NULL && *listp != &param->waitlist[cnt])
87 listp = &(*listp)->next;
89 if (*listp != NULL)
90 *listp = (*listp)->next;
93 #ifndef DONT_NEED_AIO_MISC_COND
94 /* Release the conditional variable. */
95 (void) pthread_cond_destroy (param->cond);
96 #endif
98 /* Release the mutex. */
99 pthread_mutex_unlock (&__aio_requests_mutex);
104 aio_suspend (list, nent, timeout)
105 const struct aiocb *const list[];
106 int nent;
107 const struct timespec *timeout;
109 if (__builtin_expect (nent < 0, 0))
111 __set_errno (EINVAL);
112 return -1;
115 struct waitlist waitlist[nent];
116 struct requestlist *requestlist[nent];
117 #ifndef DONT_NEED_AIO_MISC_COND
118 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
119 #endif
120 int cnt;
121 int result = 0;
122 int cntr = 1;
123 int total = 0, ktotal = 0;
125 /* Request the mutex. */
126 pthread_mutex_lock (&__aio_requests_mutex);
128 /* There is not yet a finished request. Signal the request that
129 we are working for it. */
130 for (cnt = 0; cnt < nent; ++cnt)
131 if (list[cnt] != NULL)
133 if (list[cnt]->__error_code == EINPROGRESS)
135 requestlist[cnt] = __aio_find_req ((aiocb_union *) list[cnt]);
137 if (requestlist[cnt] != NULL)
139 #ifndef DONT_NEED_AIO_MISC_COND
140 waitlist[cnt].cond = &cond;
141 #endif
142 waitlist[cnt].result = NULL;
143 waitlist[cnt].next = requestlist[cnt]->waiting;
144 waitlist[cnt].counterp = &cntr;
145 waitlist[cnt].sigevp = NULL;
146 #ifdef BROKEN_THREAD_SIGNALS
147 waitlist[cnt].caller_pid = 0; /* Not needed. */
148 #endif
149 requestlist[cnt]->waiting = &waitlist[cnt];
150 total++;
151 if (requestlist[cnt]->kioctx != KCTX_NONE)
152 ktotal++;
154 else
155 /* We will never suspend. */
156 break;
158 else
159 /* We will never suspend. */
160 break;
164 /* Only if none of the entries is NULL or finished to be wait. */
165 if (cnt == nent && total)
167 struct clparam clparam =
169 .list = list,
170 .waitlist = waitlist,
171 .requestlist = requestlist,
172 #ifndef DONT_NEED_AIO_MISC_COND
173 .cond = &cond,
174 #endif
175 .nent = nent
178 pthread_cleanup_push (cleanup, &clparam);
180 if (!__kernel_thread_started && ktotal)
182 /* If the kernel aio thread was not started yet all requests
183 are served by the kernel and there are no other threads running,
184 read events with mutex hold, so that nobody else can get them
185 instead of us here. */
186 if (SINGLE_THREAD_P && total == ktotal)
188 if (timeout == NULL)
190 while (cntr == 1)
191 __aio_wait_for_events (__aio_kioctx, NULL);
193 else
195 struct timeval now;
196 struct timespec abstime, ts;
198 __gettimeofday (&now, NULL);
199 abstime.tv_nsec = timeout->tv_nsec + now.tv_usec * 1000;
200 abstime.tv_sec = timeout->tv_sec + now.tv_sec;
201 if (abstime.tv_nsec >= 1000000000)
203 abstime.tv_nsec -= 1000000000;
204 abstime.tv_sec += 1;
207 for (;;)
209 result = __aio_wait_for_events (__aio_kioctx, timeout);
210 if (cntr < 1)
211 break;
212 if (result == ETIMEDOUT)
213 break;
215 __gettimeofday (&now, NULL);
216 if (now.tv_sec > abstime.tv_sec
217 || (now.tv_sec == abstime.tv_sec
218 && now.tv_usec * 1000 >= abstime.tv_nsec))
219 break;
221 ts.tv_nsec = abstime.tv_nsec - now.tv_usec * 1000;
222 ts.tv_sec = abstime.tv_sec - now.tv_sec;
223 if (abstime.tv_nsec < now.tv_usec * 1000)
225 ts.tv_nsec += 1000000000;
226 ts.tv_sec -= 1;
228 timeout = &ts;
231 if (cntr < 1)
232 result = 0;
233 else
234 result = ETIMEDOUT;
236 total = 0;
238 else if (__aio_create_kernel_thread () < 0)
240 total = 0;
241 __set_errno (ENOMEM);
242 result = -1;
246 if (total == 0)
247 /* Suspending was handled above. */
249 #ifdef DONT_NEED_AIO_MISC_COND
250 else
251 AIO_MISC_WAIT (result, cntr, timeout, 1);
252 #else
253 else if (timeout == NULL)
254 result = pthread_cond_wait (&cond, &__aio_requests_mutex);
255 else
257 /* We have to convert the relative timeout value into an
258 absolute time value with pthread_cond_timedwait expects. */
259 struct timeval now;
260 struct timespec abstime;
262 __gettimeofday (&now, NULL);
263 abstime.tv_nsec = timeout->tv_nsec + now.tv_usec * 1000;
264 abstime.tv_sec = timeout->tv_sec + now.tv_sec;
265 if (abstime.tv_nsec >= 1000000000)
267 abstime.tv_nsec -= 1000000000;
268 abstime.tv_sec += 1;
271 result = pthread_cond_timedwait (&cond, &__aio_requests_mutex,
272 &abstime);
274 #endif
276 pthread_cleanup_pop (0);
279 /* Now remove the entry in the waiting list for all requests
280 which didn't terminate. */
281 while (cnt-- > 0)
282 if (list[cnt] != NULL && list[cnt]->__error_code == EINPROGRESS)
284 struct waitlist **listp;
286 assert (requestlist[cnt] != NULL);
288 /* There is the chance that we cannot find our entry anymore. This
289 could happen if the request terminated and restarted again. */
290 listp = &requestlist[cnt]->waiting;
291 while (*listp != NULL && *listp != &waitlist[cnt])
292 listp = &(*listp)->next;
294 if (*listp != NULL)
295 *listp = (*listp)->next;
298 #ifndef DONT_NEED_AIO_MISC_COND
299 /* Release the conditional variable. */
300 if (__builtin_expect (pthread_cond_destroy (&cond) != 0, 0))
301 /* This must never happen. */
302 abort ();
303 #endif
305 if (result != 0)
307 #ifndef DONT_NEED_AIO_MISC_COND
308 /* An error occurred. Possibly it's ETIMEDOUT. We have to translate
309 the timeout error report of `pthread_cond_timedwait' to the
310 form expected from `aio_suspend'. */
311 if (result == ETIMEDOUT)
312 __set_errno (EAGAIN);
313 else
314 #endif
315 __set_errno (result);
317 result = -1;
320 /* Release the mutex. */
321 pthread_mutex_unlock (&__aio_requests_mutex);
323 return result;
326 weak_alias (aio_suspend, aio_suspend64)
327 #endif