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;
}
void __pthread_wait_for_restart_signal(pthread_descr self)
{
    sigset_t mask;

    sigprocmask(SIG_SETMASK, NULL, &mask); /* Get current signal mask */
    sigdelset(&mask, __pthread_sig_restart); /* Unblock the restart signal */
    THREAD_SETMEM(self, p_signal, 0);
    do {
	sigsuspend(&mask);                   /* Wait for signal */
    } while (THREAD_GETMEM(self, p_signal) !=__pthread_sig_restart);

    READ_MEMORY_BARRIER(); /* See comment in __pthread_restart_new */
}
Esempio n. 3
0
int __pthread_once(pthread_once_t * once_control, void (*init_routine)(void))
{
  /* flag for doing the condition broadcast outside of mutex */
  int state_changed;

  /* Test without locking first for speed */
  if (*once_control == DONE) {
    READ_MEMORY_BARRIER();
    return 0;
  }
  /* Lock and test again */

  state_changed = 0;

  pthread_mutex_lock(&once_masterlock);

  /* If this object was left in an IN_PROGRESS state in a parent
     process (indicated by stale generation field), reset it to NEVER. */
  if ((*once_control & 3) == IN_PROGRESS && (*once_control & ~3) != fork_generation)
    *once_control = NEVER;

  /* If init_routine is being called from another routine, wait until
     it completes. */
  while ((*once_control & 3) == IN_PROGRESS) {
    pthread_cond_wait(&once_finished, &once_masterlock);
  }
  /* Here *once_control is stable and either NEVER or DONE. */
  if (*once_control == NEVER) {
    *once_control = IN_PROGRESS | fork_generation;
    pthread_mutex_unlock(&once_masterlock);
    pthread_cleanup_push(pthread_once_cancelhandler, once_control);
    init_routine();
    pthread_cleanup_pop(0);
    pthread_mutex_lock(&once_masterlock);
    WRITE_MEMORY_BARRIER();
    *once_control = DONE;
    state_changed = 1;
  }
  pthread_mutex_unlock(&once_masterlock);

  if (state_changed)
    pthread_cond_broadcast(&once_finished);

  return 0;
}