Minor comment fix
[kopensolaris-gnu/glibc.git] / sysdeps / pthread / lio_listio.c
1 /* Enqueue and list of read or write requests.
2    Copyright (C) 1997,1998,1999,2000,2001,2003,2005,2006
3         Free Software Foundation, Inc.
4    This file is part of the GNU C Library.
5    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
6
7    The GNU C Library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Lesser General Public
9    License as published by the Free Software Foundation; either
10    version 2.1 of the License, or (at your option) any later version.
11
12    The GNU C Library is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16
17    You should have received a copy of the GNU Lesser General Public
18    License along with the GNU C Library; if not, write to the Free
19    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20    02111-1307 USA.  */
21
22 #ifndef lio_listio
23 #include <aio.h>
24 #include <assert.h>
25 #include <errno.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28
29 #include <aio_misc.h>
30
31 #define LIO_OPCODE_BASE 0
32 #endif
33
34 #include <shlib-compat.h>
35
36
37 /* We need this special structure to handle asynchronous I/O.  */
38 struct async_waitlist
39   {
40     int counter;
41     struct sigevent sigev;
42     struct waitlist list[0];
43   };
44
45
46 /* The code in glibc 2.1 to glibc 2.4 issued only one event when all
47    requests submitted with lio_listio finished.  The existing practice
48    is to issue events for the individual requests as well.  This is
49    what the new code does.  */
50 #if SHLIB_COMPAT (librt, GLIBC_2_1, GLIBC_2_4)
51 # define LIO_MODE(mode) ((mode) & 127)
52 # define NO_INDIVIDUAL_EVENT_P(mode) ((mode) & 128)
53 #else
54 # define LIO_MODE(mode) mode
55 # define NO_INDIVIDUAL_EVENT_P(mode) 0
56 #endif
57
58
59 static int
60 lio_listio_internal (int mode, struct aiocb *const list[], int nent,
61                      struct sigevent *sig)
62 {
63   struct sigevent defsigev;
64   struct requestlist *requests[nent];
65   int cnt;
66   volatile int total = 0;
67   int result = 0;
68
69   if (sig == NULL)
70     {
71       defsigev.sigev_notify = SIGEV_NONE;
72       sig = &defsigev;
73     }
74
75   /* Request the mutex.  */
76   pthread_mutex_lock (&__aio_requests_mutex);
77
78   /* Now we can enqueue all requests.  Since we already acquired the
79      mutex the enqueue function need not do this.  */
80   for (cnt = 0; cnt < nent; ++cnt)
81     if (list[cnt] != NULL && list[cnt]->aio_lio_opcode != LIO_NOP)
82       {
83         if (NO_INDIVIDUAL_EVENT_P (mode))
84           list[cnt]->aio_sigevent.sigev_notify = SIGEV_NONE;
85
86         requests[cnt] = __aio_enqueue_request ((aiocb_union *) list[cnt],
87                                                (list[cnt]->aio_lio_opcode
88                                                 | LIO_OPCODE_BASE));
89
90         if (requests[cnt] != NULL)
91           /* Successfully enqueued.  */
92           ++total;
93         else
94           /* Signal that we've seen an error.  `errno' and the error code
95              of the aiocb will tell more.  */
96           result = -1;
97       }
98     else
99       requests[cnt] = NULL;
100
101   if (total == 0)
102     {
103       /* We don't have anything to do except signalling if we work
104          asynchronously.  */
105
106       /* Release the mutex.  We do this before raising a signal since the
107          signal handler might do a `siglongjmp' and then the mutex is
108          locked forever.  */
109       pthread_mutex_unlock (&__aio_requests_mutex);
110
111       if (LIO_MODE (mode) == LIO_NOWAIT)
112         {
113 #ifdef BROKEN_THREAD_SIGNALS
114         __aio_notify_only (sig,
115                            sig->sigev_notify == SIGEV_SIGNAL ? getpid () : 0);
116 #else
117         __aio_notify_only (sig);
118 #endif
119         }
120
121       return result;
122     }
123   else if (LIO_MODE (mode) == LIO_WAIT)
124     {
125 #ifndef DONT_NEED_AIO_MISC_COND
126       pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
127       int oldstate;
128 #endif
129       struct waitlist waitlist[nent];
130
131       total = 0;
132       for (cnt = 0; cnt < nent; ++cnt)
133         {
134           assert (requests[cnt] == NULL || list[cnt] != NULL);
135
136           if (requests[cnt] != NULL && list[cnt]->aio_lio_opcode != LIO_NOP)
137             {
138 #ifndef DONT_NEED_AIO_MISC_COND
139               waitlist[cnt].cond = &cond;
140 #endif
141               waitlist[cnt].result = &result;
142               waitlist[cnt].next = requests[cnt]->waiting;
143               waitlist[cnt].counterp = &total;
144               waitlist[cnt].sigevp = NULL;
145 #ifdef BROKEN_THREAD_SIGNALS
146               waitlist[cnt].caller_pid = 0;     /* Not needed.  */
147 #endif
148               requests[cnt]->waiting = &waitlist[cnt];
149               ++total;
150             }
151         }
152
153 #ifdef DONT_NEED_AIO_MISC_COND
154       AIO_MISC_WAIT (result, total, NULL, 0);
155 #else
156       /* Since `pthread_cond_wait'/`pthread_cond_timedwait' are cancellation
157          points we must be careful.  We added entries to the waiting lists
158          which we must remove.  So defer cancellation for now.  */
159       pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &oldstate);
160
161       while (total > 0 && result == 0)
162         result = pthread_cond_wait (&cond, &__aio_requests_mutex);
163
164       /* Now it's time to restore the cancellation state.  */
165       pthread_setcancelstate (oldstate, NULL);
166
167       /* Release the conditional variable.  */
168       if (pthread_cond_destroy (&cond) != 0)
169         /* This must never happen.  */
170         abort ();
171 #endif
172
173       /* If any of the I/O requests failed, return -1 and set errno.  */
174       if (result != 0)
175         {
176           __set_errno (result == EINTR ? EINTR : EIO);
177           result = -1;
178         }
179     }
180   else
181     {
182       struct async_waitlist *waitlist;
183
184       waitlist = (struct async_waitlist *)
185         malloc (sizeof (struct async_waitlist)
186                 + (nent * sizeof (struct waitlist)));
187
188       if (waitlist == NULL)
189         {
190           __set_errno (EAGAIN);
191           result = -1;
192         }
193       else
194         {
195 #ifdef BROKEN_THREAD_SIGNALS
196           pid_t caller_pid = sig->sigev_notify == SIGEV_SIGNAL ? getpid () : 0;
197 #endif
198           total = 0;
199
200           for (cnt = 0; cnt < nent; ++cnt)
201             {
202               assert (requests[cnt] == NULL || list[cnt] != NULL);
203
204               if (requests[cnt] != NULL
205                   && list[cnt]->aio_lio_opcode != LIO_NOP)
206                 {
207 #ifndef DONT_NEED_AIO_MISC_COND
208                   waitlist->list[cnt].cond = NULL;
209 #endif
210                   waitlist->list[cnt].result = NULL;
211                   waitlist->list[cnt].next = requests[cnt]->waiting;
212                   waitlist->list[cnt].counterp = &waitlist->counter;
213                   waitlist->list[cnt].sigevp = &waitlist->sigev;
214 #ifdef BROKEN_THREAD_SIGNALS
215                   waitlist->list[cnt].caller_pid = caller_pid;
216 #endif
217                   requests[cnt]->waiting = &waitlist->list[cnt];
218                   ++total;
219                 }
220             }
221
222           waitlist->counter = total;
223           waitlist->sigev = *sig;
224         }
225     }
226
227   /* Release the mutex.  */
228   pthread_mutex_unlock (&__aio_requests_mutex);
229
230   return result;
231 }
232
233
234 #if SHLIB_COMPAT (librt, GLIBC_2_1, GLIBC_2_4)
235 int
236 attribute_compat_text_section
237 __lio_listio_21 (int mode, struct aiocb *const list[], int nent,
238                  struct sigevent *sig)
239 {
240   /* Check arguments.  */
241   if (mode != LIO_WAIT && mode != LIO_NOWAIT)
242     {
243       __set_errno (EINVAL);
244       return -1;
245     }
246
247   return lio_listio_internal (mode | LIO_NO_INDIVIDUAL_EVENT, list, nent, sig);
248 }
249 compat_symbol (librt, __lio_listio_21, lio_listio, GLIBC_2_1);
250 #endif
251
252
253 int
254 __lio_listio_item_notify (int mode, struct aiocb *const list[], int nent,
255                           struct sigevent *sig)
256 {
257     /* Check arguments.  */
258   if (mode != LIO_WAIT && mode != LIO_NOWAIT)
259     {
260       __set_errno (EINVAL);
261       return -1;
262     }
263
264   return lio_listio_internal (mode, list, nent, sig);
265 }
266 versioned_symbol (librt, __lio_listio_item_notify, lio_listio, GLIBC_2_4);