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 new_sem *isem = (struct new_sem *) arg;
00036 
00037   atomic_decrement (&isem->nwaiters);
00038 }
00039 
00040 
00041 int
00042 __new_sem_wait (sem_t *sem)
00043 {
00044   struct new_sem *isem = (struct new_sem *) sem;
00045   int err;
00046 
00047   if (atomic_decrement_if_positive (&isem->value) > 0)
00048     return 0;
00049 
00050   atomic_increment (&isem->nwaiters);
00051 
00052   pthread_cleanup_push (__sem_wait_cleanup, isem);
00053 
00054   while (1)
00055     {
00056       /* Enable asynchronous cancellation.  Required by the standard.  */
00057       int oldtype = __pthread_enable_asynccancel ();
00058 
00059       err = lll_futex_wait (&isem->value, 0,
00060                          isem->private ^ FUTEX_PRIVATE_FLAG);
00061 
00062       /* Disable asynchronous cancellation.  */
00063       __pthread_disable_asynccancel (oldtype);
00064 
00065       if (err != 0 && err != -EWOULDBLOCK)
00066        {
00067          __set_errno (-err);
00068          err = -1;
00069          break;
00070        }
00071 
00072       if (atomic_decrement_if_positive (&isem->value) > 0)
00073        {
00074          err = 0;
00075          break;
00076        }
00077     }
00078 
00079   pthread_cleanup_pop (0);
00080 
00081   atomic_decrement (&isem->nwaiters);
00082 
00083   return err;
00084 }
00085 versioned_symbol (libpthread, __new_sem_wait, sem_wait, GLIBC_2_1);
00086 
00087 
00088 #if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_1)
00089 int
00090 attribute_compat_text_section
00091 __old_sem_wait (sem_t *sem)
00092 {
00093   int *futex = (int *) sem;
00094   int err;
00095 
00096   do
00097     {
00098       if (atomic_decrement_if_positive (futex) > 0)
00099        return 0;
00100 
00101       /* Enable asynchronous cancellation.  Required by the standard.  */
00102       int oldtype = __pthread_enable_asynccancel ();
00103 
00104       /* Always assume the semaphore is shared.  */
00105       err = lll_futex_wait (futex, 0, LLL_SHARED);
00106 
00107       /* Disable asynchronous cancellation.  */
00108       __pthread_disable_asynccancel (oldtype);
00109     }
00110   while (err == 0 || err == -EWOULDBLOCK);
00111 
00112   __set_errno (-err);
00113   return -1;
00114 }
00115 
00116 compat_symbol (libpthread, __old_sem_wait, sem_wait, GLIBC_2_0);
00117 #endif