1 /* Handle general operations.
2 Copyright (C) 1997 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 Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 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 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
24 #include <semaphore.h>
32 /* We need a list of pending operations. This is sorted according to
33 the priority given in the aio_reqprio member. */
34 aiocb_union
*__aio_requests
;
36 /* Since the list is global we need a semaphore protecting it. */
37 sem_t __aio_requests_sema
;
40 /* The initialization function. It gets automatically called if any
41 aio_* function is used in the program. */
43 __attribute__ ((unused
))
46 /* Initialize the semaphore. We allow exactly one user at a time. */
47 sem_init (&__aio_requests_sema
, 0, 1);
50 text_set_element (__libc_subinit
, aio_initialize
);
53 /* The thread handler. */
54 static void *handle_fildes_io (void *arg
);
57 /* The main function of the async I/O handling. It enqueues requests
58 and if necessary starts and handles threads. */
60 __aio_enqueue_request (aiocb_union
*aiocbp
, int operation
, int require_lock
)
64 struct sched_param param
;
67 if (aiocbp
->aiocb
.aio_reqprio
< 0
68 || aiocbp
->aiocb
.aio_reqprio
> AIO_PRIO_DELTA_MAX
)
70 /* Invalid priority value. */
72 aiocbp
->aiocb
.__error_code
= EINVAL
;
73 aiocbp
->aiocb
.__return_value
= -1;
77 if (pthread_getschedparam (pthread_self (), &policy
, ¶m
) < 0)
79 /* Something went wrong. */
80 aiocbp
->aiocb
.__error_code
= errno
;
81 aiocbp
->aiocb
.__return_value
= -1;
85 /* Compute priority for this request. */
86 prio
= param
.sched_priority
- aiocbp
->aiocb
.aio_reqprio
;
89 /* Get the semaphore. */
91 sem_wait (&__aio_requests_sema
);
93 runp
= __aio_requests
;
94 /* First look whether the current file descriptor is currently
96 while (runp
!= NULL
&& runp
->aiocb
.aio_fildes
< aiocbp
->aiocb
.aio_fildes
)
97 runp
= (aiocb_union
*) runp
->aiocb
.__next_fd
;
101 /* The current file descriptor is worked on. It makes no sense
102 to start another thread since this new thread would have to
103 wait for the previous one to terminate. Simply enqueue it
104 after the running one according to the priority. */
105 while (runp
->aiocb
.__next_prio
!= NULL
106 && runp
->aiocb
.__next_prio
->__abs_prio
>= prio
)
107 runp
= (aiocb_union
*) runp
->aiocb
.__next_prio
;
109 aiocbp
->aiocb
.__next_prio
= runp
->aiocb
.__next_prio
;
110 aiocbp
->aiocb
.__abs_prio
= prio
;
111 aiocbp
->aiocb
.__policy
= policy
;
112 aiocbp
->aiocb
.aio_lio_opcode
= operation
;
113 aiocbp
->aiocb
.__error_code
= EINPROGRESS
;
114 aiocbp
->aiocb
.__return_value
= 0;
115 runp
->aiocb
.__next_prio
= (struct aiocb
*) aiocbp
;
121 /* We create a new thread for this file descriptor. The
122 function which gets called will handle all available requests
123 for this descriptor and when all are processed it will
128 /* First enqueue the request (the list is empty). */
129 aiocbp
->aiocb
.__next_fd
= NULL
;
130 aiocbp
->aiocb
.__last_fd
= NULL
;
132 aiocbp
->aiocb
.__next_prio
= NULL
;
133 aiocbp
->aiocb
.__abs_prio
= prio
;
134 aiocbp
->aiocb
.__policy
= policy
;
135 aiocbp
->aiocb
.aio_lio_opcode
= operation
;
136 aiocbp
->aiocb
.__error_code
= EINPROGRESS
;
137 aiocbp
->aiocb
.__return_value
= 0;
139 /* Make sure the thread is created detached. */
140 pthread_attr_init (&attr
);
141 pthread_attr_setdetachstate (&attr
, PTHREAD_CREATE_DETACHED
);
143 /* Now try to start a thread. */
144 if (pthread_create (&thid
, &attr
, handle_fildes_io
, aiocbp
) < 0)
147 aiocbp
->aiocb
.__error_code
= errno
;
148 aiocbp
->aiocb
.__return_value
= -1;
151 /* We managed to enqueue the request. All errors which can
152 happen now can be recognized by calls to `aio_return' and
157 /* Release the semaphore. */
159 sem_post (&__aio_requests_sema
);
166 handle_fildes_io (void *arg
)
168 pthread_t self
= pthread_self ();
169 struct sched_param param
;
170 aiocb_union
*runp
= (aiocb_union
*) arg
;
172 int fildes
= runp
->aiocb
.aio_fildes
; /* This is always the same. */
174 pthread_getschedparam (self
, &policy
, ¶m
);
178 /* Change the priority to the requested value (if necessary). */
179 if (runp
->aiocb
.__abs_prio
!= param
.sched_priority
180 || runp
->aiocb
.__policy
!= policy
)
182 param
.sched_priority
= runp
->aiocb
.__abs_prio
;
183 policy
= runp
->aiocb
.__policy
;
184 pthread_setschedparam (self
, policy
, ¶m
);
187 /* Process request pointed to by RUNP. We must not be disturbed
189 if ((runp
->aiocb
.aio_lio_opcode
& 127) == LIO_READ
)
191 if (runp
->aiocb
.aio_lio_opcode
& 128)
192 runp
->aiocb
.__return_value
=
193 TEMP_FAILURE_RETRY (__pread64 (fildes
,
194 (void *) runp
->aiocb64
.aio_buf
,
195 runp
->aiocb64
.aio_nbytes
,
196 runp
->aiocb64
.aio_offset
));
198 runp
->aiocb
.__return_value
=
199 TEMP_FAILURE_RETRY (__pread (fildes
,
200 (void *) runp
->aiocb
.aio_buf
,
201 runp
->aiocb
.aio_nbytes
,
202 runp
->aiocb
.aio_offset
));
204 else if ((runp
->aiocb
.aio_lio_opcode
& 127) == LIO_WRITE
)
206 if (runp
->aiocb
.aio_lio_opcode
& 128)
207 runp
->aiocb
.__return_value
=
208 TEMP_FAILURE_RETRY (__pwrite64 (fildes
,
209 (const void *) runp
->aiocb64
.aio_buf
,
210 runp
->aiocb64
.aio_nbytes
,
211 runp
->aiocb64
.aio_offset
));
213 runp
->aiocb
.__return_value
=
214 TEMP_FAILURE_RETRY (__pwrite (fildes
,
215 (const void *) runp
->aiocb
.aio_buf
,
216 runp
->aiocb
.aio_nbytes
,
217 runp
->aiocb
.aio_offset
));
219 else if (runp
->aiocb
.aio_lio_opcode
== __LIO_DSYNC
)
220 runp
->aiocb
.__return_value
= TEMP_FAILURE_RETRY (fdatasync (fildes
));
221 else if (runp
->aiocb
.aio_lio_opcode
== __LIO_SYNC
)
222 runp
->aiocb
.__return_value
= TEMP_FAILURE_RETRY (fsync (fildes
));
225 /* This is an invalid opcode. */
226 runp
->aiocb
.__return_value
= -1;
227 __set_errno (EINVAL
);
230 if (runp
->aiocb
.__return_value
== -1)
231 runp
->aiocb
.__error_code
= errno
;
233 runp
->aiocb
.__error_code
= 0;
235 /* Send the signal to notify about finished processing of the
237 if (runp
->aiocb
.aio_sigevent
.sigev_notify
== SIGEV_THREAD
)
239 /* We have to start a thread. */
241 pthread_attr_t attr
, *pattr
;
243 pattr
= (pthread_attr_t
*)
244 runp
->aiocb
.aio_sigevent
.sigev_notify_attributes
;
247 pthread_attr_init (&attr
);
248 pthread_attr_setdetachstate (&attr
, PTHREAD_CREATE_DETACHED
);
252 if (pthread_create (&tid
,
254 runp
->aiocb
.aio_sigevent
.sigev_notify_attributes
,
256 runp
->aiocb
.aio_sigevent
.sigev_notify_function
,
257 runp
->aiocb
.aio_sigevent
.sigev_value
.sival_ptr
)
260 /* XXX What shall we do if already an error is set by
262 runp
->aiocb
.__error_code
= errno
;
263 runp
->aiocb
.__return_value
= -1;
266 else if (runp
->aiocb
.aio_sigevent
.sigev_notify
== SIGEV_SIGNAL
)
267 /* We have to send a signal. */
268 if (__aio_sigqueue (runp
->aiocb
.aio_sigevent
.sigev_signo
,
269 runp
->aiocb
.aio_sigevent
.sigev_value
) < 0)
271 /* XXX What shall we do if already an error is set by
273 runp
->aiocb
.__error_code
= errno
;
274 runp
->aiocb
.__return_value
= -1;
277 /* Get the semaphore. */
278 sem_wait (&__aio_requests_sema
);
280 /* Now dequeue the current request. */
281 if (runp
->aiocb
.__next_prio
== NULL
)
283 if (runp
->aiocb
.__next_fd
!= NULL
)
284 runp
->aiocb
.__next_fd
->__last_fd
= runp
->aiocb
.__last_fd
;
285 if (runp
->aiocb
.__last_fd
!= NULL
)
286 runp
->aiocb
.__last_fd
->__next_fd
= runp
->aiocb
.__next_fd
;
291 runp
->aiocb
.__next_prio
->__last_fd
= runp
->aiocb
.__last_fd
;
292 runp
->aiocb
.__next_prio
->__next_fd
= runp
->aiocb
.__next_fd
;
293 if (runp
->aiocb
.__next_fd
!= NULL
)
294 runp
->aiocb
.__next_fd
->__last_fd
= runp
->aiocb
.__next_prio
;
295 if (runp
->aiocb
.__last_fd
!= NULL
)
296 runp
->aiocb
.__last_fd
->__next_fd
= runp
->aiocb
.__next_prio
;
297 runp
= (aiocb_union
*) runp
->aiocb
.__next_prio
;
300 /* Release the semaphore. */
301 sem_post (&__aio_requests_sema
);
303 while (runp
!= NULL
);