All the mail mirrored from lore.kernel.org
 help / color / mirror / Atom feed
From: Kevin Hendricks <khendricks@ivey.uwo.ca>
To: linuxppc-dev@lists.linuxppc.org, Andreas Jaeger <aj@suse.de>,
	Jesper Skov <jskov@cygnus.co.uk>
Subject: Bug in glibc 2.1.3 linuxthreads in pthread_cond_timedwait_relative
Date: Fri, 28 Jan 2000 17:45:14 -0500	[thread overview]
Message-ID: <00012814481500.18396@localhost.localdomain> (raw)
In-Reply-To: <vtou2jy3t2q.fsf@astra.cs.uni-dortmund.de>


Hi,

Checkout the following code piece.  reltime is set by pthread_condtimedwait
before it calls pthread_cond_timedwait_relative_new.

That routine calls nanosleep with reltime and NULL.

If this routine gets an interrupt nanosleep is called again with reltime.

But according to the man page for nanosleep reltime is not changed from before.
If the remaining time is needed the NULL should have been changed in the
nanosleep call.

So if enough interrupts hit this thread within the timeout, it will effectively
always restart itself and hang forever.

I will put together a formal patch but this one was nasty to find since there
have to be enogh signals to keep the thread restarting with the old reltime.



Kevin


static int
pthread_cond_timedwait_relative_new(pthread_cond_t *cond,
                                pthread_mutex_t *mutex,
                                const struct timespec * reltime)
{
  volatile pthread_descr self = thread_self();
  sigset_t unblock, initial_mask;
  int retsleep, already_canceled, was_signalled;
  sigjmp_buf jmpbuf;
  pthread_extricate_if extr;

requeue_and_wait_again:

  retsleep = 0;
  already_canceled = 0;
  was_signalled = 0;

  /* Set up extrication interface */
  extr.pu_object = cond;
  extr.pu_extricate_func = cond_extricate_func;

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

  /* Enqueue to wait on the condition and check for cancellation. */
  __pthread_lock(&cond->__c_lock, self);
  if (!(THREAD_GETMEM(self, p_canceled)
      && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
    enqueue(&cond->__c_waiting, self);
  else
    already_canceled = 1;
  __pthread_unlock(&cond->__c_lock);

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

  pthread_mutex_unlock(mutex);

  /* 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);
    /* Sleep for the required duration */
    retsleep = __libc_nanosleep(reltime, NULL);
    /* Block the restart signal again */
    sigprocmask(SIG_SETMASK, &initial_mask, NULL);
    was_signalled = 0;
  } else {
    retsleep = -1;
    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 the queue
     by the other thread, and consumed its signal.

     Otherwise we this thread woke up spontaneously, or due to a signal other
     than restart. The next thing to do is to try to remove the thread
     from the queue. This may fail due to a race against another thread
     trying to do the same. In the failed case, we know we were signalled,
     and we may also have to consume a restart signal. */

  if (!was_signalled) {
    int was_on_queue;

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

    __pthread_lock(&cond->__c_lock, self);
    was_on_queue = remove_from_queue(&cond->__c_waiting, self);
    __pthread_unlock(&cond->__c_lock);

    if (was_on_queue) {
      __pthread_set_own_extricate_if(self, 0);
:   /* __pthread_lock will queue back any spurious restarts that
       may happen to it. */

    __pthread_lock(&cond->__c_lock, self);
    was_on_queue = remove_from_queue(&cond->__c_waiting, self);
    __pthread_unlock(&cond->__c_lock);

    if (was_on_queue) {
      __pthread_set_own_extricate_if(self, 0);
      pthread_mutex_lock(mutex);

      if (retsleep == 0)
        return ETIMEDOUT;
      /* Woken by a signal: resume waiting as
         required by Single Unix Specification. */
      goto requeue_and_wait_again;
    }

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

  __pthread_set_own_extricate_if(self, 0);

  /* The remaining logic is the same as in other cancellable waits,
     such as pthread_join sem_wait or pthread_cond wait. */

  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_mutex_lock(mutex);
    pthread_exit(PTHREAD_CANCELED);
  }

  pthread_mutex_lock(mutex);
  return 0;
}

** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/

       reply	other threads:[~2000-01-28 22:45 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <Pine.LNX.3.95.1000128103100.276B-100000@www.mprojects>
     [not found] ` <00012814071700.05087@localhost.localdomain>
     [not found]   ` <vtou2jy3t2q.fsf@astra.cs.uni-dortmund.de>
2000-01-28 22:45     ` Kevin Hendricks [this message]
2000-01-29  3:10       ` Bug in glibc 2.1.3 linuxthreads in pthread_cond_timedwait_relative scott hutinger

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=00012814481500.18396@localhost.localdomain \
    --to=khendricks@ivey.uwo.ca \
    --cc=aj@suse.de \
    --cc=jskov@cygnus.co.uk \
    --cc=linuxppc-dev@lists.linuxppc.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.