Fixed incorrect use of mvcle introduced by 2001-07-12 change.
[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 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
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    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, write to the Free
18    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20
21 #include <aio.h>
22 #include <assert.h>
23 #include <errno.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26
27 #include "aio_misc.h"
28
29
30 /* We need this special structure to handle asynchronous I/O.  */
31 struct async_waitlist
32   {
33     int counter;
34     struct sigevent sigev;
35     struct waitlist list[0];
36   };
37
38
39 int
40 lio_listio (mode, list, nent, sig)
41      int mode;
42      struct aiocb *const list[];
43      int nent;
44      struct sigevent *sig;
45 {
46   struct sigevent defsigev;
47   struct requestlist *requests[nent];
48   int cnt;
49   volatile int total = 0;
50   int result = 0;
51
52   /* Check arguments.  */
53   if (mode != LIO_WAIT && mode != LIO_NOWAIT)
54     {
55       __set_errno (EINVAL);
56       return -1;
57     }
58
59   if (sig == NULL)
60     {
61       defsigev.sigev_notify = SIGEV_NONE;
62       sig = &defsigev;
63     }
64
65   /* Request the mutex.  */
66   pthread_mutex_lock (&__aio_requests_mutex);
67
68   /* Now we can enqueue all requests.  Since we already acquired the
69      mutex the enqueue function need not do this.  */
70   for (cnt = 0; cnt < nent; ++cnt)
71     if (list[cnt] != NULL && list[cnt]->aio_lio_opcode != LIO_NOP)
72       {
73         list[cnt]->aio_sigevent.sigev_notify = SIGEV_NONE;
74         requests[cnt] = __aio_enqueue_request ((aiocb_union *) list[cnt],
75                                                list[cnt]->aio_lio_opcode);
76
77         if (requests[cnt] != NULL)
78           /* Successfully enqueued.  */
79           ++total;
80         else
81           /* Signal that we've seen an error.  `errno' and the error code
82              of the aiocb will tell more.  */
83           result = -1;
84       }
85     else
86       requests[cnt] = NULL;
87
88   if (total == 0)
89     {
90       /* We don't have anything to do except signalling if we work
91          asynchronously.  */
92
93       /* Release the mutex.  We do this before raising a signal since the
94          signal handler might do a `siglongjmp' and then the mutex is
95          locked forever.  */
96       pthread_mutex_unlock (&__aio_requests_mutex);
97
98       if (mode == LIO_NOWAIT)
99         __aio_notify_only (sig,
100                            sig->sigev_notify == SIGEV_SIGNAL ? getpid () : 0);
101
102       return result;
103     }
104   else if (mode == LIO_WAIT)
105     {
106       pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
107       struct waitlist waitlist[nent];
108       int oldstate;
109
110       total = 0;
111       for (cnt = 0; cnt < nent; ++cnt)
112         {
113           assert (requests[cnt] == NULL || list[cnt] != NULL);
114
115           if (requests[cnt] != NULL && list[cnt]->aio_lio_opcode != LIO_NOP)
116             {
117               waitlist[cnt].cond = &cond;
118               waitlist[cnt].next = requests[cnt]->waiting;
119               waitlist[cnt].counterp = &total;
120               waitlist[cnt].sigevp = NULL;
121               waitlist[cnt].caller_pid = 0;     /* Not needed.  */
122               requests[cnt]->waiting = &waitlist[cnt];
123               ++total;
124             }
125         }
126
127       /* Since `pthread_cond_wait'/`pthread_cond_timedwait' are cancelation
128          points we must be careful.  We added entries to the waiting lists
129          which we must remove.  So defer cancelation for now.  */
130       pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &oldstate);
131
132       while (total > 0)
133         pthread_cond_wait (&cond, &__aio_requests_mutex);
134
135       /* Now it's time to restore the cancelation state.  */
136       pthread_setcancelstate (oldstate, NULL);
137
138       /* Release the conditional variable.  */
139       if (pthread_cond_destroy (&cond) != 0)
140         /* This must never happen.  */
141         abort ();
142     }
143   else
144     {
145       struct async_waitlist *waitlist;
146
147       waitlist = (struct async_waitlist *)
148         malloc (sizeof (struct async_waitlist)
149                 + (nent * sizeof (struct waitlist)));
150
151       if (waitlist == NULL)
152         {
153           __set_errno (EAGAIN);
154           result = -1;
155         }
156       else
157         {
158           pid_t caller_pid = sig->sigev_notify == SIGEV_SIGNAL ? getpid () : 0;
159           total = 0;
160
161           for (cnt = 0; cnt < nent; ++cnt)
162             {
163               assert (requests[cnt] == NULL || list[cnt] != NULL);
164
165               if (requests[cnt] != NULL
166                   && list[cnt]->aio_lio_opcode != LIO_NOP)
167                 {
168                   waitlist->list[cnt].cond = NULL;
169                   waitlist->list[cnt].next = requests[cnt]->waiting;
170                   waitlist->list[cnt].counterp = &waitlist->counter;
171                   waitlist->list[cnt].sigevp = &waitlist->sigev;
172                   waitlist->list[cnt].caller_pid = caller_pid;
173                   requests[cnt]->waiting = &waitlist->list[cnt];
174                   ++total;
175                 }
176             }
177
178           waitlist->counter = total;
179           waitlist->sigev = *sig;
180         }
181     }
182
183   /* Release the mutex.  */
184   pthread_mutex_unlock (&__aio_requests_mutex);
185
186   return result;
187 }