2.5-18.1
[glibc.git] / rtkaio / sysdeps / unix / sysv / linux / kaio_misc.h
blob5e0ca19c316b4c720ca550090bc7ec55964140d1
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
18 02111-1307 USA. */
20 #ifndef _AIO_MISC_H
22 #include <sysdep.h>
24 #if !defined __NR_io_setup || !defined __NR_io_destroy \
25 || !defined __NR_io_getevents || !defined __NR_io_submit \
26 || !defined __NR_io_cancel
28 #include <aio_misc.h>
30 #else
32 #define _AIO_MISC_H 1
33 #define USE_KAIO 1
35 #include <aio.h>
36 #include <pthread.h>
37 #include <stdint.h>
38 #include <signal.h>
39 #include <sysdep.h>
40 #include <limits.h>
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. */
49 #include <assert.h>
50 #include <pthreadP.h>
51 #include <lowlevellock.h>
53 # define DONT_NEED_AIO_MISC_COND 1
55 # define AIO_MISC_NOTIFY(waitlist) \
56 do { \
57 if (*waitlist->counterp > 0 && --*waitlist->counterp == 0) \
58 lll_futex_wake (waitlist->counterp, 1); \
59 } while (0)
61 # define AIO_MISC_WAIT(result, futex, timeout, cancel) \
62 do { \
63 volatile int *futexaddr = &futex; \
64 int oldval = futex; \
66 if (oldval != 0) \
67 { \
68 pthread_mutex_unlock (&__aio_requests_mutex); \
70 int oldtype; \
71 if (cancel) \
72 oldtype = LIBC_CANCEL_ASYNC (); \
74 int status; \
75 do \
76 { \
77 status = lll_futex_timed_wait (futexaddr, oldval, timeout); \
78 if (status != -EWOULDBLOCK) \
79 break; \
81 oldval = *futexaddr; \
82 } \
83 while (oldval != 0); \
85 if (cancel) \
86 LIBC_CANCEL_RESET (oldtype); \
88 if (status == -EINTR) \
89 result = EINTR; \
90 else if (status == -ETIMEDOUT) \
91 result = EAGAIN; \
92 else \
93 assert (status == 0 || status == -EWOULDBLOCK); \
95 pthread_mutex_lock (&__aio_requests_mutex); \
96 } \
97 } while (0)
99 #endif
101 typedef unsigned long kctx_t;
102 #define KCTX_NONE ~0UL
103 extern kctx_t __aio_kioctx;
105 enum
107 IO_CMD_PREAD,
108 IO_CMD_PWRITE,
109 IO_CMD_FSYNC,
110 IO_CMD_FDSYNC,
111 IO_CMD_PREADX,
112 IO_CMD_POLL
115 struct kiocb
117 uint64_t kiocb_data;
118 uint64_t kiocb_key;
119 uint16_t kiocb_lio_opcode;
120 int16_t kiocb_req_prio;
121 uint32_t kiocb_fildes;
122 uint64_t kiocb_buf;
123 uint64_t kiocb_nbytes;
124 int64_t kiocb_offset;
125 int64_t __pad3, __pad4;
128 struct kio_event
130 uint64_t kioe_data;
131 uint64_t kioe_obj;
132 int64_t kioe_res;
133 int64_t kioe_res2;
136 /* Extend the operation enum. */
137 enum
139 LIO_DSYNC = LIO_NOP + 1,
140 LIO_SYNC,
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. */
149 typedef union
151 struct aiocb aiocb;
152 struct aiocb64 aiocb64;
153 } aiocb_union;
156 /* Used to synchronize. */
157 struct waitlist
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;
164 #endif
165 int *result;
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. */
173 pid_t caller_pid;
174 #endif
178 /* Status of a request. */
179 enum
182 queued,
183 yes,
184 allocated,
185 done
189 /* Used to queue requests.. */
190 struct requestlist
192 struct kiocb kiocb;
193 kctx_t kioctx;
195 int running;
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. */
205 aiocb_union *aiocbp;
207 #ifdef BROKEN_THREAD_SIGNALS
208 /* PID of the initiator thread.
209 XXX This is only necessary for the broken signal handling on Linux. */
210 pid_t caller_pid;
211 #endif
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,
224 int operation,
225 kctx_t kctx)
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;
263 #else
264 extern int __aio_notify_only (struct sigevent *sigev)
265 attribute_hidden internal_function;
266 #endif
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
287 extern inline void
288 __aio_start_notify_thread (void)
290 sigset_t ss;
291 sigemptyset (&ss);
292 INTERNAL_SYSCALL_DECL (err);
293 INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &ss, NULL, _NSIG / 8);
296 extern inline int
297 __aio_create_helper_thread (pthread_t *threadp, void *(*tf) (void *), void *arg)
299 pthread_attr_t attr;
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. */
310 sigset_t ss;
311 sigset_t oss;
312 sigfillset (&ss);
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,
320 _NSIG / 8);
322 (void) pthread_attr_destroy (&attr);
323 return ret;
325 #endif
327 #endif
328 #endif /* aio_misc.h */