1 /* Enqueue and list of read or write requests. Common code template.
2 Copyright (C) 1997-2024 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/>. */
19 /* The following macros must be defined before including this file:
21 LIO_LISTIO The public symbol (lio_listio or lio_listio64).
22 AIOCB Struct tag used by LIO_LISTIO (aiocb or aiocb64).
23 LIO_LISTIO_OLD The internal symbol for the compat implementation.
24 LIO_LISTIO_NEW The internal symbol for the current implementation.
25 LIO_OPCODE_BASE Opcode shift for 64-bit version with 32-bit word size.
27 For __WORDSIZE == 64, LIO_LISTIO must always be lio_listio, and
28 lio_listio64 is automatically defined as well. */
30 #include <bits/wordsize.h>
32 # define lio_listio64 XXX
34 /* And undo the hack. */
48 #include <shlib-compat.h>
51 /* We need this special structure to handle asynchronous I/O. */
55 struct sigevent sigev
;
56 struct waitlist list
[0];
60 /* The code in glibc 2.1 to glibc 2.4 issued only one event when all
61 requests submitted with lio_listio finished. The existing practice
62 is to issue events for the individual requests as well. This is
63 what the new code does. */
64 #if SHLIB_COMPAT (librt, GLIBC_2_1, GLIBC_2_4)
65 # define LIO_MODE(mode) ((mode) & 127)
66 # define NO_INDIVIDUAL_EVENT_P(mode) ((mode) & 128)
68 # define LIO_MODE(mode) mode
69 # define NO_INDIVIDUAL_EVENT_P(mode) 0
74 lio_listio_internal (int mode
, struct AIOCB
*const list
[], int nent
,
77 struct sigevent defsigev
;
78 struct requestlist
*requests
[nent
];
80 volatile unsigned int total
= 0;
85 defsigev
.sigev_notify
= SIGEV_NONE
;
89 /* Request the mutex. */
90 __pthread_mutex_lock (&__aio_requests_mutex
);
92 /* Now we can enqueue all requests. Since we already acquired the
93 mutex the enqueue function need not do this. */
94 for (cnt
= 0; cnt
< nent
; ++cnt
)
95 if (list
[cnt
] != NULL
&& list
[cnt
]->aio_lio_opcode
!= LIO_NOP
)
97 if (NO_INDIVIDUAL_EVENT_P (mode
))
98 list
[cnt
]->aio_sigevent
.sigev_notify
= SIGEV_NONE
;
100 requests
[cnt
] = __aio_enqueue_request ((aiocb_union
*) list
[cnt
],
101 (list
[cnt
]->aio_lio_opcode
104 if (requests
[cnt
] != NULL
)
105 /* Successfully enqueued. */
108 /* Signal that we've seen an error. `errno' and the error code
109 of the aiocb will tell more. */
113 requests
[cnt
] = NULL
;
117 /* We don't have anything to do except signalling if we work
120 /* Release the mutex. We do this before raising a signal since the
121 signal handler might do a `siglongjmp' and then the mutex is
123 __pthread_mutex_unlock (&__aio_requests_mutex
);
125 if (LIO_MODE (mode
) == LIO_NOWAIT
)
126 __aio_notify_only (sig
);
130 else if (LIO_MODE (mode
) == LIO_WAIT
)
132 #ifndef DONT_NEED_AIO_MISC_COND
133 pthread_cond_t cond
= PTHREAD_COND_INITIALIZER
;
136 struct waitlist waitlist
[nent
];
139 for (cnt
= 0; cnt
< nent
; ++cnt
)
141 assert (requests
[cnt
] == NULL
|| list
[cnt
] != NULL
);
143 if (requests
[cnt
] != NULL
&& list
[cnt
]->aio_lio_opcode
!= LIO_NOP
)
145 #ifndef DONT_NEED_AIO_MISC_COND
146 waitlist
[cnt
].cond
= &cond
;
148 waitlist
[cnt
].result
= &result
;
149 waitlist
[cnt
].next
= requests
[cnt
]->waiting
;
150 waitlist
[cnt
].counterp
= &total
;
151 waitlist
[cnt
].sigevp
= NULL
;
152 requests
[cnt
]->waiting
= &waitlist
[cnt
];
157 #ifdef DONT_NEED_AIO_MISC_COND
158 AIO_MISC_WAIT (result
, total
, NULL
, 0);
160 /* Since `pthread_cond_wait'/`pthread_cond_timedwait' are cancellation
161 points we must be careful. We added entries to the waiting lists
162 which we must remove. So defer cancellation for now. */
163 pthread_setcancelstate (PTHREAD_CANCEL_DISABLE
, &oldstate
);
166 pthread_cond_wait (&cond
, &__aio_requests_mutex
);
168 /* Now it's time to restore the cancellation state. */
169 pthread_setcancelstate (oldstate
, NULL
);
171 /* Release the conditional variable. */
172 if (pthread_cond_destroy (&cond
) != 0)
173 /* This must never happen. */
177 /* If any of the I/O requests failed, return -1 and set errno. */
180 __set_errno (result
== EINTR
? EINTR
: EIO
);
186 struct async_waitlist
*waitlist
;
188 waitlist
= (struct async_waitlist
*)
189 malloc (sizeof (struct async_waitlist
)
190 + (nent
* sizeof (struct waitlist
)));
192 if (waitlist
== NULL
)
194 __set_errno (EAGAIN
);
201 for (cnt
= 0; cnt
< nent
; ++cnt
)
203 assert (requests
[cnt
] == NULL
|| list
[cnt
] != NULL
);
205 if (requests
[cnt
] != NULL
206 && list
[cnt
]->aio_lio_opcode
!= LIO_NOP
)
208 #ifndef DONT_NEED_AIO_MISC_COND
209 waitlist
->list
[cnt
].cond
= NULL
;
211 waitlist
->list
[cnt
].result
= NULL
;
212 waitlist
->list
[cnt
].next
= requests
[cnt
]->waiting
;
213 waitlist
->list
[cnt
].counterp
= &waitlist
->counter
;
214 waitlist
->list
[cnt
].sigevp
= &waitlist
->sigev
;
215 requests
[cnt
]->waiting
= &waitlist
->list
[cnt
];
220 waitlist
->counter
= total
;
221 waitlist
->sigev
= *sig
;
225 /* Release the mutex. */
226 __pthread_mutex_unlock (&__aio_requests_mutex
);
232 #if OTHER_SHLIB_COMPAT (librt, GLIBC_2_1, GLIBC_2_4)
234 attribute_compat_text_section
235 LIO_LISTIO_OLD (int mode
, struct AIOCB
*const list
[], int nent
,
236 struct sigevent
*sig
)
238 /* Check arguments. */
239 if (mode
!= LIO_WAIT
&& mode
!= LIO_NOWAIT
)
241 __set_errno (EINVAL
);
245 return lio_listio_internal (mode
| LIO_NO_INDIVIDUAL_EVENT
, list
, nent
, sig
);
247 compat_symbol (librt
, LIO_LISTIO_OLD
, LIO_LISTIO
, GLIBC_2_1
);
248 # if __WORDSIZE == 64
249 compat_symbol (librt
, LIO_LISTIO_OLD
, lio_listio64
, GLIBC_2_1
);
251 #endif /* OTHER_SHLIB_COMPAT */
255 LIO_LISTIO_NEW (int mode
, struct AIOCB
*const list
[], int nent
,
256 struct sigevent
*sig
)
258 /* Check arguments. */
259 if (mode
!= LIO_WAIT
&& mode
!= LIO_NOWAIT
)
261 __set_errno (EINVAL
);
265 return lio_listio_internal (mode
, list
, nent
, sig
);
269 versioned_symbol (libc
, LIO_LISTIO_NEW
, LIO_LISTIO
, GLIBC_2_34
);
270 # if __WORDSIZE == 64
271 versioned_symbol (libc
, LIO_LISTIO_NEW
, lio_listio64
, GLIBC_2_34
);
273 # if OTHER_SHLIB_COMPAT (librt, GLIBC_2_4, GLIBC_2_34)
274 compat_symbol (librt
, LIO_LISTIO_NEW
, LIO_LISTIO
, GLIBC_2_4
);
275 # if __WORDSIZE == 64
276 compat_symbol (librt
, LIO_LISTIO_NEW
, lio_listio64
, GLIBC_2_4
);
278 # endif /* OTHER_SHLIB_COMPAT */
279 #else /* !PTHREAD_IN_LIBC */
280 versioned_symbol (librt
, LIO_LISTIO_NEW
, LIO_LISTIO
, GLIBC_2_4
);
281 # if __WORDSIZE == 64
282 versioned_symbol (librt
, LIO_LISTIO_NEW
, lio_listio64
, GLIBC_2_4
);
284 #endif /* !PTHREAD_IN_LIBC */