[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#749087: libc6: Patch for pthread_spin_lock on sparc32/sparc64



Package: libc6
Version: 2.18-7
Severity: serious
Tags: upstream patch
Justification: causes ftbfs for src:kyotocabinet on sparc
Forwarded: https://sourceware.org/bugzilla/show_bug.cgi?id=16882
Control: affects -1 + src:kyotocabinet

Hi,

kyotocabinet failed to build on sparc[1], because of a test failure.
It's a deadlock due to a bug in pthread_spin_lock[2]. Glibc branches
from 2.16 to 2.19 are affected. Patches are attached[3][4]. (waiting
for upstream approval) I've tested it locally, and all the testcases
in kyotocabinet passed, resulting in a successful build.

[1]
https://buildd.debian.org/status/fetch.php?pkg=kyotocabinet&arch=sparc&ver=1.2.76-4&stamp=1370038499
[2] https://sourceware.org/bugzilla/show_bug.cgi?id=16882
[3] https://sourceware.org/bugzilla/attachment.cgi?id=7613&action=diff
[4] https://sourceware.org/bugzilla/attachment.cgi?id=7614&action=diff

Cheers,

Yixuan
>From d3f72a5abca98758c80cdd59f20e6abf2a0cab2a Mon Sep 17 00:00:00 2001
From: GUO Yixuan <culu.gyx@gmail.com>
Date: Thu, 22 May 2014 22:48:31 -0400
Subject: [PATCH 1/2] Fixed pthread_spin_lock on sparc32/64 (bug 16882)

The bug occurs under this situation.
  1. thread1 gets the lock, set the byte to FF
  2. when thread2 is trying to lock, it enters the loop,
     checking whether the byte is 00
  3. thread1 unlocks, set to 00
  4. thread2 finally gets the lock, without setting to FF
  5. thread3 gets the lock, before thread2 unlocks it
---
 nptl/sysdeps/sparc/sparc32/pthread_spin_lock.S | 4 ++--
 nptl/sysdeps/sparc/sparc64/pthread_spin_lock.S | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/nptl/sysdeps/sparc/sparc32/pthread_spin_lock.S b/nptl/sysdeps/sparc/sparc32/pthread_spin_lock.S
index ea863d7..3accc69 100644
--- a/nptl/sysdeps/sparc/sparc32/pthread_spin_lock.S
+++ b/nptl/sysdeps/sparc/sparc32/pthread_spin_lock.S
@@ -19,11 +19,11 @@
 
 	.text
 ENTRY(pthread_spin_lock)
-	ldstub		[%o0], %g1
+1:	ldstub		[%o0], %g1
 	orcc		%g1, 0x0, %g0
 	bne,a		2f
 	 ldub		[%o0], %g1
-1:	retl
+	retl
 	 mov		0, %o0
 2:	orcc		%g1, 0x0, %g0
 	bne,a		2b
diff --git a/nptl/sysdeps/sparc/sparc64/pthread_spin_lock.S b/nptl/sysdeps/sparc/sparc64/pthread_spin_lock.S
index 0f849b2..aec6654 100644
--- a/nptl/sysdeps/sparc/sparc64/pthread_spin_lock.S
+++ b/nptl/sysdeps/sparc/sparc64/pthread_spin_lock.S
@@ -19,10 +19,10 @@
 
 	.text
 ENTRY(pthread_spin_lock)
-	ldstub		[%o0], %g1
+1:	ldstub		[%o0], %g1
 	brnz,pn		%g1, 2f
 	 membar		#StoreLoad | #StoreStore
-1:	retl
+	retl
 	 mov		0, %o0
 2:	ldub		[%o0], %g1
 	brnz,pt		%g1, 2b
-- 
2.0.0.rc2

>From 1e11cc5a3689a4f960087ecd28188da580c67158 Mon Sep 17 00:00:00 2001
From: GUO Yixuan <culu.gyx@gmail.com>
Date: Thu, 22 May 2014 23:41:05 -0400
Subject: [PATCH 2/2] New test for pthread_spin_lock (bug 16882)

---
 nptl/Makefile    |   2 +-
 nptl/tst-spin4.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 110 insertions(+), 1 deletion(-)
 create mode 100644 nptl/tst-spin4.c

diff --git a/nptl/Makefile b/nptl/Makefile
index 7551406..0bb6ab1 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -210,7 +210,7 @@ tests = tst-typesizes \
 	tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 tst-mutexpi5 \
 	tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a tst-mutexpi8 \
 	tst-mutexpi9 \
-	tst-spin1 tst-spin2 tst-spin3 \
+	tst-spin1 tst-spin2 tst-spin3 tst-spin4 \
 	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 \
diff --git a/nptl/tst-spin4.c b/nptl/tst-spin4.c
new file mode 100644
index 0000000..5b23a17
--- /dev/null
+++ b/nptl/tst-spin4.c
@@ -0,0 +1,109 @@
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static int count = 0;
+
+static void *
+thread_add_one (void *arg)
+{
+  int tmp;
+  pthread_spinlock_t *lock = (pthread_spinlock_t *) arg;
+
+  /* When do_test holds the lock for 1 sec, the two thread will be
+     in contention for the lock. */
+  if (pthread_spin_lock (lock) != 0)
+    {
+      puts ("thread_add_one(): spin_lock failed");
+      pthread_exit ((void *) 1l);
+    }
+
+  /* sleep 1s before modifying count */
+  tmp = count;
+  sleep (1);
+  count = tmp + 1;
+
+  if (pthread_spin_unlock (lock) != 0)
+    {
+      puts ("thread_add_one(): spin_unlock failed");
+      pthread_exit ((void *) 1l);
+    }
+
+  return NULL;
+}
+
+static int
+do_test (void)
+{
+  pthread_t thr1, thr2;
+  pthread_spinlock_t lock;
+  int tmp;
+
+  if (pthread_spin_init (&lock, PTHREAD_PROCESS_PRIVATE) != 0)
+    {
+      puts ("spin_init failed");
+      return 1;
+    }
+
+  if (pthread_spin_lock (&lock) != 0)
+    {
+      puts ("1st spin_lock failed");
+      return 1;
+    }
+
+  if (pthread_create (&thr1, NULL, thread_add_one, (void *) &lock) != 0)
+    {
+      puts ("1st pthread_create failed");
+      return 1;
+    }
+
+  if (pthread_create (&thr2, NULL, thread_add_one, (void *) &lock) != 0)
+    {
+      puts ("2nd pthread_create failed");
+      return 1;
+    }
+
+  /* sleep 1s before modifying count */
+  tmp = count;
+  sleep (1);
+  count = tmp + 1;
+
+  if (pthread_spin_unlock (&lock) != 0)
+    {
+      puts ("1st spin_unlock failed");
+      return 1;
+    }
+
+  void *status;
+  if (pthread_join (thr1, &status) != 0)
+    {
+      puts ("1st pthread_join failed");
+      return 1;
+    }
+  if (status != NULL)
+    {
+      puts ("failure in the 1st thread");
+      return 1;
+    }
+  if (pthread_join (thr2, &status) != 0)
+    {
+      puts ("2nd pthread_join failed");
+      return 1;
+    }
+  if (status != NULL)
+    {
+      puts ("failure in the 2nd thread");
+      return 1;
+    }
+
+  if (count != 3)
+    {
+      printf ("count is %d, should be 3\n", count);
+      return 1;
+    }
+  return 0;
+}
+
+#define TIMEOUT 5
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
-- 
2.0.0.rc2


Reply to: