Back to index

glibc  2.9
Functions
sem_timedwait.c File Reference
#include <errno.h>
#include <sysdep.h>
#include <lowlevellock.h>
#include <internaltypes.h>
#include <semaphore.h>
#include <pthreadP.h>
#include <shlib-compat.h>

Go to the source code of this file.

Functions

void __sem_wait_cleanup (void *arg) attribute_hidden
int sem_timedwait (sem_t *sem, const struct timespec *abstime)

Function Documentation

void __sem_wait_cleanup ( void *  arg)

Definition at line 33 of file sem_wait.c.

{
  struct new_sem *isem = (struct new_sem *) arg;

  atomic_decrement (&isem->nwaiters);
}
int sem_timedwait ( sem_t sem,
const struct timespec abstime 
)

Definition at line 35 of file sem_timedwait.c.

{
  struct sparc_new_sem *isem = (struct sparc_new_sem *) sem;
  int err;
  int val;

  if (__atomic_is_v9)
    val = atomic_decrement_if_positive (&isem->value);
  else
    {
      __sparc32_atomic_do_lock24 (&isem->lock);
      val = isem->value;
      if (val > 0)
        isem->value = val - 1;
      __sparc32_atomic_do_unlock24 (&isem->lock);
    }

  if (val > 0)
    return 0;

  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
    {
      __set_errno (EINVAL);
      return -1;
    }

  if (__atomic_is_v9)
    atomic_increment (&isem->nwaiters);
  else
    {
      __sparc32_atomic_do_lock24 (&isem->lock);
      isem->nwaiters++;
      __sparc32_atomic_do_unlock24 (&isem->lock);
    }

  pthread_cleanup_push (__sem_wait_cleanup, isem);

  while (1)
    {
      struct timeval tv;
      struct timespec rt;
      int sec, nsec;

      /* Get the current time.  */
      __gettimeofday (&tv, NULL);

      /* Compute relative timeout.  */
      sec = abstime->tv_sec - tv.tv_sec;
      nsec = abstime->tv_nsec - tv.tv_usec * 1000;
      if (nsec < 0)
       {
         nsec += 1000000000;
         --sec;
       }

      /* Already timed out?  */
      err = -ETIMEDOUT;
      if (sec < 0)
       {
         __set_errno (ETIMEDOUT);
         err = -1;
         break;
       }

      /* Do wait.  */
      rt.tv_sec = sec;
      rt.tv_nsec = nsec;

      /* Enable asynchronous cancellation.  Required by the standard.  */
      int oldtype = __pthread_enable_asynccancel ();

      err = lll_futex_timed_wait (&isem->value, 0, &rt,
                              isem->private ^ FUTEX_PRIVATE_FLAG);

      /* Disable asynchronous cancellation.  */
      __pthread_disable_asynccancel (oldtype);

      if (err != 0 && err != -EWOULDBLOCK)
       {
         __set_errno (-err);
         err = -1;
         break;
       }

      if (__atomic_is_v9)
       val = atomic_decrement_if_positive (&isem->value);
      else
       {
         __sparc32_atomic_do_lock24 (&isem->lock);
         val = isem->value;
         if (val > 0)
           isem->value = val - 1;
         __sparc32_atomic_do_unlock24 (&isem->lock);
       }

      if (val > 0)
       {
         err = 0;
         break;
       }
    }

  pthread_cleanup_pop (0);

  if (__atomic_is_v9)
    atomic_decrement (&isem->nwaiters);
  else
    {
      __sparc32_atomic_do_lock24 (&isem->lock);
      isem->nwaiters--;
      __sparc32_atomic_do_unlock24 (&isem->lock);
    }

  return err;
}

Here is the call graph for this function: