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
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
29 /* And undo the hack. */
32 #include <kaio_misc.h>
35 #include <aio_suspend.c>
42 #include <bits/libc-lock.h>
43 #include <sysdep-cancel.h>
48 const struct aiocb
*const *list
;
49 struct waitlist
*waitlist
;
50 struct requestlist
**requestlist
;
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
;
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
= ¶m
->requestlist
[cnt
]->waiting
;
75 while (*listp
!= NULL
&& *listp
!= ¶m
->waitlist
[cnt
])
76 listp
= &(*listp
)->next
;
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
);
91 aio_suspend (list
, nent
, timeout
)
92 const struct aiocb
*const list
[];
94 const struct timespec
*timeout
;
96 struct waitlist waitlist
[nent
];
97 struct requestlist
*requestlist
[nent
];
98 pthread_cond_t cond
= PTHREAD_COND_INITIALIZER
;
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. */
124 requestlist
[cnt
]->waiting
= &waitlist
[cnt
];
126 if (requestlist
[cnt
]->kioctx
!= KCTX_NONE
)
130 /* We will never suspend. */
134 /* We will never suspend. */
139 /* Only if none of the entries is NULL or finished to be wait. */
140 if (cnt
== nent
&& total
)
142 struct clparam clparam
=
145 .waitlist
= waitlist
,
146 .requestlist
= requestlist
,
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
)
163 while (total
== ktotal
)
164 __aio_wait_for_events (__aio_kioctx
, NULL
);
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;
182 result
= __aio_wait_for_events (__aio_kioctx
, timeout
);
185 if (result
== ETIMEDOUT
)
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
))
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;
211 else if (__aio_create_kernel_thread () < 0)
214 __set_errno (ENOMEM
);
220 /* Suspending was handled above. */
222 else if (timeout
== NULL
)
223 result
= pthread_cond_wait (&cond
, &__aio_requests_mutex
);
226 /* We have to convert the relative timeout value into an
227 absolute time value with pthread_cond_timedwait expects. */
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;
240 result
= pthread_cond_timedwait (&cond
, &__aio_requests_mutex
,
244 pthread_cleanup_pop (0);
247 /* Now remove the entry in the waiting list for all requests
248 which didn't terminate. */
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
;
263 *listp
= (*listp
)->next
;
266 /* Release the conditional variable. */
267 if (__builtin_expect (pthread_cond_destroy (&cond
) != 0, 0))
268 /* This must never happen. */
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
);
279 __set_errno (result
);
284 /* Release the mutex. */
285 pthread_mutex_unlock (&__aio_requests_mutex
);
290 weak_alias (aio_suspend
, aio_suspend64
)