1 /* Suspend until termination of a requests.
2 Copyright (C) 1997-2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
20 /* We use an UGLY hack to prevent gcc from finding us cheating. The
21 implementations of aio_suspend and aio_suspend64 are identical and so
22 we want to avoid code duplication by using aliases. But gcc sees
23 the different parameter lists and prints a warning. We define here
24 a function so that aio_suspend64 has no prototype. */
25 #define aio_suspend64 XXX
27 /* And undo the hack. */
36 #include <libc-lock.h>
39 #include <shlib-compat.h>
44 const struct aiocb
*const *list
;
45 struct waitlist
*waitlist
;
46 struct requestlist
**requestlist
;
47 #ifndef DONT_NEED_AIO_MISC_COND
57 #ifdef DONT_NEED_AIO_MISC_COND
58 /* Acquire the mutex. If pthread_cond_*wait is used this would
60 __pthread_mutex_lock (&__aio_requests_mutex
);
63 const struct clparam
*param
= (const struct clparam
*) arg
;
65 /* Now remove the entry in the waiting list for all requests
66 which didn't terminate. */
67 int cnt
= param
->nent
;
69 if (param
->list
[cnt
] != NULL
70 && param
->list
[cnt
]->__error_code
== EINPROGRESS
)
72 struct waitlist
**listp
;
74 assert (param
->requestlist
[cnt
] != NULL
);
76 /* There is the chance that we cannot find our entry anymore. This
77 could happen if the request terminated and restarted again. */
78 listp
= ¶m
->requestlist
[cnt
]->waiting
;
79 while (*listp
!= NULL
&& *listp
!= ¶m
->waitlist
[cnt
])
80 listp
= &(*listp
)->next
;
83 *listp
= (*listp
)->next
;
86 #ifndef DONT_NEED_AIO_MISC_COND
87 /* Release the conditional variable. */
88 (void) pthread_cond_destroy (param
->cond
);
91 /* Release the mutex. */
92 __pthread_mutex_unlock (&__aio_requests_mutex
);
95 #ifdef DONT_NEED_AIO_MISC_COND
97 __attribute__ ((noinline
))
98 do_aio_misc_wait (unsigned int *cntr
, const struct __timespec64
*timeout
)
102 AIO_MISC_WAIT (result
, *cntr
, timeout
, 1);
109 ___aio_suspend_time64 (const struct aiocb
*const list
[], int nent
,
110 const struct __timespec64
*timeout
)
112 if (__glibc_unlikely (nent
< 0))
114 __set_errno (EINVAL
);
118 struct waitlist waitlist
[nent
];
119 struct requestlist
*requestlist
[nent
];
120 #ifndef DONT_NEED_AIO_MISC_COND
121 pthread_cond_t cond
= PTHREAD_COND_INITIALIZER
;
126 unsigned int cntr
= 1;
128 /* Request the mutex. */
129 __pthread_mutex_lock (&__aio_requests_mutex
);
131 /* There is not yet a finished request. Signal the request that
132 we are working for it. */
133 for (cnt
= 0; cnt
< nent
; ++cnt
)
134 if (list
[cnt
] != NULL
)
136 if (list
[cnt
]->__error_code
== EINPROGRESS
)
138 requestlist
[cnt
] = __aio_find_req ((aiocb_union
*) list
[cnt
]);
140 if (requestlist
[cnt
] != NULL
)
142 #ifndef DONT_NEED_AIO_MISC_COND
143 waitlist
[cnt
].cond
= &cond
;
145 waitlist
[cnt
].result
= NULL
;
146 waitlist
[cnt
].next
= requestlist
[cnt
]->waiting
;
147 waitlist
[cnt
].counterp
= &cntr
;
148 waitlist
[cnt
].sigevp
= NULL
;
149 requestlist
[cnt
]->waiting
= &waitlist
[cnt
];
153 /* We will never suspend. */
157 /* We will never suspend. */
161 struct __timespec64 ts
;
164 __clock_gettime64 (CLOCK_MONOTONIC
, &ts
);
165 ts
.tv_sec
+= timeout
->tv_sec
;
166 ts
.tv_nsec
+= timeout
->tv_nsec
;
167 if (ts
.tv_nsec
>= 1000000000)
169 ts
.tv_nsec
-= 1000000000;
174 /* Only if none of the entries is NULL or finished to be wait. */
175 if (cnt
== nent
&& any
)
177 struct clparam clparam
=
180 .waitlist
= waitlist
,
181 .requestlist
= requestlist
,
182 #ifndef DONT_NEED_AIO_MISC_COND
189 __libc_cleanup_region_start (1, cleanup
, &clparam
);
191 __pthread_cleanup_push (cleanup
, &clparam
);
194 #ifdef DONT_NEED_AIO_MISC_COND
195 result
= do_aio_misc_wait (&cntr
, timeout
== NULL
? NULL
: &ts
);
197 struct timespec ts32
= valid_timespec64_to_timespec (ts
);
198 result
= pthread_cond_timedwait (&cond
, &__aio_requests_mutex
,
199 timeout
== NULL
? NULL
: &ts32
);
203 __libc_cleanup_region_end (0);
205 pthread_cleanup_pop (0);
209 /* Now remove the entry in the waiting list for all requests
210 which didn't terminate. */
212 if (list
[cnt
] != NULL
&& list
[cnt
]->__error_code
== EINPROGRESS
)
214 struct waitlist
**listp
;
216 assert (requestlist
[cnt
] != NULL
);
218 /* There is the chance that we cannot find our entry anymore. This
219 could happen if the request terminated and restarted again. */
220 listp
= &requestlist
[cnt
]->waiting
;
221 while (*listp
!= NULL
&& *listp
!= &waitlist
[cnt
])
222 listp
= &(*listp
)->next
;
225 *listp
= (*listp
)->next
;
228 #ifndef DONT_NEED_AIO_MISC_COND
229 /* Release the conditional variable. */
230 if (__glibc_unlikely (pthread_cond_destroy (&cond
) != 0))
231 /* This must never happen. */
237 #ifndef DONT_NEED_AIO_MISC_COND
238 /* An error occurred. Possibly it's ETIMEDOUT. We have to translate
239 the timeout error report of `pthread_cond_timedwait' to the
240 form expected from `aio_suspend'. */
241 if (result
== ETIMEDOUT
)
242 __set_errno (EAGAIN
);
245 __set_errno (result
);
250 /* Release the mutex. */
251 __pthread_mutex_unlock (&__aio_requests_mutex
);
257 strong_alias (___aio_suspend_time64
, __aio_suspend
)
258 #else /* __TIMESIZE != 64 */
260 libc_hidden_ver (___aio_suspend_time64
, __aio_suspend_time64
)
261 /* The conditional is slightly wrong: PTHREAD_IN_LIBC is a stand-in
262 for whether time64 support is needed. */
263 versioned_symbol (libc
, ___aio_suspend_time64
, __aio_suspend_time64
, GLIBC_2_34
);
265 librt_hidden_ver (___aio_suspend_time64
, __aio_suspend_time64
)
269 __aio_suspend (const struct aiocb
*const list
[], int nent
,
270 const struct timespec
*timeout
)
272 struct __timespec64 ts64
;
275 ts64
= valid_timespec_to_timespec64 (*timeout
);
277 return __aio_suspend_time64 (list
, nent
, timeout
!= NULL
? &ts64
: NULL
);
279 #endif /* __TIMESPEC64 != 64 */
282 versioned_symbol (libc
, __aio_suspend
, aio_suspend
, GLIBC_2_34
);
283 versioned_symbol (libc
, __aio_suspend
, aio_suspend64
, GLIBC_2_34
);
284 # if OTHER_SHLIB_COMPAT (librt, GLIBC_2_1, GLIBC_2_34)
285 compat_symbol (librt
, __aio_suspend
, aio_suspend
, GLIBC_2_1
);
286 compat_symbol (librt
, __aio_suspend
, aio_suspend64
, GLIBC_2_1
);
288 #else /* !PTHREAD_IN_LIBC */
289 weak_alias (__aio_suspend
, aio_suspend
)
290 weak_alias (__aio_suspend
, aio_suspend64
)
291 #endif /* !PTHREAD_IN_LIBC */