int __pthread_timedsuspend_new(pthread_descr self, const struct timespec *abstime)
{
    sigset_t unblock, initial_mask;
    int was_signalled = 0;
    sigjmp_buf jmpbuf;

    if (sigsetjmp(jmpbuf, 1) == 0) {
	THREAD_SETMEM(self, p_signal_jmp, &jmpbuf);
	THREAD_SETMEM(self, p_signal, 0);
	/* Unblock the restart signal */
	sigemptyset(&unblock);
	sigaddset(&unblock, __pthread_sig_restart);
	sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask);

	while (1) {
	    struct timeval now;
	    struct timespec reltime;

	    /* Compute a time offset relative to now.  */
	    gettimeofday (&now, NULL);
	    reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000;
	    reltime.tv_sec = abstime->tv_sec - now.tv_sec;
	    if (reltime.tv_nsec < 0) {
		reltime.tv_nsec += 1000000000;
		reltime.tv_sec -= 1;
	    }

	    /* Sleep for the required duration. If woken by a signal,
	       resume waiting as required by Single Unix Specification.  */
	    if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0)
		break;
	}

	/* Block the restart signal again */
	sigprocmask(SIG_SETMASK, &initial_mask, NULL);
	was_signalled = 0;
    } else {
	was_signalled = 1;
    }
    THREAD_SETMEM(self, p_signal_jmp, NULL);

    /* Now was_signalled is true if we exited the above code
       due to the delivery of a restart signal.  In that case,
       everything is cool. We have been removed from whatever
       we were waiting on by the other thread, and consumed its signal.

       Otherwise we this thread woke up spontaneously, or due to a signal other
       than restart. This is an ambiguous case  that must be resolved by
       the caller; the thread is still eligible for a restart wakeup
       so there is a race. */

    READ_MEMORY_BARRIER(); /* See comment in __pthread_restart_new */
    return was_signalled;
}
Ejemplo n.º 2
0
void __pthread_lock(struct _pthread_fastlock*lock) {
  int cnt=0;
  struct timespec tm;
  while (__testandset(&lock->__spinlock)) {
    if (cnt<MAX_SPIN_COUNT) {
      sched_yield();
      cnt++;
    } else {
      tm.tv_sec=0;
      tm.tv_nsec=SPIN_SLEEP_DURATION;
      __libc_nanosleep(&tm, 0);
      cnt = 0;
    }
  }
}
int
__pthread_timedsuspend_old(pthread_descr self, const struct timespec *abstime)
{
  sigset_t unblock, initial_mask;
  int was_signalled = 0;
  sigjmp_buf jmpbuf;

  if (atomic_decrement(&self->p_resume_count) == 0) {
    /* Set up a longjmp handler for the restart signal, unblock
       the signal and sleep. */

    if (sigsetjmp(jmpbuf, 1) == 0) {
      THREAD_SETMEM(self, p_signal_jmp, &jmpbuf);
      THREAD_SETMEM(self, p_signal, 0);
      /* Unblock the restart signal */
      sigemptyset(&unblock);
      sigaddset(&unblock, __pthread_sig_restart);
      sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask);

      while (1) {
	struct timeval now;
	struct timespec reltime;

	/* Compute a time offset relative to now.  */
	__gettimeofday (&now, NULL);
	reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000;
	reltime.tv_sec = abstime->tv_sec - now.tv_sec;
	if (reltime.tv_nsec < 0) {
	  reltime.tv_nsec += 1000000000;
	  reltime.tv_sec -= 1;
	}

	/* Sleep for the required duration. If woken by a signal,
	   resume waiting as required by Single Unix Specification.  */
	if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0)
	  break;
      }

      /* Block the restart signal again */
      sigprocmask(SIG_SETMASK, &initial_mask, NULL);
      was_signalled = 0;
    } else {
      was_signalled = 1;
    }
    THREAD_SETMEM(self, p_signal_jmp, NULL);
  }

  /* Now was_signalled is true if we exited the above code
     due to the delivery of a restart signal.  In that case,
     we know we have been dequeued and resumed and that the
     resume count is balanced.  Otherwise, there are some
     cases to consider. First, try to bump up the resume count
     back to zero. If it goes to 1, it means restart() was
     invoked on this thread. The signal must be consumed
     and the count bumped down and everything is cool. We
     can return a 1 to the caller.
     Otherwise, no restart was delivered yet, so a potential
     race exists; we return a 0 to the caller which must deal
     with this race in an appropriate way; for example by
     atomically removing the thread from consideration for a
     wakeup---if such a thing fails, it means a restart is
     being delivered. */

  if (!was_signalled) {
    if (atomic_increment(&self->p_resume_count) != -1) {
      __pthread_wait_for_restart_signal(self);
      atomic_decrement(&self->p_resume_count); /* should be zero now! */
      /* woke spontaneously and consumed restart signal */
      return 1;
    }
    /* woke spontaneously but did not consume restart---caller must resolve */
    return 0;
  }
  /* woken due to restart signal */
  return 1;
}