Exemplo n.º 1
0
int
__pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock,
			      const struct timespec *abstime)
{
  pthread_descr self;
  pthread_extricate_if extr;

  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
    return EINVAL;

  self = thread_self ();

  /* Set up extrication interface */
  extr.pu_object = rwlock;
  extr.pu_extricate_func =  rwlock_wr_extricate_func;

  /* Register extrication interface */
  __pthread_set_own_extricate_if (self, &extr);

  while(1)
    {
      __pthread_lock (&rwlock->__rw_lock, self);

      if (rwlock->__rw_readers == 0 && rwlock->__rw_writer == NULL)
	{
	  rwlock->__rw_writer = self;
	  __pthread_set_own_extricate_if (self, 0);
	  __pthread_unlock (&rwlock->__rw_lock);
	  return 0;
	}

      /* Suspend ourselves, then try again */
      enqueue (&rwlock->__rw_write_waiting, self);
      __pthread_unlock (&rwlock->__rw_lock);
      /* This is not a cancellation point */
      if (timedsuspend (self, abstime) == 0)
	{
	  int was_on_queue;

	  __pthread_lock (&rwlock->__rw_lock, self);
	  was_on_queue = remove_from_queue (&rwlock->__rw_write_waiting, self);
	  __pthread_unlock (&rwlock->__rw_lock);

	  if (was_on_queue)
	    {
	      __pthread_set_own_extricate_if (self, 0);
	      return ETIMEDOUT;
	    }

	  /* Eat the outstanding restart() from the signaller */
	  suspend (self);
	}
    }
}
Exemplo n.º 2
0
int sem_wait(sem_t * sem)
{
  __volatile__ pthread_descr self = thread_self();
  pthread_extricate_if extr;
  int already_canceled = 0;
  int spurious_wakeup_count;

  /* Set up extrication interface */
  extr.pu_object = sem;
  extr.pu_extricate_func = new_sem_extricate_func;

  __pthread_lock(&sem->__sem_lock, self);
  if (sem->__sem_value > 0) {
    sem->__sem_value--;
    __pthread_unlock(&sem->__sem_lock);
    return 0;
  }
  /* Register extrication interface */
  THREAD_SETMEM(self, p_sem_avail, 0);
  __pthread_set_own_extricate_if(self, &extr);
  /* Enqueue only if not already cancelled. */
  if (!(THREAD_GETMEM(self, p_canceled)
      && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
    enqueue(&sem->__sem_waiting, self);
  else
    already_canceled = 1;
  __pthread_unlock(&sem->__sem_lock);

  if (already_canceled) {
    __pthread_set_own_extricate_if(self, 0);
    __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
  }

  /* Wait for sem_post or cancellation, or fall through if already canceled */
  spurious_wakeup_count = 0;
  while (1)
    {
      suspend(self);
      if (THREAD_GETMEM(self, p_sem_avail) == 0
	  && (THREAD_GETMEM(self, p_woken_by_cancel) == 0
	      || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
	{
	  /* Count resumes that don't belong to us. */
	  spurious_wakeup_count++;
	  continue;
	}
      break;
    }
  __pthread_set_own_extricate_if(self, 0);

  /* Terminate only if the wakeup came from cancellation. */
  /* Otherwise ignore cancellation because we got the semaphore. */

  if (THREAD_GETMEM(self, p_woken_by_cancel)
      && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
    THREAD_SETMEM(self, p_woken_by_cancel, 0);
    __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
  }
  /* We got the semaphore */
  return 0;
}
Exemplo n.º 3
0
int sem_timedwait(sem_t *sem, const struct timespec *abstime)
{
  pthread_descr self = thread_self();
  pthread_extricate_if extr;
  int already_canceled = 0;
  int spurious_wakeup_count;

  __pthread_lock(&sem->__sem_lock, self);
  if (sem->__sem_value > 0) {
    --sem->__sem_value;
    __pthread_unlock(&sem->__sem_lock);
    return 0;
  }

  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) {
    /* The standard requires that if the function would block and the
       time value is illegal, the function returns with an error.  */
    __pthread_unlock(&sem->__sem_lock);
    __set_errno (EINVAL);
    return -1;
  }

  /* Set up extrication interface */
  extr.pu_object = sem;
  extr.pu_extricate_func = new_sem_extricate_func;

  /* Register extrication interface */
  THREAD_SETMEM(self, p_sem_avail, 0);
  __pthread_set_own_extricate_if(self, &extr);
  /* Enqueue only if not already cancelled. */
  if (!(THREAD_GETMEM(self, p_canceled)
      && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
    enqueue(&sem->__sem_waiting, self);
  else
    already_canceled = 1;
  __pthread_unlock(&sem->__sem_lock);

  if (already_canceled) {
    __pthread_set_own_extricate_if(self, 0);
    __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
  }

  spurious_wakeup_count = 0;
  while (1)
    {
      if (timedsuspend(self, abstime) == 0) {
	int was_on_queue;

	/* __pthread_lock will queue back any spurious restarts that
	   may happen to it. */

	__pthread_lock(&sem->__sem_lock, self);
	was_on_queue = remove_from_queue(&sem->__sem_waiting, self);
	__pthread_unlock(&sem->__sem_lock);

	if (was_on_queue) {
	  __pthread_set_own_extricate_if(self, 0);
	  __set_errno (ETIMEDOUT);
	  return -1;
	}

	/* Eat the outstanding restart() from the signaller */
	suspend(self);
      }

      if (THREAD_GETMEM(self, p_sem_avail) == 0
	  && (THREAD_GETMEM(self, p_woken_by_cancel) == 0
	      || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
	{
	  /* Count resumes that don't belong to us. */
	  spurious_wakeup_count++;
	  continue;
	}
      break;
    }

 __pthread_set_own_extricate_if(self, 0);

  /* Terminate only if the wakeup came from cancellation. */
  /* Otherwise ignore cancellation because we got the semaphore. */

  if (THREAD_GETMEM(self, p_woken_by_cancel)
      && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
    THREAD_SETMEM(self, p_woken_by_cancel, 0);
    __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
  }
  /* We got the semaphore */
  return 0;
}
Exemplo n.º 4
0
int
__pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock,
			      const struct timespec *abstime)
{
  pthread_descr self = NULL;
  pthread_readlock_info *existing;
  int out_of_mem, have_lock_already;
  pthread_extricate_if extr;

  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
    return EINVAL;

  have_lock_already = rwlock_have_already(&self, rwlock,
					  &existing, &out_of_mem);

  if (self == NULL)
    self = thread_self ();

  /* Set up extrication interface */
  extr.pu_object = rwlock;
  extr.pu_extricate_func = rwlock_rd_extricate_func;

  /* Register extrication interface */
  __pthread_set_own_extricate_if (self, &extr);

  for (;;)
    {
      __pthread_lock (&rwlock->__rw_lock, self);

      if (rwlock_can_rdlock(rwlock, have_lock_already))
	break;

      enqueue (&rwlock->__rw_read_waiting, self);
      __pthread_unlock (&rwlock->__rw_lock);
      /* This is not a cancellation point */
      if (timedsuspend (self, abstime) == 0)
	{
	  int was_on_queue;

	  __pthread_lock (&rwlock->__rw_lock, self);
	  was_on_queue = remove_from_queue (&rwlock->__rw_read_waiting, self);
	  __pthread_unlock (&rwlock->__rw_lock);

	  if (was_on_queue)
	    {
	      __pthread_set_own_extricate_if (self, 0);
	      return ETIMEDOUT;
	    }

	  /* Eat the outstanding restart() from the signaller */
	  suspend (self);
	}
    }

  __pthread_set_own_extricate_if (self, 0);

  ++rwlock->__rw_readers;
  __pthread_unlock (&rwlock->__rw_lock);

  if (have_lock_already || out_of_mem)
    {
      if (existing != NULL)
	++existing->pr_lock_count;
      else
	++self->p_untracked_readlock_count;
    }

  return 0;
}
Exemplo n.º 5
0
int __old_sem_wait(old_sem_t * sem)
{
    long oldstatus, newstatus;
    volatile pthread_descr self = thread_self();
    pthread_descr * th;
    pthread_extricate_if extr;

    /* Set up extrication interface */
    extr.pu_object = 0;
    extr.pu_extricate_func = old_sem_extricate_func;

    while (1) {
	/* Register extrication interface */
	__pthread_set_own_extricate_if(self, &extr);
	do {
            oldstatus = sem->sem_status;
            if ((oldstatus & 1) && (oldstatus != 1))
		newstatus = oldstatus - 2;
            else {
		newstatus = (long) self;
		self->p_nextwaiting = (pthread_descr) oldstatus;
	    }
	}
	while (! sem_compare_and_swap(sem, oldstatus, newstatus));
	if (newstatus & 1) {
	    /* We got the semaphore. */
	    __pthread_set_own_extricate_if(self, 0);
	    self->p_nextwaiting = NULL;
	    return 0;
	}
	/* Wait for sem_post or cancellation */
	suspend(self);
	__pthread_set_own_extricate_if(self, 0);

	/* This is a cancellation point */
	if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) {
	    /* Remove ourselves from the waiting list if we're still on it */
	    /* First check if we're at the head of the list. */
            do {
		oldstatus = sem->sem_status;
		if (oldstatus != (long) self) break;
		newstatus = (long) self->p_nextwaiting;
	    }
            while (! sem_compare_and_swap(sem, oldstatus, newstatus));
            /* Now, check if we're somewhere in the list.
	       There's a race condition with sem_post here, but it does not matter:
	       the net result is that at the time pthread_exit is called,
	       self is no longer reachable from sem->sem_status. */
            if (oldstatus != (long) self && (oldstatus & 1) == 0) {
		for (th = &(((pthread_descr) oldstatus)->p_nextwaiting);
		     *th != NULL && *th != (pthread_descr) 1;
		     th = &((*th)->p_nextwaiting)) {
		    if (*th == self) {
			*th = self->p_nextwaiting;
			break;
		    }
		}
	    }
            __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
	}
    }
}
Exemplo n.º 6
0
int pthread_join(pthread_t thread_id, void ** thread_return)
{
  volatile pthread_descr self = thread_self();
  struct pthread_request request;
  pthread_handle handle = thread_handle(thread_id);
  pthread_descr th;
  pthread_extricate_if extr;
  int already_canceled = 0;
  PDEBUG("\n");

  /* Set up extrication interface */
  extr.pu_object = handle;
  extr.pu_extricate_func = join_extricate_func;

  __pthread_lock(&handle->h_lock, self);
  if (invalid_handle(handle, thread_id)) {
    __pthread_unlock(&handle->h_lock);
    return ESRCH;
  }
  th = handle->h_descr;
  if (th == self) {
    __pthread_unlock(&handle->h_lock);
    return EDEADLK;
  }
  /* If detached or already joined, error */
  if (th->p_detached || th->p_joining != NULL) {
    __pthread_unlock(&handle->h_lock);
    return EINVAL;
  }
  /* If not terminated yet, suspend ourselves. */
  if (! th->p_terminated) {
    /* Register extrication interface */
    __pthread_set_own_extricate_if(self, &extr);
    if (!(THREAD_GETMEM(self, p_canceled)
	&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
      th->p_joining = self;
    else
      already_canceled = 1;
    __pthread_unlock(&handle->h_lock);

    if (already_canceled) {
      __pthread_set_own_extricate_if(self, 0);
      __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
    }

  PDEBUG("before suspend\n");
    suspend(self);
  PDEBUG("after suspend\n");
    /* Deregister extrication interface */
    __pthread_set_own_extricate_if(self, 0);

    /* This is a cancellation point */
    if (THREAD_GETMEM(self, p_woken_by_cancel)
	&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
      THREAD_SETMEM(self, p_woken_by_cancel, 0);
      __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
    }
    __pthread_lock(&handle->h_lock, self);
  }
  /* Get return value */
  if (thread_return != NULL) *thread_return = th->p_retval;
  __pthread_unlock(&handle->h_lock);
  /* Send notification to thread manager */
  if (__pthread_manager_request >= 0) {
    request.req_thread = self;
    request.req_kind = REQ_FREE;
    request.req_args.free.thread_id = thread_id;
    TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request,
		(char *) &request, sizeof(request)));
  }
  return 0;
}