Back to index

glibc  2.9
aio_suspend.c
Go to the documentation of this file.
00001 /* Suspend until termination of a requests.
00002    Copyright (C) 1997-2000,2002,2003,2005,2006 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 
00022 /* We use an UGLY hack to prevent gcc from finding us cheating.  The
00023    implementations of aio_suspend and aio_suspend64 are identical and so
00024    we want to avoid code duplication by using aliases.  But gcc sees
00025    the different parameter lists and prints a warning.  We define here
00026    a function so that aio_suspend64 has no prototype.  */
00027 #define aio_suspend64 XXX
00028 #include <aio.h>
00029 /* And undo the hack.  */
00030 #undef aio_suspend64
00031 
00032 #include <assert.h>
00033 #include <errno.h>
00034 #include <stdbool.h>
00035 #include <stdlib.h>
00036 #include <sys/time.h>
00037 
00038 #include <bits/libc-lock.h>
00039 #include <aio_misc.h>
00040 
00041 
00042 struct clparam
00043 {
00044   const struct aiocb *const *list;
00045   struct waitlist *waitlist;
00046   struct requestlist **requestlist;
00047 #ifndef DONT_NEED_AIO_MISC_COND
00048   pthread_cond_t *cond;
00049 #endif
00050   int nent;
00051 };
00052 
00053 
00054 static void
00055 cleanup (void *arg)
00056 {
00057 #ifdef DONT_NEED_AIO_MISC_COND
00058   /* Acquire the mutex.  If pthread_cond_*wait is used this would
00059      happen implicitly.  */
00060   pthread_mutex_lock (&__aio_requests_mutex);
00061 #endif
00062 
00063   const struct clparam *param = (const struct clparam *) arg;
00064 
00065   /* Now remove the entry in the waiting list for all requests
00066      which didn't terminate.  */
00067   int cnt = param->nent;
00068   while (cnt-- > 0)
00069     if (param->list[cnt] != NULL
00070        && param->list[cnt]->__error_code == EINPROGRESS)
00071       {
00072        struct waitlist **listp;
00073 
00074        assert (param->requestlist[cnt] != NULL);
00075 
00076        /* There is the chance that we cannot find our entry anymore. This
00077           could happen if the request terminated and restarted again.  */
00078        listp = &param->requestlist[cnt]->waiting;
00079        while (*listp != NULL && *listp != &param->waitlist[cnt])
00080          listp = &(*listp)->next;
00081 
00082        if (*listp != NULL)
00083          *listp = (*listp)->next;
00084       }
00085 
00086 #ifndef DONT_NEED_AIO_MISC_COND
00087   /* Release the conditional variable.  */
00088   (void) pthread_cond_destroy (param->cond);
00089 #endif
00090 
00091   /* Release the mutex.  */
00092   pthread_mutex_unlock (&__aio_requests_mutex);
00093 }
00094 
00095 
00096 int
00097 aio_suspend (list, nent, timeout)
00098      const struct aiocb *const list[];
00099      int nent;
00100      const struct timespec *timeout;
00101 {
00102   if (__builtin_expect (nent < 0, 0))
00103     {
00104       __set_errno (EINVAL);
00105       return -1;
00106     }
00107 
00108   struct waitlist waitlist[nent];
00109   struct requestlist *requestlist[nent];
00110 #ifndef DONT_NEED_AIO_MISC_COND
00111   pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
00112 #endif
00113   int cnt;
00114   bool any = false;
00115   int result = 0;
00116   int cntr = 1;
00117 
00118   /* Request the mutex.  */
00119   pthread_mutex_lock (&__aio_requests_mutex);
00120 
00121   /* There is not yet a finished request.  Signal the request that
00122      we are working for it.  */
00123   for (cnt = 0; cnt < nent; ++cnt)
00124     if (list[cnt] != NULL)
00125       {
00126        if (list[cnt]->__error_code == EINPROGRESS)
00127          {
00128            requestlist[cnt] = __aio_find_req ((aiocb_union *) list[cnt]);
00129 
00130            if (requestlist[cnt] != NULL)
00131              {
00132 #ifndef DONT_NEED_AIO_MISC_COND
00133               waitlist[cnt].cond = &cond;
00134 #endif
00135               waitlist[cnt].result = NULL;
00136               waitlist[cnt].next = requestlist[cnt]->waiting;
00137               waitlist[cnt].counterp = &cntr;
00138               waitlist[cnt].sigevp = NULL;
00139 #ifdef BROKEN_THREAD_SIGNALS
00140               waitlist[cnt].caller_pid = 0;      /* Not needed.  */
00141 #endif
00142               requestlist[cnt]->waiting = &waitlist[cnt];
00143               any = true;
00144              }
00145            else
00146              /* We will never suspend.  */
00147              break;
00148          }
00149        else
00150          /* We will never suspend.  */
00151          break;
00152       }
00153 
00154 
00155   /* Only if none of the entries is NULL or finished to be wait.  */
00156   if (cnt == nent && any)
00157     {
00158       struct clparam clparam =
00159        {
00160          .list = list,
00161          .waitlist = waitlist,
00162          .requestlist = requestlist,
00163 #ifndef DONT_NEED_AIO_MISC_COND
00164          .cond = &cond,
00165 #endif
00166          .nent = nent
00167        };
00168 
00169       pthread_cleanup_push (cleanup, &clparam);
00170 
00171 #ifdef DONT_NEED_AIO_MISC_COND
00172       AIO_MISC_WAIT (result, cntr, timeout, 1);
00173 #else
00174       if (timeout == NULL)
00175        result = pthread_cond_wait (&cond, &__aio_requests_mutex);
00176       else
00177        {
00178          /* We have to convert the relative timeout value into an
00179             absolute time value with pthread_cond_timedwait expects.  */
00180          struct timeval now;
00181          struct timespec abstime;
00182 
00183          __gettimeofday (&now, NULL);
00184          abstime.tv_nsec = timeout->tv_nsec + now.tv_usec * 1000;
00185          abstime.tv_sec = timeout->tv_sec + now.tv_sec;
00186          if (abstime.tv_nsec >= 1000000000)
00187            {
00188              abstime.tv_nsec -= 1000000000;
00189              abstime.tv_sec += 1;
00190            }
00191 
00192          result = pthread_cond_timedwait (&cond, &__aio_requests_mutex,
00193                                       &abstime);
00194        }
00195 #endif
00196 
00197       pthread_cleanup_pop (0);
00198     }
00199 
00200   /* Now remove the entry in the waiting list for all requests
00201      which didn't terminate.  */
00202   while (cnt-- > 0)
00203     if (list[cnt] != NULL && list[cnt]->__error_code == EINPROGRESS)
00204       {
00205        struct waitlist **listp;
00206 
00207        assert (requestlist[cnt] != NULL);
00208 
00209        /* There is the chance that we cannot find our entry anymore. This
00210           could happen if the request terminated and restarted again.  */
00211        listp = &requestlist[cnt]->waiting;
00212        while (*listp != NULL && *listp != &waitlist[cnt])
00213          listp = &(*listp)->next;
00214 
00215        if (*listp != NULL)
00216          *listp = (*listp)->next;
00217       }
00218 
00219 #ifndef DONT_NEED_AIO_MISC_COND
00220   /* Release the conditional variable.  */
00221   if (__builtin_expect (pthread_cond_destroy (&cond) != 0, 0))
00222     /* This must never happen.  */
00223     abort ();
00224 #endif
00225 
00226   if (result != 0)
00227     {
00228 #ifndef DONT_NEED_AIO_MISC_COND
00229       /* An error occurred.  Possibly it's ETIMEDOUT.  We have to translate
00230         the timeout error report of `pthread_cond_timedwait' to the
00231         form expected from `aio_suspend'.  */
00232       if (result == ETIMEDOUT)
00233        __set_errno (EAGAIN);
00234       else
00235 #endif
00236        __set_errno (result);
00237 
00238       result = -1;
00239     }
00240 
00241   /* Release the mutex.  */
00242   pthread_mutex_unlock (&__aio_requests_mutex);
00243 
00244   return result;
00245 }
00246 
00247 weak_alias (aio_suspend, aio_suspend64)