Back to index

glibc  2.9
sem_wait.c
Go to the documentation of this file.
00001 /* sem_wait -- wait on a semaphore.  Generic futex-using version.
00002    Copyright (C) 2003, 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 void
00032 attribute_hidden
00033 __sem_wait_cleanup (void *arg)
00034 {
00035   struct sparc_new_sem *isem = (struct sparc_new_sem *) arg;
00036 
00037   if (__atomic_is_v9)
00038     atomic_decrement (&isem->nwaiters);
00039   else
00040     {
00041       __sparc32_atomic_do_lock24 (&isem->lock);
00042       isem->nwaiters--;
00043       __sparc32_atomic_do_unlock24 (&isem->lock);
00044     }
00045 }
00046 
00047 
00048 int
00049 __new_sem_wait (sem_t *sem)
00050 {
00051   struct sparc_new_sem *isem = (struct sparc_new_sem *) sem;
00052   int err;
00053   int val;
00054 
00055   if (__atomic_is_v9)
00056     val = atomic_decrement_if_positive (&isem->value);
00057   else
00058     {
00059       __sparc32_atomic_do_lock24 (&isem->lock);
00060       val = isem->value;
00061       if (val > 0)
00062        isem->value = val - 1;
00063       else
00064        isem->nwaiters++;
00065       __sparc32_atomic_do_unlock24 (&isem->lock);
00066     }
00067 
00068   if (val > 0)
00069     return 0;
00070 
00071   if (__atomic_is_v9)
00072     atomic_increment (&isem->nwaiters);
00073   else
00074     /* Already done above while still holding isem->lock.  */;
00075 
00076   pthread_cleanup_push (__sem_wait_cleanup, isem);
00077 
00078   while (1)
00079     {
00080       /* Enable asynchronous cancellation.  Required by the standard.  */
00081       int oldtype = __pthread_enable_asynccancel ();
00082 
00083       err = lll_futex_wait (&isem->value, 0,
00084                          isem->private ^ FUTEX_PRIVATE_FLAG);
00085 
00086       /* Disable asynchronous cancellation.  */
00087       __pthread_disable_asynccancel (oldtype);
00088 
00089       if (err != 0 && err != -EWOULDBLOCK)
00090        {
00091          __set_errno (-err);
00092          err = -1;
00093          break;
00094        }
00095 
00096       if (__atomic_is_v9)
00097        val = atomic_decrement_if_positive (&isem->value);
00098       else
00099        {
00100          __sparc32_atomic_do_lock24 (&isem->lock);
00101          val = isem->value;
00102          if (val > 0)
00103            isem->value = val - 1;
00104          __sparc32_atomic_do_unlock24 (&isem->lock);
00105        }
00106 
00107       if (val > 0)
00108        {
00109          err = 0;
00110          break;
00111        }
00112     }
00113 
00114   pthread_cleanup_pop (0);
00115 
00116   if (__atomic_is_v9)
00117     atomic_decrement (&isem->nwaiters);
00118   else
00119     {
00120       __sparc32_atomic_do_lock24 (&isem->lock);
00121       isem->nwaiters--;
00122       __sparc32_atomic_do_unlock24 (&isem->lock);
00123     }
00124 
00125   return err;
00126 }
00127 versioned_symbol (libpthread, __new_sem_wait, sem_wait, GLIBC_2_1);
00128 
00129 
00130 #if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_1)
00131 int
00132 attribute_compat_text_section
00133 __old_sem_wait (sem_t *sem)
00134 {
00135   struct sparc_old_sem *isem = (struct sparc_old_sem *) sem;
00136   int err;
00137   int val;
00138 
00139   do
00140     {
00141       if (__atomic_is_v9)
00142        val = atomic_decrement_if_positive (&isem->value);
00143       else
00144        {
00145          __sparc32_atomic_do_lock24 (&isem->lock);
00146          val = isem->value;
00147          if (val > 0)
00148            isem->value = val - 1;
00149          __sparc32_atomic_do_unlock24 (&isem->lock);
00150        }
00151 
00152       if (val > 0)
00153        return 0;
00154 
00155       /* Enable asynchronous cancellation.  Required by the standard.  */
00156       int oldtype = __pthread_enable_asynccancel ();
00157 
00158       err = lll_futex_wait (&isem->value, 0,
00159                          isem->private ^ FUTEX_PRIVATE_FLAG);
00160 
00161       /* Disable asynchronous cancellation.  */
00162       __pthread_disable_asynccancel (oldtype);
00163     }
00164   while (err == 0 || err == -EWOULDBLOCK);
00165 
00166   __set_errno (-err);
00167   return -1;
00168 }
00169 
00170 compat_symbol (libpthread, __old_sem_wait, sem_wait, GLIBC_2_0);
00171 #endif