Back to index

glibc  2.9
lio_listio.c
Go to the documentation of this file.
00001 /* Enqueue and list of read or write requests.
00002    Copyright (C) 1997,1998,1999,2000,2001,2003,2005,2006
00003        Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
00005    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
00006 
00007    The GNU C Library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Lesser General Public
00009    License as published by the Free Software Foundation; either
00010    version 2.1 of the License, or (at your option) any later version.
00011 
00012    The GNU C Library is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Lesser General Public License for more details.
00016 
00017    You should have received a copy of the GNU Lesser General Public
00018    License along with the GNU C Library; if not, write to the Free
00019    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00020    02111-1307 USA.  */
00021 
00022 #ifndef lio_listio
00023 #include <aio.h>
00024 #include <assert.h>
00025 #include <errno.h>
00026 #include <stdlib.h>
00027 #include <unistd.h>
00028 
00029 #include <aio_misc.h>
00030 
00031 #define LIO_OPCODE_BASE 0
00032 #endif
00033 
00034 #include <shlib-compat.h>
00035 
00036 
00037 /* We need this special structure to handle asynchronous I/O.  */
00038 struct async_waitlist
00039   {
00040     int counter;
00041     struct sigevent sigev;
00042     struct waitlist list[0];
00043   };
00044 
00045 
00046 /* The code in glibc 2.1 to glibc 2.4 issued only one event when all
00047    requests submitted with lio_listio finished.  The existing practice
00048    is to issue events for the individual requests as well.  This is
00049    what the new code does.  */
00050 #if SHLIB_COMPAT (librt, GLIBC_2_1, GLIBC_2_4)
00051 # define LIO_MODE(mode) ((mode) & 127)
00052 # define NO_INDIVIDUAL_EVENT_P(mode) ((mode) & 128)
00053 #else
00054 # define LIO_MODE(mode) mode
00055 # define NO_INDIVIDUAL_EVENT_P(mode) 0
00056 #endif
00057 
00058 
00059 static int
00060 lio_listio_internal (int mode, struct aiocb *const list[], int nent,
00061                    struct sigevent *sig)
00062 {
00063   struct sigevent defsigev;
00064   struct requestlist *requests[nent];
00065   int cnt;
00066   volatile int total = 0;
00067   int result = 0;
00068 
00069   if (sig == NULL)
00070     {
00071       defsigev.sigev_notify = SIGEV_NONE;
00072       sig = &defsigev;
00073     }
00074 
00075   /* Request the mutex.  */
00076   pthread_mutex_lock (&__aio_requests_mutex);
00077 
00078   /* Now we can enqueue all requests.  Since we already acquired the
00079      mutex the enqueue function need not do this.  */
00080   for (cnt = 0; cnt < nent; ++cnt)
00081     if (list[cnt] != NULL && list[cnt]->aio_lio_opcode != LIO_NOP)
00082       {
00083        if (NO_INDIVIDUAL_EVENT_P (mode))
00084          list[cnt]->aio_sigevent.sigev_notify = SIGEV_NONE;
00085 
00086        requests[cnt] = __aio_enqueue_request ((aiocb_union *) list[cnt],
00087                                           (list[cnt]->aio_lio_opcode
00088                                            | LIO_OPCODE_BASE));
00089 
00090        if (requests[cnt] != NULL)
00091          /* Successfully enqueued.  */
00092          ++total;
00093        else
00094          /* Signal that we've seen an error.  `errno' and the error code
00095             of the aiocb will tell more.  */
00096          result = -1;
00097       }
00098     else
00099       requests[cnt] = NULL;
00100 
00101   if (total == 0)
00102     {
00103       /* We don't have anything to do except signalling if we work
00104         asynchronously.  */
00105 
00106       /* Release the mutex.  We do this before raising a signal since the
00107         signal handler might do a `siglongjmp' and then the mutex is
00108         locked forever.  */
00109       pthread_mutex_unlock (&__aio_requests_mutex);
00110 
00111       if (LIO_MODE (mode) == LIO_NOWAIT)
00112        {
00113 #ifdef BROKEN_THREAD_SIGNALS
00114        __aio_notify_only (sig,
00115                         sig->sigev_notify == SIGEV_SIGNAL ? getpid () : 0);
00116 #else
00117        __aio_notify_only (sig);
00118 #endif
00119        }
00120 
00121       return result;
00122     }
00123   else if (LIO_MODE (mode) == LIO_WAIT)
00124     {
00125 #ifndef DONT_NEED_AIO_MISC_COND
00126       pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
00127       int oldstate;
00128 #endif
00129       struct waitlist waitlist[nent];
00130 
00131       total = 0;
00132       for (cnt = 0; cnt < nent; ++cnt)
00133        {
00134          assert (requests[cnt] == NULL || list[cnt] != NULL);
00135 
00136          if (requests[cnt] != NULL && list[cnt]->aio_lio_opcode != LIO_NOP)
00137            {
00138 #ifndef DONT_NEED_AIO_MISC_COND
00139              waitlist[cnt].cond = &cond;
00140 #endif
00141              waitlist[cnt].result = &result;
00142              waitlist[cnt].next = requests[cnt]->waiting;
00143              waitlist[cnt].counterp = &total;
00144              waitlist[cnt].sigevp = NULL;
00145 #ifdef BROKEN_THREAD_SIGNALS
00146              waitlist[cnt].caller_pid = 0;       /* Not needed.  */
00147 #endif
00148              requests[cnt]->waiting = &waitlist[cnt];
00149              ++total;
00150            }
00151        }
00152 
00153 #ifdef DONT_NEED_AIO_MISC_COND
00154       AIO_MISC_WAIT (result, total, NULL, 0);
00155 #else
00156       /* Since `pthread_cond_wait'/`pthread_cond_timedwait' are cancellation
00157         points we must be careful.  We added entries to the waiting lists
00158         which we must remove.  So defer cancellation for now.  */
00159       pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &oldstate);
00160 
00161       while (total > 0)
00162        pthread_cond_wait (&cond, &__aio_requests_mutex);
00163 
00164       /* Now it's time to restore the cancellation state.  */
00165       pthread_setcancelstate (oldstate, NULL);
00166 
00167       /* Release the conditional variable.  */
00168       if (pthread_cond_destroy (&cond) != 0)
00169        /* This must never happen.  */
00170        abort ();
00171 #endif
00172 
00173       /* If any of the I/O requests failed, return -1 and set errno.  */
00174       if (result != 0)
00175        {
00176          __set_errno (result == EINTR ? EINTR : EIO);
00177          result = -1;
00178        }
00179     }
00180   else
00181     {
00182       struct async_waitlist *waitlist;
00183 
00184       waitlist = (struct async_waitlist *)
00185        malloc (sizeof (struct async_waitlist)
00186               + (nent * sizeof (struct waitlist)));
00187 
00188       if (waitlist == NULL)
00189        {
00190          __set_errno (EAGAIN);
00191          result = -1;
00192        }
00193       else
00194        {
00195 #ifdef BROKEN_THREAD_SIGNALS
00196          pid_t caller_pid = sig->sigev_notify == SIGEV_SIGNAL ? getpid () : 0;
00197 #endif
00198          total = 0;
00199 
00200          for (cnt = 0; cnt < nent; ++cnt)
00201            {
00202              assert (requests[cnt] == NULL || list[cnt] != NULL);
00203 
00204              if (requests[cnt] != NULL
00205                 && list[cnt]->aio_lio_opcode != LIO_NOP)
00206               {
00207 #ifndef DONT_NEED_AIO_MISC_COND
00208                 waitlist->list[cnt].cond = NULL;
00209 #endif
00210                 waitlist->list[cnt].result = NULL;
00211                 waitlist->list[cnt].next = requests[cnt]->waiting;
00212                 waitlist->list[cnt].counterp = &waitlist->counter;
00213                 waitlist->list[cnt].sigevp = &waitlist->sigev;
00214 #ifdef BROKEN_THREAD_SIGNALS
00215                 waitlist->list[cnt].caller_pid = caller_pid;
00216 #endif
00217                 requests[cnt]->waiting = &waitlist->list[cnt];
00218                 ++total;
00219               }
00220            }
00221 
00222          waitlist->counter = total;
00223          waitlist->sigev = *sig;
00224        }
00225     }
00226 
00227   /* Release the mutex.  */
00228   pthread_mutex_unlock (&__aio_requests_mutex);
00229 
00230   return result;
00231 }
00232 
00233 
00234 #if SHLIB_COMPAT (librt, GLIBC_2_1, GLIBC_2_4)
00235 int
00236 attribute_compat_text_section
00237 __lio_listio_21 (int mode, struct aiocb *const list[], int nent,
00238                struct sigevent *sig)
00239 {
00240   /* Check arguments.  */
00241   if (mode != LIO_WAIT && mode != LIO_NOWAIT)
00242     {
00243       __set_errno (EINVAL);
00244       return -1;
00245     }
00246 
00247   return lio_listio_internal (mode | LIO_NO_INDIVIDUAL_EVENT, list, nent, sig);
00248 }
00249 compat_symbol (librt, __lio_listio_21, lio_listio, GLIBC_2_1);
00250 #endif
00251 
00252 
00253 int
00254 __lio_listio_item_notify (int mode, struct aiocb *const list[], int nent,
00255                        struct sigevent *sig)
00256 {
00257     /* Check arguments.  */
00258   if (mode != LIO_WAIT && mode != LIO_NOWAIT)
00259     {
00260       __set_errno (EINVAL);
00261       return -1;
00262     }
00263 
00264   return lio_listio_internal (mode, list, nent, sig);
00265 }
00266 versioned_symbol (librt, __lio_listio_item_notify, lio_listio, GLIBC_2_4);