[BZ #3123]
authorUlrich Drepper <drepper@redhat.com>
Fri, 8 Sep 2006 10:41:17 +0000 (10:41 +0000)
committerUlrich Drepper <drepper@redhat.com>
Fri, 8 Sep 2006 10:41:17 +0000 (10:41 +0000)
2006-09-08  Ulrich Drepper  <drepper@redhat.com>
[BZ #3123]
* sysdeps/pthread/pthread_cond_wait.c (__condvar_cleanup): Don't
increment WAKEUP_SEQ if this would increase the value beyond TOTAL_SEQ.
* sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.c: Likewise.
* sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.c: Likewise.
* sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.c: Likewise.
* Makefile (tests): Add tst-cond22.
* tst-cond22.c: New file.

nptl/ChangeLog
nptl/Makefile
nptl/sysdeps/pthread/pthread_cond_wait.c
nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S
nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S
nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S
nptl/tst-cond22.c [new file with mode: 0644]

index 3e58f04..edc668c 100644 (file)
@@ -1,3 +1,14 @@
+2006-09-08  Ulrich Drepper  <drepper@redhat.com>
+
+       [BZ #3123]
+       * sysdeps/pthread/pthread_cond_wait.c (__condvar_cleanup): Don't
+       increment WAKEUP_SEQ if this would increase the value beyond TOTAL_SEQ.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.c: Likewise.
+       * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.c: Likewise.
+       * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.c: Likewise.
+       * Makefile (tests): Add tst-cond22.
+       * tst-cond22.c: New file.
+
 2006-09-05  Ulrich Drepper  <drepper@redhat.com>
 
        [BZ #3124]
index 03e4c7e..9393cab 100644 (file)
@@ -207,7 +207,7 @@ tests = tst-typesizes \
        tst-cond1 tst-cond2 tst-cond3 tst-cond4 tst-cond5 tst-cond6 tst-cond7 \
        tst-cond8 tst-cond9 tst-cond10 tst-cond11 tst-cond12 tst-cond13 \
        tst-cond14 tst-cond15 tst-cond16 tst-cond17 tst-cond18 tst-cond19 \
-       tst-cond20 tst-cond21 \
+       tst-cond20 tst-cond21 tst-cond22 \
        tst-robust1 tst-robust2 tst-robust3 tst-robust4 tst-robust5 \
        tst-robust6 tst-robust7 tst-robust8 \
        tst-robustpi1 tst-robustpi2 tst-robustpi3 tst-robustpi4 \
index 8666945..f641a7e 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
 
@@ -50,8 +50,12 @@ __condvar_cleanup (void *arg)
   if (cbuffer->bc_seq == cbuffer->cond->__data.__broadcast_seq)
     {
       /* This thread is not waiting anymore.  Adjust the sequence counters
-        appropriately.  */
-      ++cbuffer->cond->__data.__wakeup_seq;
+        appropriately.  We do not increment WAKEUP_SEQ if this would
+        bump it over the value of TOTAL_SEQ>  This can happen if a thread
+        was woken and then canceled.  */
+      if (cbuffer->cond->__data.__wakeup_seq
+         < cbuffer->cond->__data.__total_seq)
+       ++cbuffer->cond->__data.__wakeup_seq;
       ++cbuffer->cond->__data.__woken_seq;
       ++cbuffer->cond->__data.__futex;
     }
index 699c2cb..692e0dd 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -406,10 +406,21 @@ __condvar_tw_cleanup:
        cmpl    20(%esp), %eax
        jne     3f
 
-       addl    $1, wakeup_seq(%ebx)
+       /* We increment the woken_seq counter only if it is lower than
+          total_seq.  If this is not the case the thread was woken and
+          then canceled.  In this case we ignore the signal.  */
+       movl    total_seq(%ebx), %eax
+       movl    total_seq+4(%ebx), %edi
+       cmpl    wakeup_seq+4(%ebx), %edi
+       jb      6f
+       ja      7f
+       cmpl    wakeup_seq(%ebx), %eax
+       jbe     7f
+
+6:     addl    $1, wakeup_seq(%ebx)
        adcl    $0, wakeup_seq+4(%ebx)
 
-       addl    $1, cond_futex(%ebx)
+7:     addl    $1, cond_futex(%ebx)
 
        addl    $1, woken_seq(%ebx)
        adcl    $0, woken_seq+4(%ebx)
index d282785..7f93a85 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -297,11 +297,21 @@ __condvar_w_cleanup:
        cmpl    12(%esp), %eax
        jne     3f
 
-       addl    $1, wakeup_seq(%ebx)
+       /* We increment the woken_seq counter only if it is lower than
+          total_seq.  If this is not the case the thread was woken and
+          then canceled.  In this case we ignore the signal.  */
+       movl    total_seq(%ebx), %eax
+       movl    total_seq+4(%ebx), %edi
+       cmpl    wakeup_seq+4(%ebx), %edi
+       jb      6f
+       ja      7f
+       cmpl    wakeup_seq(%ebx), %eax
+       jbe     7f
+
+6:     addl    $1, wakeup_seq(%ebx)
        adcl    $0, wakeup_seq+4(%ebx)
 
-       addl    $1, cond_futex(%ebx)
-
+7:     addl    $1, cond_futex(%ebx)
        addl    $1, woken_seq(%ebx)
        adcl    $0, woken_seq+4(%ebx)
 
index b837d46..6b8091b 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -67,8 +67,14 @@ __condvar_cleanup:
        cmpl    4(%r8), %edx
        jne     3f
 
+       /* We increment the woken_seq counter only if it is lower than
+          total_seq.  If this is not the case the thread was woken and
+          then canceled.  In this case we ignore the signal.  */
+       movq    total_seq(%rdi), %rax
+       cmpq    wakeup_seq(%rdi), %rax
+       jbe     6f
        incq    wakeup_seq(%rdi)
-       incq    woken_seq(%rdi)
+6:     incq    woken_seq(%rdi)
        incl    cond_futex(%rdi)
 
 3:     subl    $(1 << clock_bits), cond_nwaiters(%rdi)
diff --git a/nptl/tst-cond22.c b/nptl/tst-cond22.c
new file mode 100644 (file)
index 0000000..0e829ff
--- /dev/null
@@ -0,0 +1,153 @@
+#include <pthreadP.h>
+#include <stdio.h>
+
+
+static pthread_barrier_t b;
+static pthread_cond_t c = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
+
+
+static void
+cl (void *arg)
+{
+  pthread_mutex_unlock (&m);
+}
+
+
+static void *
+tf (void *arg)
+{
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      printf ("%s: mutex_lock failed\n", __func__);
+      exit (1);
+    }
+  int e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __func__);
+      exit (1);
+    }
+  pthread_cleanup_push (cl, NULL);
+  if (pthread_cond_wait (&c, &m) != 0)
+    {
+      printf ("%s: cond_wait failed\n", __func__);
+      exit (1);
+    }
+  pthread_cleanup_pop (0);
+  if (pthread_mutex_unlock (&m) != 0)
+    {
+      printf ("%s: mutex_unlock failed\n", __func__);
+      exit (1);
+    }
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  int status = 0;
+
+  if (pthread_barrier_init (&b, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("1st create failed");
+      return 1;
+    }
+  int e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("1st barrier_wait failed");
+      return 1;
+    }
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("1st mutex_lock failed");
+      return 1;
+    }
+  if (pthread_cond_signal (&c) != 0)
+    {
+      puts ("1st cond_signal failed");
+      return 1;
+    }
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("cancel failed");
+      return 1;
+    }
+  if (pthread_mutex_unlock (&m) != 0)
+    {
+      puts ("1st mutex_unlock failed");
+      return 1;
+    }
+  void *res;
+  if (pthread_join (th, &res) != 0)
+    {
+      puts ("1st join failed");
+      return 1;
+    }
+  if (res != PTHREAD_CANCELED)
+    {
+      puts ("first thread not canceled");
+      status = 1;
+    }
+
+  printf ("cond = { %d, %x, %lld, %lld, %lld, %p, %u, %u }\n",
+         c.__data.__lock, c.__data.__futex, c.__data.__total_seq,
+         c.__data.__wakeup_seq, c.__data.__woken_seq, c.__data.__mutex,
+         c.__data.__nwaiters, c.__data.__broadcast_seq);
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("2nd create failed");
+      return 1;
+    }
+  e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("2nd barrier_wait failed");
+      return 1;
+    }
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("2nd mutex_lock failed");
+      return 1;
+    }
+  if (pthread_cond_signal (&c) != 0)
+    {
+      puts ("2nd cond_signal failed");
+      return 1;
+    }
+  if (pthread_mutex_unlock (&m) != 0)
+    {
+      puts ("2nd mutex_unlock failed");
+      return 1;
+    }
+  if (pthread_join (th, &res) != 0)
+    {
+      puts ("2nd join failed");
+      return 1;
+    }
+  if (res != NULL)
+    {
+      puts ("2nd thread canceled");
+      status = 1;
+    }
+
+  printf ("cond = { %d, %x, %lld, %lld, %lld, %p, %u, %u }\n",
+         c.__data.__lock, c.__data.__futex, c.__data.__total_seq,
+         c.__data.__wakeup_seq, c.__data.__woken_seq, c.__data.__mutex,
+         c.__data.__nwaiters, c.__data.__broadcast_seq);
+
+  return status;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"