This is the mail archive of the libc-hacker@sources.redhat.com mailing list for the glibc project.

Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Avoid cancellation point in pthread_mutex_lock etc. in linuxthreads


Hi!

linuxthreads call sigsuspend from pthread_mutex_lock etc., so when sigsuspend
was made cancellation point in December, suddenly all pthread primitives
which wait for restart signals are cancellation points.
Fix below, tested on all the usual arches.

2003-04-01  Jakub Jelinek  <jakub at redhat dot com>

linuxthreads/
	* pthread.c (__pthread_wait_for_restart_signal): Use
	__pthread_sigsuspend instead of sigsuspend.
	* internals.h (__pthread_sigsuspend): New prototype.
	* Makefile (libpthread-routines): Add pt-sigsuspend.
	(tests): Add tst-cancel7.
	* sysdeps/unix/sysv/linux/pt-sigsuspend.c: New file.
	* sysdeps/unix/sysv/linux/alpha/pt-sigsuspend.S: New file.
	* sysdeps/unix/sysv/linux/ia64/pt-sigsuspend.c: New file.
	* sysdeps/unix/sysv/linux/s390/s390-64/pt-sigsuspend.c: New file.
	* sysdeps/unix/sysv/linux/sparc/sparc64/pt-sigsuspend.c: New file.
	* sysdeps/unix/sysv/linux/x86_64/pt-sigsuspend.c: New file.
	* tst-cancel7.c: New test.
libc/
	* sysdeps/unix/sysv/linux/sparc/sparc64/sigsuspend.c: Use the
	IA-64 version.

--- libc/linuxthreads/Makefile.jj	2003-02-22 17:53:57.000000000 -0500
+++ libc/linuxthreads/Makefile	2003-04-01 05:27:16.000000000 -0500
@@ -36,8 +36,8 @@ extra-libs-others := $(extra-libs)
 install-lib-ldscripts := libpthread.so
 
 libpthread-routines := attr cancel condvar join manager mutex ptfork \
-		       ptlongjmp pthread signals specific errno lockfile \
-		       semaphore spinlock rwlock pt-machine \
+		       ptlongjmp pthread pt-sigsuspend signals specific errno \
+		       lockfile semaphore spinlock rwlock pt-machine \
 		       oldsemaphore events getcpuclockid pspinlock barrier \
 		       ptclock_gettime ptclock_settime sighandler \
 		       pthandles libc-tls-loc pt-allocrtsig \
@@ -89,7 +89,7 @@ tests = ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 
 	tststack $(tests-nodelete-$(have-z-nodelete)) ecmutex ex14 ex15 ex16 \
 	ex17 ex18 tst-cancel tst-context bug-sleep \
 	tst-cancel1 tst-cancel2 tst-cancel3 tst-cancel4 tst-cancel5 \
-	tst-cancel6 tst-popen tst-popen2
+	tst-cancel6 tst-cancel7 tst-popen tst-popen2
 test-srcs = tst-signal
 # These tests are linked with libc before libpthread
 tests-reverse += tst-cancel5
--- libc/linuxthreads/tst-cancel7.c.jj	2003-04-01 06:07:27.000000000 -0500
+++ libc/linuxthreads/tst-cancel7.c	2003-04-01 06:41:34.000000000 -0500
@@ -0,0 +1,110 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub at redhat dot com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+pthread_barrier_t b;
+int value = 0;
+
+static void *
+tf (void *arg)
+{
+  int r = pthread_barrier_wait (&b);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  pthread_mutex_lock (&lock);
+  ++value;
+  pthread_testcancel ();
+  ++value;
+  pthread_mutex_unlock (&lock);
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_mutex_lock (&lock);
+
+  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 ("pthread_create failed");
+      return 1;
+    }
+
+  int r = pthread_barrier_wait (&b);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("pthread_cancel failed");
+      return 1;
+    }
+
+  pthread_mutex_unlock (&lock);
+
+  void *status;
+  if (pthread_join (th, &status) != 0)
+    {
+      puts ("join failed");
+      return 1;
+    }
+
+  if (status != PTHREAD_CANCELED)
+    {
+      puts ("thread not canceled");
+      return 1;
+    }
+                                                                                          
+  if (value == 0)
+    {
+      puts ("thread cancelled in the pthread_mutex_lock call");
+      return 1;
+    }
+
+  if (value != 1)
+    {
+      puts ("thread not cancelled in pthread_testcancel call");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
--- libc/linuxthreads/pthread.c.jj	2003-03-06 12:26:17.000000000 -0500
+++ libc/linuxthreads/pthread.c	2003-04-01 04:56:53.000000000 -0500
@@ -1144,7 +1144,8 @@ void __pthread_wait_for_restart_signal(p
   sigdelset(&mask, __pthread_sig_restart); /* Unblock the restart signal */
   THREAD_SETMEM(self, p_signal, 0);
   do {
-    sigsuspend(&mask);                   /* Wait for signal */
+    __pthread_sigsuspend(&mask);	/* Wait for signal.  Must not be a
+					   cancellation point. */
   } while (THREAD_GETMEM(self, p_signal) !=__pthread_sig_restart);
 
   READ_MEMORY_BARRIER(); /* See comment in __pthread_restart_new */
--- libc/linuxthreads/sysdeps/unix/sysv/linux/ia64/pt-sigsuspend.c.jj	2003-04-01 05:09:33.000000000 -0500
+++ libc/linuxthreads/sysdeps/unix/sysv/linux/ia64/pt-sigsuspend.c	2003-04-01 05:12:37.000000000 -0500
@@ -0,0 +1,32 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <sysdep.h>
+#include <sys/syscall.h>
+#include <linuxthreads/internals.h>
+
+void
+__pthread_sigsuspend (const sigset_t *set)
+{
+  INTERNAL_SYSCALL_DECL (err);
+  INTERNAL_SYSCALL (rt_sigsuspend, err, 2, set, _NSIG / 8);
+}
--- libc/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-64/pt-sigsuspend.c.jj	2003-04-01 05:16:33.000000000 -0500
+++ libc/linuxthreads/sysdeps/unix/sysv/linux/s390/s390-64/pt-sigsuspend.c	2003-04-01 05:16:48.000000000 -0500
@@ -0,0 +1 @@
+#include "../../ia64/pt-sigsuspend.c"
--- libc/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc64/pt-sigsuspend.c.jj	2003-04-01 05:16:33.000000000 -0500
+++ libc/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc64/pt-sigsuspend.c	2003-04-01 05:16:48.000000000 -0500
@@ -0,0 +1 @@
+#include "../../ia64/pt-sigsuspend.c"
--- libc/linuxthreads/sysdeps/unix/sysv/linux/x86_64/pt-sigsuspend.c.jj	2003-04-01 05:16:33.000000000 -0500
+++ libc/linuxthreads/sysdeps/unix/sysv/linux/x86_64/pt-sigsuspend.c	2003-04-01 05:16:29.000000000 -0500
@@ -0,0 +1 @@
+#include "../ia64/pt-sigsuspend.c"
--- libc/linuxthreads/sysdeps/unix/sysv/linux/alpha/pt-sigsuspend.S.jj	2003-04-01 05:05:55.000000000 -0500
+++ libc/linuxthreads/sysdeps/unix/sysv/linux/alpha/pt-sigsuspend.S	2003-04-01 05:08:30.000000000 -0500
@@ -0,0 +1,27 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+
+#undef PSEUDO_PREPARE_ARGS
+#define PSEUDO_PREPARE_ARGS	ldq	a0, 0(a0);
+
+	.hidden __pthread_sigsuspend
+PSEUDO_NOERRNO(__pthread_sigsuspend, sigsuspend, 1)
+	ret
+PSEUDO_END_NOERRNO(__pthread_sigsuspend)
--- libc/linuxthreads/sysdeps/unix/sysv/linux/pt-sigsuspend.c.jj	2003-04-01 04:48:47.000000000 -0500
+++ libc/linuxthreads/sysdeps/unix/sysv/linux/pt-sigsuspend.c	2003-04-01 05:13:26.000000000 -0500
@@ -0,0 +1,55 @@
+/* Copyright (C) 1996-2000, 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <sysdep.h>
+#include <sys/syscall.h>
+#include <linuxthreads/internals.h>
+
+#include "kernel-features.h"
+
+void
+__pthread_sigsuspend (const sigset_t *set)
+{
+  INTERNAL_SYSCALL_DECL (err);
+#if !__ASSUME_REALTIME_SIGNALS
+  static int __pthread_missing_rt_sigs;
+
+# ifdef __NR_rt_sigsuspend
+  /* First try the RT signals.  */
+  if (!__pthread_missing_rt_sigs)
+    {
+      /* XXX The size argument hopefully will have to be changed to the
+	 real size of the user-level sigset_t.  */
+      int r;
+      r = INTERNAL_SYSCALL (rt_sigsuspend, err, 2, set, _NSIG / 8);
+      if (INTERNAL_SYSCALL_ERRNO (r, err) != ENOSYS)
+	return;
+
+      __pthread_missing_rt_sigs = 1;
+    }
+# endif
+
+  INTERNAL_SYSCALL (sigsuspend, err, 3, 0, 0, set->__val[0]);
+#else
+  INTERNAL_SYSCALL (rt_sigsuspend, err, 2, set, _NSIG / 8);
+#endif
+}
--- libc/linuxthreads/internals.h.jj	2003-01-07 10:57:55.000000000 -0500
+++ libc/linuxthreads/internals.h	2003-04-01 05:23:33.000000000 -0500
@@ -377,6 +377,8 @@ extern int __pthread_timedsuspend_new(pt
 
 extern void __pthread_wait_for_restart_signal(pthread_descr self);
 
+extern void __pthread_sigsuspend (const sigset_t *mask) attribute_hidden;
+
 extern int __pthread_yield (void);
 
 extern int __pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock,
--- libc/sysdeps/unix/sysv/linux/sparc/sparc64/sigsuspend.c.jj	2002-12-15 18:21:00.000000000 -0500
+++ libc/sysdeps/unix/sysv/linux/sparc/sparc64/sigsuspend.c	2003-04-01 05:21:01.000000000 -0500
@@ -1,41 +1 @@
-/* Copyright (C) 1996,1997,1998,1999,2000,2002 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
-
-#include <errno.h>
-#include <signal.h>
-#include <unistd.h>
-
-#include <sysdep.h>
-#include <sys/syscall.h>
-#include <bp-checks.h>
-
-extern int __syscall_rt_sigsuspend (const sigset_t *__unbounded, size_t);
-
-/* Change the set of blocked signals to SET,
-   wait until a signal arrives, and restore the set of blocked signals.  */
-int
-__sigsuspend (set)
-     const sigset_t *set;
-{
-  /* XXX The size argument hopefully will have to be changed to the
-     real size of the user-level sigset_t.  */
-  return INLINE_SYSCALL (rt_sigsuspend, 2, CHECK_SIGSET (set), _NSIG / 8);
-}
-libc_hidden_def (__sigsuspend)
-weak_alias (__sigsuspend, sigsuspend)
-strong_alias (__sigsuspend, __libc_sigsuspend)
+#include "../../ia64/sigsuspend.c"

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]