1 /* Copyright (C) 1997,1999,2000,2001,2002,2003,2006
2 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, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24 #if !defined __NR_io_setup || !defined __NR_io_destroy \
25 || !defined __NR_io_getevents || !defined __NR_io_submit \
26 || !defined __NR_io_cancel
42 #ifdef HAVE_FORCED_UNWIND
44 /* We define a special synchronization primitive for AIO. POSIX
45 conditional variables would be ideal but the pthread_cond_*wait
46 operations do not return on EINTR. This is a requirement for
47 correct aio_suspend and lio_listio implementations. */
51 #include <lowlevellock.h>
53 # define DONT_NEED_AIO_MISC_COND 1
55 # define AIO_MISC_NOTIFY(waitlist) \
57 if (*waitlist->counterp > 0 && --*waitlist->counterp == 0) \
58 lll_futex_wake (waitlist->counterp, 1); \
61 # define AIO_MISC_WAIT(result, futex, timeout, cancel) \
63 volatile int *futexaddr = &futex; \
68 pthread_mutex_unlock (&__aio_requests_mutex); \
72 oldtype = LIBC_CANCEL_ASYNC (); \
77 status = lll_futex_timed_wait (futexaddr, oldval, timeout); \
78 if (status != -EWOULDBLOCK) \
81 oldval = *futexaddr; \
83 while (oldval != 0); \
86 LIBC_CANCEL_RESET (oldtype); \
88 if (status == -EINTR) \
90 else if (status == -ETIMEDOUT) \
93 assert (status == 0 || status == -EWOULDBLOCK); \
95 pthread_mutex_lock (&__aio_requests_mutex); \
101 typedef unsigned long kctx_t
;
102 #define KCTX_NONE ~0UL
103 extern kctx_t __aio_kioctx
;
119 uint16_t kiocb_lio_opcode
;
120 int16_t kiocb_req_prio
;
121 uint32_t kiocb_fildes
;
123 uint64_t kiocb_nbytes
;
124 int64_t kiocb_offset
;
125 int64_t __pad3
, __pad4
;
136 /* Extend the operation enum. */
139 LIO_DSYNC
= LIO_NOP
+ 1,
141 LIO_READ64
= LIO_READ
| 128,
142 LIO_WRITE64
= LIO_WRITE
| 128,
143 LIO_KTHREAD
= 0x10000,
144 LIO_KTHREAD_REQUIRED
= 0x20000
148 /* Union of the two request types. */
152 struct aiocb64 aiocb64
;
156 /* Used to synchronize. */
159 struct waitlist
*next
;
161 /* The next two fields is used in synchronous \fio_listio' operations. */
162 #ifndef DONT_NEED_AIO_MISC_COND
163 pthread_cond_t
*cond
;
167 volatile int *counterp
;
168 /* The next field is used in asynchronous `lio_listio' operations. */
169 struct sigevent
*sigevp
;
170 #ifdef BROKEN_THREAD_SIGNALS
171 /* XXX See requestlist, it's used to work around the broken signal
172 handling in Linux. */
178 /* Status of a request. */
189 /* Used to queue requests.. */
197 struct requestlist
*last_fd
;
198 struct requestlist
*next_fd
;
199 struct requestlist
*next_prio
;
200 struct requestlist
*next_run
;
201 /* For kioctx != KCTX_NONE requests we are doubly linked. */
202 #define prev_prio next_run
204 /* Pointer to the actual data. */
207 #ifdef BROKEN_THREAD_SIGNALS
208 /* PID of the initiator thread.
209 XXX This is only necessary for the broken signal handling on Linux. */
213 /* List of waiting processes. */
214 struct waitlist
*waiting
;
218 /* Lock for global I/O list of requests. */
219 extern pthread_mutex_t __aio_requests_mutex attribute_hidden
;
222 /* Enqueue request. */
223 extern struct requestlist
*__aio_enqueue_request_ctx (aiocb_union
*aiocbp
,
226 attribute_hidden internal_function
;
228 #define __aio_enqueue_request(aiocbp, operation) \
229 __aio_enqueue_request_ctx (aiocbp, operation | LIO_KTHREAD, KCTX_NONE)
231 /* Find request entry for given AIO control block. */
232 extern struct requestlist
*__aio_find_req (aiocb_union
*elem
)
233 attribute_hidden internal_function
;
235 /* Find request entry for given file descriptor. */
236 extern struct requestlist
*__aio_find_req_fd (int fildes
)
237 attribute_hidden internal_function
;
239 /* Find request entry for given file descriptor. */
240 extern struct requestlist
*__aio_find_kreq_fd (int fildes
)
241 attribute_hidden internal_function
;
243 /* Remove request from the list. */
244 extern void __aio_remove_request (struct requestlist
*last
,
245 struct requestlist
*req
, int all
)
246 attribute_hidden internal_function
;
248 extern void __aio_remove_krequest (struct requestlist
*req
)
249 attribute_hidden internal_function
;
251 /* Release the entry for the request. */
252 extern void __aio_free_request (struct requestlist
*req
)
253 attribute_hidden internal_function
;
255 /* Notify initiator of request and tell this everybody listening. */
256 extern void __aio_notify (struct requestlist
*req
)
257 attribute_hidden internal_function
;
259 /* Notify initiator of request. */
260 #ifdef BROKEN_THREAD_SIGNALS
261 extern int __aio_notify_only (struct sigevent
*sigev
, pid_t caller_pid
)
262 attribute_hidden internal_function
;
264 extern int __aio_notify_only (struct sigevent
*sigev
)
265 attribute_hidden internal_function
;
268 /* Send the signal. */
269 extern int __aio_sigqueue (int sig
, const union sigval val
, pid_t caller_pid
)
270 attribute_hidden internal_function
;
272 extern int __aio_wait_for_events (kctx_t kctx
, const struct timespec
*timeout
)
273 attribute_hidden internal_function
;
275 extern void __aio_read_one_event (void) attribute_hidden internal_function
;
277 extern int __aio_create_kernel_thread (void)
278 attribute_hidden internal_function
;
280 extern int __have_no_kernel_aio attribute_hidden
;
281 extern int __kernel_thread_started attribute_hidden
;
283 #ifndef BROKEN_THREAD_SIGNALS
284 # define aio_start_notify_thread __aio_start_notify_thread
285 # define aio_create_helper_thread __aio_create_helper_thread
288 __aio_start_notify_thread (void)
292 INTERNAL_SYSCALL_DECL (err
);
293 INTERNAL_SYSCALL (rt_sigprocmask
, err
, 4, SIG_SETMASK
, &ss
, NULL
, _NSIG
/ 8);
297 __aio_create_helper_thread (pthread_t
*threadp
, void *(*tf
) (void *), void *arg
)
301 /* Make sure the thread is created detached. */
302 pthread_attr_init (&attr
);
303 pthread_attr_setdetachstate (&attr
, PTHREAD_CREATE_DETACHED
);
305 /* The helper thread needs only very little resources. */
306 (void) pthread_attr_setstacksize (&attr
, PTHREAD_STACK_MIN
);
308 /* Block all signals in the helper thread. To do this thoroughly we
309 temporarily have to block all signals here. */
313 INTERNAL_SYSCALL_DECL (err
);
314 INTERNAL_SYSCALL (rt_sigprocmask
, err
, 4, SIG_SETMASK
, &ss
, &oss
, _NSIG
/ 8);
316 int ret
= pthread_create (threadp
, &attr
, tf
, arg
);
318 /* Restore the signal mask. */
319 INTERNAL_SYSCALL (rt_sigprocmask
, err
, 4, SIG_SETMASK
, &oss
, NULL
,
322 (void) pthread_attr_destroy (&attr
);
328 #endif /* aio_misc.h */