Back to index

glibc  2.9
sem_timedwait.c
Go to the documentation of this file.
00001 /* sem_timedwait -- wait on a semaphore.  SPARC version.
00002    Copyright (C) 2003, 2006, 2007 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
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 #include <errno.h>
00022 #include <sysdep.h>
00023 #include <lowlevellock.h>
00024 #include <internaltypes.h>
00025 #include <semaphore.h>
00026 
00027 #include <pthreadP.h>
00028 #include <shlib-compat.h>
00029 
00030 
00031 extern void __sem_wait_cleanup (void *arg) attribute_hidden;
00032 
00033 
00034 int
00035 sem_timedwait (sem_t *sem, const struct timespec *abstime)
00036 {
00037   struct sparc_new_sem *isem = (struct sparc_new_sem *) sem;
00038   int err;
00039   int val;
00040 
00041   if (__atomic_is_v9)
00042     val = atomic_decrement_if_positive (&isem->value);
00043   else
00044     {
00045       __sparc32_atomic_do_lock24 (&isem->lock);
00046       val = isem->value;
00047       if (val > 0)
00048         isem->value = val - 1;
00049       __sparc32_atomic_do_unlock24 (&isem->lock);
00050     }
00051 
00052   if (val > 0)
00053     return 0;
00054 
00055   if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
00056     {
00057       __set_errno (EINVAL);
00058       return -1;
00059     }
00060 
00061   if (__atomic_is_v9)
00062     atomic_increment (&isem->nwaiters);
00063   else
00064     {
00065       __sparc32_atomic_do_lock24 (&isem->lock);
00066       isem->nwaiters++;
00067       __sparc32_atomic_do_unlock24 (&isem->lock);
00068     }
00069 
00070   pthread_cleanup_push (__sem_wait_cleanup, isem);
00071 
00072   while (1)
00073     {
00074       struct timeval tv;
00075       struct timespec rt;
00076       int sec, nsec;
00077 
00078       /* Get the current time.  */
00079       __gettimeofday (&tv, NULL);
00080 
00081       /* Compute relative timeout.  */
00082       sec = abstime->tv_sec - tv.tv_sec;
00083       nsec = abstime->tv_nsec - tv.tv_usec * 1000;
00084       if (nsec < 0)
00085        {
00086          nsec += 1000000000;
00087          --sec;
00088        }
00089 
00090       /* Already timed out?  */
00091       err = -ETIMEDOUT;
00092       if (sec < 0)
00093        {
00094          __set_errno (ETIMEDOUT);
00095          err = -1;
00096          break;
00097        }
00098 
00099       /* Do wait.  */
00100       rt.tv_sec = sec;
00101       rt.tv_nsec = nsec;
00102 
00103       /* Enable asynchronous cancellation.  Required by the standard.  */
00104       int oldtype = __pthread_enable_asynccancel ();
00105 
00106       err = lll_futex_timed_wait (&isem->value, 0, &rt,
00107                               isem->private ^ FUTEX_PRIVATE_FLAG);
00108 
00109       /* Disable asynchronous cancellation.  */
00110       __pthread_disable_asynccancel (oldtype);
00111 
00112       if (err != 0 && err != -EWOULDBLOCK)
00113        {
00114          __set_errno (-err);
00115          err = -1;
00116          break;
00117        }
00118 
00119       if (__atomic_is_v9)
00120        val = atomic_decrement_if_positive (&isem->value);
00121       else
00122        {
00123          __sparc32_atomic_do_lock24 (&isem->lock);
00124          val = isem->value;
00125          if (val > 0)
00126            isem->value = val - 1;
00127          __sparc32_atomic_do_unlock24 (&isem->lock);
00128        }
00129 
00130       if (val > 0)
00131        {
00132          err = 0;
00133          break;
00134        }
00135     }
00136 
00137   pthread_cleanup_pop (0);
00138 
00139   if (__atomic_is_v9)
00140     atomic_decrement (&isem->nwaiters);
00141   else
00142     {
00143       __sparc32_atomic_do_lock24 (&isem->lock);
00144       isem->nwaiters--;
00145       __sparc32_atomic_do_unlock24 (&isem->lock);
00146     }
00147 
00148   return err;
00149 }