Changes and additions migrated from cvs.devel.redhat.com:/cvs/devel/glibc to fedora...
[glibc.git] / rtkaio / sysdeps / unix / sysv / linux / kaio_suspend.c
blob0b3380f98ab7069186339f774e737cea6b234211
1 /* Suspend until termination of a requests.
2 Copyright (C) 1997,1998,1999,2000,2002,2003 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
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.
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.
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. */
22 /* We use an UGLY hack to prevent gcc from finding us cheating. The
23 implementations of aio_suspend and aio_suspend64 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_suspend64 has no prototype. */
27 #define aio_suspend64 XXX
28 #include <aio.h>
29 /* And undo the hack. */
30 #undef aio_suspend64
32 #include <kaio_misc.h>
34 #ifndef USE_KAIO
35 #include <aio_suspend.c>
36 #else
38 #include <assert.h>
39 #include <errno.h>
40 #include <stdlib.h>
41 #include <sys/time.h>
42 #include <bits/libc-lock.h>
43 #include <sysdep-cancel.h>
46 struct clparam
48 const struct aiocb *const *list;
49 struct waitlist *waitlist;
50 struct requestlist **requestlist;
51 pthread_cond_t *cond;
52 int nent;
56 static void
57 cleanup (void *arg)
59 const struct clparam *param = (const struct clparam *) arg;
61 /* Now remove the entry in the waiting list for all requests
62 which didn't terminate. */
63 int cnt = param->nent;
64 while (cnt-- > 0)
65 if (param->list[cnt] != NULL
66 && param->list[cnt]->__error_code == EINPROGRESS)
68 struct waitlist **listp;
70 assert (param->requestlist[cnt] != NULL);
72 /* There is the chance that we cannot find our entry anymore. This
73 could happen if the request terminated and restarted again. */
74 listp = &param->requestlist[cnt]->waiting;
75 while (*listp != NULL && *listp != &param->waitlist[cnt])
76 listp = &(*listp)->next;
78 if (*listp != NULL)
79 *listp = (*listp)->next;
82 /* Release the conditional variable. */
83 (void) pthread_cond_destroy (param->cond);
85 /* Release the mutex. */
86 pthread_mutex_unlock (&__aio_requests_mutex);
90 int
91 aio_suspend (list, nent, timeout)
92 const struct aiocb *const list[];
93 int nent;
94 const struct timespec *timeout;
96 struct waitlist waitlist[nent];
97 struct requestlist *requestlist[nent];
98 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
99 int cnt;
100 int result = 0;
101 int total = 0, ktotal = 0;
103 /* Request the mutex. */
104 pthread_mutex_lock (&__aio_requests_mutex);
106 /* There is not yet a finished request. Signal the request that
107 we are working for it. */
108 for (cnt = 0; cnt < nent; ++cnt)
109 if (list[cnt] != NULL)
111 if (list[cnt]->__error_code == EINPROGRESS)
113 requestlist[cnt] = __aio_find_req ((aiocb_union *) list[cnt]);
115 if (requestlist[cnt] != NULL)
117 waitlist[cnt].cond = &cond;
118 waitlist[cnt].next = requestlist[cnt]->waiting;
119 waitlist[cnt].counterp = &total;
120 waitlist[cnt].sigevp = NULL;
121 #ifdef BROKEN_THREAD_SIGNALS
122 waitlist[cnt].caller_pid = 0; /* Not needed. */
123 #endif
124 requestlist[cnt]->waiting = &waitlist[cnt];
125 total++;
126 if (requestlist[cnt]->kioctx != KCTX_NONE)
127 ktotal++;
129 else
130 /* We will never suspend. */
131 break;
133 else
134 /* We will never suspend. */
135 break;
139 /* Only if none of the entries is NULL or finished to be wait. */
140 if (cnt == nent && total)
142 struct clparam clparam =
144 .list = list,
145 .waitlist = waitlist,
146 .requestlist = requestlist,
147 .cond = &cond,
148 .nent = nent
151 pthread_cleanup_push (cleanup, &clparam);
153 if (!__kernel_thread_started)
155 /* If the kernel aio thread was not started yet all requests
156 are served by the kernel and there are no other threads running,
157 read events with mutex hold, so that nobody else can get them
158 instead of us here. */
159 if (SINGLE_THREAD_P && total == ktotal)
161 if (timeout == NULL)
163 while (total == ktotal)
164 __aio_wait_for_events (__aio_kioctx, NULL);
166 else
168 struct timeval now;
169 struct timespec abstime, ts;
171 __gettimeofday (&now, NULL);
172 abstime.tv_nsec = timeout->tv_nsec + now.tv_usec * 1000;
173 abstime.tv_sec = timeout->tv_sec + now.tv_sec;
174 if (abstime.tv_nsec >= 1000000000)
176 abstime.tv_nsec -= 1000000000;
177 abstime.tv_sec += 1;
180 for (;;)
182 result = __aio_wait_for_events (__aio_kioctx, timeout);
183 if (total < ktotal)
184 break;
185 if (result == ETIMEDOUT)
186 break;
188 __gettimeofday (&now, NULL);
189 if (now.tv_sec > abstime.tv_sec
190 || (now.tv_sec == abstime.tv_sec
191 && now.tv_usec * 1000 >= abstime.tv_nsec))
192 break;
194 ts.tv_nsec = abstime.tv_nsec - now.tv_usec * 1000;
195 ts.tv_sec = abstime.tv_sec - now.tv_sec;
196 if (abstime.tv_nsec < now.tv_usec * 1000)
198 ts.tv_nsec += 1000000000;
199 ts.tv_sec -= 1;
201 timeout = &ts;
204 if (total < ktotal)
205 result = 0;
206 else
207 result = ETIMEDOUT;
209 total = 0;
211 else if (__aio_create_kernel_thread () < 0)
213 total = 0;
214 __set_errno (ENOMEM);
215 result = -1;
219 if (total == 0)
220 /* Suspending was handled above. */
222 else if (timeout == NULL)
223 result = pthread_cond_wait (&cond, &__aio_requests_mutex);
224 else
226 /* We have to convert the relative timeout value into an
227 absolute time value with pthread_cond_timedwait expects. */
228 struct timeval now;
229 struct timespec abstime;
231 __gettimeofday (&now, NULL);
232 abstime.tv_nsec = timeout->tv_nsec + now.tv_usec * 1000;
233 abstime.tv_sec = timeout->tv_sec + now.tv_sec;
234 if (abstime.tv_nsec >= 1000000000)
236 abstime.tv_nsec -= 1000000000;
237 abstime.tv_sec += 1;
240 result = pthread_cond_timedwait (&cond, &__aio_requests_mutex,
241 &abstime);
244 pthread_cleanup_pop (0);
247 /* Now remove the entry in the waiting list for all requests
248 which didn't terminate. */
249 while (cnt-- > 0)
250 if (list[cnt] != NULL && list[cnt]->__error_code == EINPROGRESS)
252 struct waitlist **listp;
254 assert (requestlist[cnt] != NULL);
256 /* There is the chance that we cannot find our entry anymore. This
257 could happen if the request terminated and restarted again. */
258 listp = &requestlist[cnt]->waiting;
259 while (*listp != NULL && *listp != &waitlist[cnt])
260 listp = &(*listp)->next;
262 if (*listp != NULL)
263 *listp = (*listp)->next;
266 /* Release the conditional variable. */
267 if (__builtin_expect (pthread_cond_destroy (&cond) != 0, 0))
268 /* This must never happen. */
269 abort ();
271 if (result != 0)
273 /* An error occurred. Possibly it's EINTR. We have to translate
274 the timeout error report of `pthread_cond_timedwait' to the
275 form expected from `aio_suspend'. */
276 if (result == ETIMEDOUT)
277 __set_errno (EAGAIN);
278 else
279 __set_errno (result);
281 result = -1;
284 /* Release the mutex. */
285 pthread_mutex_unlock (&__aio_requests_mutex);
287 return result;
290 weak_alias (aio_suspend, aio_suspend64)
291 #endif