about summary refs log tree commit diff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2002-12-13 10:59:14 +0000
committerUlrich Drepper <drepper@redhat.com>2002-12-13 10:59:14 +0000
commit9ae0909b35bc7ed04897536cbf224f7e134b5184 (patch)
treeaa669fa5f77206d19f065a05859b8c52032019ad
parentb9633fccd30c9cb390295ca0c43477f2bef986af (diff)
downloadglibc-9ae0909b35bc7ed04897536cbf224f7e134b5184.tar.gz
glibc-9ae0909b35bc7ed04897536cbf224f7e134b5184.tar.xz
glibc-9ae0909b35bc7ed04897536cbf224f7e134b5184.zip
Update.
2002-12-13  Ulrich Drepper  <drepper@redhat.com>

	* misc/syslog.c (log_cleanup): Don't use parameter in
	__libc_lock_unlock call, use syslog_lock directly.  Adjust callers to
	pass NULL instead of a pointer to syslog_lock.
-rw-r--r--ChangeLog6
-rw-r--r--misc/syslog.c6
-rw-r--r--nptl/ChangeLog35
-rw-r--r--nptl/Makefile2
-rw-r--r--nptl/allocatestack.c6
-rw-r--r--nptl/cancellation.c33
-rw-r--r--nptl/descr.h3
-rw-r--r--nptl/init.c2
-rw-r--r--nptl/pthreadP.h48
-rw-r--r--nptl/pthread_exit.c2
-rw-r--r--nptl/pthread_setcancelstate.c2
-rw-r--r--nptl/pthread_setcanceltype.c2
-rw-r--r--nptl/sysdeps/i386/tls.h8
-rw-r--r--nptl/sysdeps/pthread/bits/libc-lock.h6
-rw-r--r--nptl/sysdeps/unix/sysv/linux/accept.S4
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/createthread.c6
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S17
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h15
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/pt-socket.S80
-rw-r--r--nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c6
-rw-r--r--nptl/sysdeps/unix/sysv/linux/read.c50
-rw-r--r--nptl/sysdeps/unix/sysv/linux/write.c50
22 files changed, 312 insertions, 77 deletions
diff --git a/ChangeLog b/ChangeLog
index 0b0101ad75..7062cdbb12 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2002-12-13  Ulrich Drepper  <drepper@redhat.com>
+
+	* misc/syslog.c (log_cleanup): Don't use parameter in
+	__libc_lock_unlock call, use syslog_lock directly.  Adjust callers to
+	pass NULL instead of a pointer to syslog_lock.
+
 2002-12-12  Ulrich Drepper  <drepper@redhat.com>
 
 	* iconvdata/Makefile: iconv-rules: Add definition to use gconv.map
diff --git a/misc/syslog.c b/misc/syslog.c
index c7d92974e9..c1fdf5b6b9 100644
--- a/misc/syslog.c
+++ b/misc/syslog.c
@@ -333,7 +333,7 @@ openlog_internal(const char *ident, int logstat, int logfac)
 static void
 log_cleanup (void *arg)
 {
-  __libc_lock_unlock (*(__libc_lock_t *) arg);
+  __libc_lock_unlock (syslog_lock);
 }
 
 void
@@ -341,7 +341,7 @@ openlog (const char *ident, int logstat, int logfac)
 {
 #ifdef _LIBC_REENTRANT
   /* Protect against multiple users.  */
-  __libc_cleanup_region_start (1, log_cleanup, &syslog_lock);
+  __libc_cleanup_region_start (1, log_cleanup, NULL);
   __libc_lock_lock (syslog_lock);
 #endif
 
@@ -375,7 +375,7 @@ closelog ()
 {
 #ifdef _LIBC_REENTRANT
   /* Protect against multiple users.  */
-  __libc_cleanup_region_start (1, log_cleanup, &syslog_lock);
+  __libc_cleanup_region_start (1, log_cleanup, NULL);
   __libc_lock_lock (syslog_lock);
 #endif
 
diff --git a/nptl/ChangeLog b/nptl/ChangeLog
index 4ec9578e7d..f1b48c46b4 100644
--- a/nptl/ChangeLog
+++ b/nptl/ChangeLog
@@ -1,3 +1,38 @@
+2002-12-13  Ulrich Drepper  <drepper@redhat.com>
+
+	* Makefile (routines): Add libc-cancellation.
+	* libc-cancellation.c: New file.
+	* descr.h (struct pthread): Add multiple_threads field.
+	* allocatestack.c (allocate_stack): Initialize multiple_header field of
+	new thread descriptor to 1.
+	* sysdeps/unix/sysv/linux/i386/createthread.c (create_thread):
+	Initialize multiple_thread field after successful thread creation.
+	* cancellation.c (__do_cancel): Move to pthreadP.h.
+	(__pthread_enable_asynccancel): Remove parameter from __do_cancel call.
+	(__pthread_disable_asynccancel): Add internal_function attribute.
+	* init.c (sigcancel_handler): Remove parameter from __do_cancel call.
+	* pthread_setcancelstate.c: Likewise.
+	* pthread_setcanceltype.c: Likewise.
+	* pthread_exit.c: Likewise.
+	* pthreadP.h (CANCELLATION_P): Likewise.
+	(__do_cancel): Define as static inline.
+	(LIBC_CANCEL_ASYNC, LIBC_CANCEL_RESET): New #defines.
+	(__libc_enable_asynccancel, __libc_disable_asynccancel): New
+	declarations.
+	* sysdeps/i386/tls.h (tcbhead_t): Add list and multiple_threads
+	fields.  Define MULTIPLE_THREADS_OFFSET.
+	* sysdeps/pthread/bits/libc-lock.h: Remove __libc_locking_needed
+	declaration.
+	* sysdeps/unix/sysv/linux/accept.S: New file.
+	* sysdeps/unix/sysv/linux/read.c: New file.
+	* sysdeps/unix/sysv/linux/write.c: New file.
+	* sysdeps/unix/sysv/linux/i386/pt-socket.S: New file.
+	* sysdeps/unix/sysv/linux/libc_pthread_init.c: Remove definition and
+	initialization of __libc_locking_needed.
+	* sysdeps/unix/sysv/linux/i386/lowlevellock.h: Don't use
+	__libc_locking_needed, use multiple_threads field in TCB.
+	* sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Likewise.
+
 2002-12-12  Ulrich Drepper  <drepper@redhat.com>
 
 	* sysdeps/unix/sysv/linux/i386/i686/libc-lowlevellock.S: Use i486
diff --git a/nptl/Makefile b/nptl/Makefile
index 57dd89f862..029d376196 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -28,7 +28,7 @@ headers := pthread.h semaphore.h
 extra-libs := libpthread
 extra-libs-others := $(extra-libs)
 
-routines = alloca_cutoff forward libc-lowlevellock
+routines = alloca_cutoff forward libc-lowlevellock libc-cancellation
 shared-only-routines = forward
 
 libpthread-routines = init events \
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
index 3e057e9c7b..2dfecf0181 100644
--- a/nptl/allocatestack.c
+++ b/nptl/allocatestack.c
@@ -272,6 +272,9 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
       /* This is a user-provided stack.  */
       pd->user_stack = true;
 
+      /* There is at least one more thread.  */
+      pd->header.data.multiple_threads = 1;
+
       /* Allocate the DTV for this thread.  */
       if (_dl_allocate_tls (pd) == NULL)
 	/* Something went wrong.  */
@@ -337,6 +340,9 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
 	  /* Initialize the lock.  */
 	  pd->lock = LLL_LOCK_INITIALIZER;
 
+	  /* There is at least one more thread.  */
+	  pd->header.data.multiple_threads = 1;
+
 	  /* Allocate the DTV for this thread.  */
 	  if (_dl_allocate_tls (pd) == NULL)
 	    {
diff --git a/nptl/cancellation.c b/nptl/cancellation.c
index 0d0af1c647..f136bbb4c4 100644
--- a/nptl/cancellation.c
+++ b/nptl/cancellation.c
@@ -23,35 +23,6 @@
 #include "atomic.h"
 
 
-/* This function is responsible for calling all registered cleanup
-   handlers and then terminate the thread.  This includes dellocating
-   the thread-specific data.  The implementation is complicated by the
-   fact that we have to handle to cancellation handler registration
-   methods: exceptions using try/finally and setjmp.
-
-   The setjmp method is always available.  The user might compile some
-   code which uses this method because no modern compiler is
-   available.  So we have to handle these first since we cannot call
-   the cleanup handlers if the stack frames are gone.  At the same
-   time this opens a hole for the register exception handler blocks
-   since now they might be in danger of using an overwritten stack
-   frame.  The advise is to only use new or only old style cancellation
-   handling.  */
-void
-__do_cancel (char *currentframe)
-{
-  struct pthread *self = THREAD_SELF;
-
-  /* Throw an exception.  */
-  // XXX TBI
-
-  /* If throwing an exception didn't work try the longjmp.  */
-  __libc_longjmp (self->cancelbuf, 1);
-
-  /* NOTREACHED */
-}
-
-
 /* The next two functions are similar to pthread_setcanceltype() but
    more specialized for the use in the cancelable functions like write().
    They do not need to check parameters etc.  */
@@ -76,7 +47,7 @@ __pthread_enable_asynccancel (void)
 	  if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval))
 	    {
 	      THREAD_SETMEM (self, result, PTHREAD_CANCELED);
-	      __do_cancel (CURRENT_STACK_FRAME);
+	      __do_cancel ();
 	    }
 
 	  break;
@@ -88,7 +59,7 @@ __pthread_enable_asynccancel (void)
 
 
 void
-attribute_hidden
+internal_function attribute_hidden
 __pthread_disable_asynccancel (int oldtype)
 {
   /* If asynchronous cancellation was enabled before we do not have
diff --git a/nptl/descr.h b/nptl/descr.h
index f3a9620a7b..3dd6e1293c 100644
--- a/nptl/descr.h
+++ b/nptl/descr.h
@@ -58,6 +58,8 @@ struct pthread
   /* XXX Remove this union for IA-64 style TLS module */
   union
   {
+    /* It is very important to always append new elements.  The offsets
+       of some of the elements of the struct are used in assembler code.  */
     struct
     {
       void *tcb;                /* Pointer to the TCB.  This is not always
@@ -65,6 +67,7 @@ struct pthread
       union dtv *dtvp;
       struct pthread *self;       /* Pointer to this structure */
       list_t list;
+      int multiple_threads;
     } data;
     void *__padding[16];
   } header;
diff --git a/nptl/init.c b/nptl/init.c
index 7686e8ca29..66976ff615 100644
--- a/nptl/init.c
+++ b/nptl/init.c
@@ -84,7 +84,7 @@ sigcancel_handler (int sig __attribute ((unused)))
 
 	      /* Run the registered destructors and terminate the
 		 thread.  */
-	      __do_cancel (CURRENT_STACK_FRAME);
+	      __do_cancel ();
 	    }
 
 	  break;
diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
index 1813a04583..94f169c564 100644
--- a/nptl/pthreadP.h
+++ b/nptl/pthreadP.h
@@ -74,7 +74,7 @@ extern int __pthread_debug attribute_hidden;
     if (CANCEL_ENABLED_AND_CANCELED (cancelhandling))			      \
       {									      \
 	THREAD_SETMEM (self, result, PTHREAD_CANCELED);			      \
-	__do_cancel (CURRENT_STACK_FRAME);				      \
+	__do_cancel ();							      \
       }									      \
   } while (0)
 
@@ -85,9 +85,41 @@ extern int __pthread_debug attribute_hidden;
 #define CANCEL_RESET(oldtype) \
   __pthread_disable_asynccancel (oldtype)
 
-/* Function performing the cancellation.  */
-extern void __do_cancel (char *currentframe)
-     __attribute ((visibility ("hidden"), noreturn, regparm (1)));
+/* Same as CANCEL_ASYNC, but for use in libc.so.  */
+#define LIBC_CANCEL_ASYNC() \
+  __libc_enable_asynccancel ()
+/* Same as CANCEL_RESET, but for use in libc.so.  */
+#define LIBC_CANCEL_RESET(oldtype) \
+  __libc_disable_asynccancel (oldtype)
+
+
+/* This function is responsible for calling all registered cleanup
+   handlers and then terminate the thread.  This includes dellocating
+   the thread-specific data.  The implementation is complicated by the
+   fact that we have to handle to cancellation handler registration
+   methods: exceptions using try/finally and setjmp.
+
+   The setjmp method is always available.  The user might compile some
+   code which uses this method because no modern compiler is
+   available.  So we have to handle these first since we cannot call
+   the cleanup handlers if the stack frames are gone.  At the same
+   time this opens a hole for the register exception handler blocks
+   since now they might be in danger of using an overwritten stack
+   frame.  The advise is to only use new or only old style cancellation
+   handling.  */
+static inline void
+__do_cancel (void)
+{
+  struct pthread *self = THREAD_SELF;
+
+  /* Throw an exception.  */
+  // XXX TBI
+
+  /* If throwing an exception didn't work try the longjmp.  */
+  __libc_longjmp (self->cancelbuf, 1);
+
+  /* NOTREACHED */
+}
 
 
 /* Test whether stackframe is still active.  */
@@ -186,7 +218,13 @@ extern int __pthread_atfork (void (*prepare) (void), void (*parent) (void),
 extern int __pthread_kill (pthread_t threadid, int signo);
 extern int __pthread_setcanceltype (int type, int *oldtype);
 extern int __pthread_enable_asynccancel (void) attribute_hidden;
-extern void __pthread_disable_asynccancel (int oldtype) attribute_hidden;
+extern void __pthread_disable_asynccancel (int oldtype)
+     internal_function attribute_hidden;
+
+/* The two functions are in libc.so and not exported.  */
+extern int __libc_enable_asynccancel (void) attribute_hidden;
+extern void __libc_disable_asynccancel (int oldtype)
+     internal_function attribute_hidden;
 
 #ifdef IS_IN_libpthread
 /* Special versions which use non-exported functions.  */
diff --git a/nptl/pthread_exit.c b/nptl/pthread_exit.c
index 5822a2e038..82065576a1 100644
--- a/nptl/pthread_exit.c
+++ b/nptl/pthread_exit.c
@@ -27,5 +27,5 @@ pthread_exit (value)
 {
   THREAD_SETMEM (THREAD_SELF, result, value);
 
-  __do_cancel (CURRENT_STACK_FRAME);
+  __do_cancel ();
 }
diff --git a/nptl/pthread_setcancelstate.c b/nptl/pthread_setcancelstate.c
index ad50d1ce75..a4466cad6e 100644
--- a/nptl/pthread_setcancelstate.c
+++ b/nptl/pthread_setcancelstate.c
@@ -58,7 +58,7 @@ pthread_setcancelstate (state, oldstate)
 					   oldval) == 0)
 	{
 	  if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval))
-	    __do_cancel (CURRENT_STACK_FRAME);
+	    __do_cancel ();
 
 	  break;
 	}
diff --git a/nptl/pthread_setcanceltype.c b/nptl/pthread_setcanceltype.c
index be0056a4e0..bb4b24943e 100644
--- a/nptl/pthread_setcanceltype.c
+++ b/nptl/pthread_setcanceltype.c
@@ -60,7 +60,7 @@ __pthread_setcanceltype (type, oldtype)
 	  if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval))
 	    {
 	      THREAD_SETMEM (self, result, PTHREAD_CANCELED);
-	      __do_cancel (CURRENT_STACK_FRAME);
+	      __do_cancel ();
 	    }
 
 	  break;
diff --git a/nptl/sysdeps/i386/tls.h b/nptl/sysdeps/i386/tls.h
index a4bbf3445a..9f4b89f7aa 100644
--- a/nptl/sysdeps/i386/tls.h
+++ b/nptl/sysdeps/i386/tls.h
@@ -24,6 +24,7 @@
 # include <stddef.h>
 # include <stdint.h>
 # include <stdlib.h>
+# include <list.h>
 
 
 /* Type for the dtv.  */
@@ -40,6 +41,8 @@ typedef struct
 			   thread descriptor used by libpthread.  */
   dtv_t *dtv;
   void *self;		/* Pointer to the thread descriptor.  */
+  list_t list;
+  int multiple_threads;
 } tcbhead_t;
 #endif
 
@@ -52,10 +55,13 @@ typedef struct
 /* Signal that TLS support is available.  */
 #define USE_TLS	1
 
-/* Alignment requirement for the stack.  For IA-32 this is govern by
+/* Alignment requirement for the stack.  For IA-32 this is governed by
    the SSE memory functions.  */
 #define STACK_ALIGN	16
 
+/* Offset of the MULTIPLE_THREADS element in tcbhead_t.  */
+#define MULTIPLE_THREADS_OFFSET 20
+
 
 #ifndef __ASSEMBLER__
 /* Get system call information.  */
diff --git a/nptl/sysdeps/pthread/bits/libc-lock.h b/nptl/sysdeps/pthread/bits/libc-lock.h
index 555f05db85..d46f74817e 100644
--- a/nptl/sysdeps/pthread/bits/libc-lock.h
+++ b/nptl/sysdeps/pthread/bits/libc-lock.h
@@ -25,12 +25,6 @@
 #include <stddef.h>
 
 
-#if defined _LIBC && !defined NOT_IN_libc
-/* Nonzero if locking is needed.  */
-extern int __libc_locking_needed attribute_hidden;
-#endif
-
-
 /* Fortunately Linux now has a mean to do locking which is realtime
    safe without the aid of the thread library.  We also need no fancy
    options like error checking mutexes etc.  We only need simple
diff --git a/nptl/sysdeps/unix/sysv/linux/accept.S b/nptl/sysdeps/unix/sysv/linux/accept.S
new file mode 100644
index 0000000000..6b668dfd9a
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/accept.S
@@ -0,0 +1,4 @@
+#define	socket	accept
+#define	__socket __libc_accept
+#define	NARGS	3
+#include <pt-socket.S>
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/createthread.c b/nptl/sysdeps/unix/sysv/linux/i386/createthread.c
index fc252e185d..f9abce2df2 100644
--- a/nptl/sysdeps/unix/sysv/linux/i386/createthread.c
+++ b/nptl/sysdeps/unix/sysv/linux/i386/createthread.c
@@ -82,6 +82,9 @@ create_thread (struct pthread *pd, STACK_VARIABLES_PARMS)
 	    /* Failed.  */
 	    return errno;
 
+	  /* We now have for sure more than one thread.  */
+	  pd->header.data.multiple_threads = 1;
+
 	  /* Now fill in the information about the new thread in
 	     the newly created thread's data structure.  We cannot let
 	     the new thread do this since we don't know whether it was
@@ -142,5 +145,8 @@ create_thread (struct pthread *pd, STACK_VARIABLES_PARMS)
     /* Failed.  */
     return errno;
 
+  /* We now have for sure more than one thread.  */
+  pd->header.data.multiple_threads = 1;
+
   return 0;
 }
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S
index 65e39e7829..27275e3158 100644
--- a/nptl/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S
@@ -18,6 +18,7 @@
    02111-1307 USA.  */
 
 #include <sysdep.h>
+#include <tls.h>
 
 	.text
 
@@ -48,13 +49,7 @@ __lll_lock_wait:
 
 	orl	$-1, %eax	/* Load -1.  */
 #ifndef UP
-# ifdef PIC
-	call	__i686.get_pc_thunk.dx
-	addl	$_GLOBAL_OFFSET_TABLE_, %edx
-	cmpl	$0, __libc_locking_needed@GOTOFF(%edx)
-# else
-	cmpl	$0, __libc_locking_needed
-# endif
+	cmpl	$0, %gs:MULTIPLE_THREADS_OFFSET
 	je,pt	0f
 	lock
 0:
@@ -83,13 +78,7 @@ lll_unlock_wake_cb:
 
 	movl	20(%esp), %ebx
 #ifndef UP
-# ifdef PIC
-	call	__i686.get_pc_thunk.dx
-	addl	$_GLOBAL_OFFSET_TABLE_, %edx
-	cmpl	$0, __libc_locking_needed@GOTOFF(%edx)
-# else
-	cmpl	$0, __libc_locking_needed
-# endif
+	cmpl	$0, %gs:MULTIPLE_THREADS_OFFSET
 	je,pt	0f
 	lock
 0:
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h b/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h
index 94c0314c12..7c516ee36a 100644
--- a/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h
+++ b/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h
@@ -21,6 +21,7 @@
 #define _LOWLEVELLOCK_H	1
 
 #include <time.h>
+#include <sys/param.h>
 #include <bits/pthreadtypes.h>
 
 #ifndef LOCK_INSTR
@@ -182,26 +183,27 @@ extern int lll_unlock_wake_cb (int *__futex) attribute_hidden;
    the lock prefix when the thread library is not used.
 
    XXX In future we might even want to avoid it on UP machines.  */
+# include <tls.h>
 
 /* Nonzero if locking is needed.  */
 extern int __libc_locking_needed attribute_hidden;
 
 # define lll_trylock(futex) \
   ({ unsigned char ret;							      \
-     __asm __volatile ("cmpl $0, %5\n\t"				      \
+     __asm __volatile ("cmpl $0, %%gs:%P5\n\t"				      \
 		       "je,pt 0f\n\t"					      \
 		       "lock\n"						      \
 		       "0:\tcmpxchgl %2, %1; setne %0"			      \
 		       : "=a" (ret), "=m" (futex)			      \
 		       : "r" (0), "1" (futex), "0" (1),			      \
-		         "m" (__libc_locking_needed)			      \
+		         "i" (offsetof (tcbhead_t, multiple_threads))	      \
 		       : "memory");					      \
      ret; })
 
 
 # define lll_lock(futex) \
   (void) ({ int ignore1, ignore2;					      \
-	    __asm __volatile ("cmpl $0, %5\n\t"				      \
+	    __asm __volatile ("cmpl $0, %%gs:%P5\n\t"			      \
 			      "je,pt 0f\n\t"				      \
 			      "lock\n"					      \
 			      "0:\txaddl %0, %2\n\t"			      \
@@ -214,13 +216,13 @@ extern int __libc_locking_needed attribute_hidden;
 			      "2:"					      \
 			      : "=a" (ignore1), "=&c" (ignore2), "=m" (futex) \
 			      : "0" (-1), "2" (futex),			      \
-		                "m" (__libc_locking_needed)		      \
+		                "i" (offsetof (tcbhead_t, multiple_threads))  \
 			      : "memory"); })
 
 
 # define lll_unlock(futex) \
   (void) ({ int ignore;							      \
-            __asm __volatile ("cmpl $0, %3\n\t"				      \
+            __asm __volatile ("cmpl $0, %%gs:%P3\n\t"			      \
 			      "je,pt 0f\n\t"				      \
 			      "lock\n"					      \
 			      "0:\tincl %0\n\t"				      \
@@ -232,7 +234,8 @@ extern int __libc_locking_needed attribute_hidden;
 			      ".previous\n"				      \
 			      "2:"					      \
 			      : "=m" (futex), "=&a" (ignore)		      \
-			      : "0" (futex), "m" (__libc_locking_needed)      \
+			      : "0" (futex),				      \
+				"i" (offsetof (tcbhead_t, multiple_threads))  \
 			      : "memory"); })
 #endif
 
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/pt-socket.S b/nptl/sysdeps/unix/sysv/linux/i386/pt-socket.S
new file mode 100644
index 0000000000..0b8523bd86
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/pt-socket.S
@@ -0,0 +1,80 @@
+/* Copyright (C) 1995, 1996, 1997, 1998, 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 <sysdep.h>
+#include <socketcall.h>
+
+#define P(a, b) P2(a, b)
+#define P2(a, b) a##b
+
+	.text
+/* The socket-oriented system calls are handled unusally in Linux.
+   They are all gated through the single `socketcall' system call number.
+   `socketcall' takes two arguments: the first is the subcode, specifying
+   which socket function is being called; and the second is a pointer to
+   the arguments to the specific function.
+
+   The .S files for the other calls just #define socket and #include this.  */
+
+#ifndef __socket
+# error "__socket and socket must be defined"
+#endif
+
+.globl __socket
+ENTRY (__socket)
+	/* We need one more register.  */
+	pushl %esi
+
+	/* Enable asynchronous cancellation.  */
+	call __libc_enable_asynccancel	/* No @plt */
+	movl %eax, %esi
+
+	/* Save registers.  */
+	movl %ebx, %edx
+
+	movl $SYS_ify(socketcall), %eax	/* System call number in %eax.  */
+
+	/* Use ## so `socket' is a separate token that might be #define'd.  */
+	movl $P(SOCKOP_,socket), %ebx	/* Subcode is first arg to syscall.  */
+	lea 8(%esp), %ecx		/* Address of args is 2nd arg.  */
+
+        /* Do the system call trap.  */
+	int $0x80
+
+	/* Restore the cancellation.  */
+	xchgl %esi, %eax
+	call __libc_disable_asynccancel	/* No @plt */
+
+	/* Restore registers.  */
+	movl %esi, %eax
+	movl %edx, %ebx
+	popl %esi
+
+	/* %eax is < 0 if there was an error.  */
+	cmpl $-125, %eax
+	jae SYSCALL_ERROR_LABEL
+
+	/* Successful; return the syscall's value.  */
+L(pseudo_end):
+	ret
+
+PSEUDO_END (__socket)
+
+#ifndef NO_WEAK_ALIAS
+weak_alias (__socket, socket)
+#endif
diff --git a/nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c b/nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c
index d7f1c03b5e..80b6dbcb4f 100644
--- a/nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c
+++ b/nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c
@@ -24,9 +24,6 @@
 
 static struct fork_handler pthread_child_handler;
 
-/* Global variable signalled when locking is needed.  */
-int __libc_locking_needed;
-
 
 void
 __libc_pthread_init (ptr, reclaim)
@@ -41,7 +38,4 @@ __libc_pthread_init (ptr, reclaim)
 
   /* The fork handler needed by libpthread.  */
   list_add_tail (&pthread_child_handler.list, &__fork_child_list);
-
-  /* Signal the internal locking code that locking is needed now.  */
-  __libc_locking_needed = 1;
 }
diff --git a/nptl/sysdeps/unix/sysv/linux/read.c b/nptl/sysdeps/unix/sysv/linux/read.c
new file mode 100644
index 0000000000..ea04002023
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/read.c
@@ -0,0 +1,50 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   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 <stdlib.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include <nptl/pthreadP.h>
+#include <tls.h>
+
+
+ssize_t
+__libc_read (int fd, void *buf, size_t count)
+{
+#ifndef NOT_IN_libc
+  if (__builtin_expect (THREAD_GETMEM (THREAD_SELF,
+				       header.data.multiple_threads) == 0, 1))
+    return INLINE_SYSCALL (read, 3, fd, buf, count);
+
+  int oldtype = LIBC_CANCEL_ASYNC ();
+#endif
+
+  ssize_t result = INLINE_SYSCALL (read, 3, fd, buf, count);
+
+#ifndef NOT_IN_libc
+  LIBC_CANCEL_RESET (oldtype);
+#endif
+
+  return result;
+}
+libc_hidden_def (__libc_read)
+strong_alias (__libc_read, __read)
+libc_hidden_weak (__read)
+weak_alias (__libc_read, read)
diff --git a/nptl/sysdeps/unix/sysv/linux/write.c b/nptl/sysdeps/unix/sysv/linux/write.c
new file mode 100644
index 0000000000..ea9b60c979
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/write.c
@@ -0,0 +1,50 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   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 <stdlib.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include <nptl/pthreadP.h>
+#include <tls.h>
+
+
+ssize_t
+__libc_write (int fd, const void *buf, size_t count)
+{
+#ifndef NOT_IN_libc
+  if (__builtin_expect (THREAD_GETMEM (THREAD_SELF,
+				       header.data.multiple_threads) == 0, 1))
+    return INLINE_SYSCALL (write, 3, fd, buf, count);
+
+  int oldtype = LIBC_CANCEL_ASYNC ();
+#endif
+
+  ssize_t result = INLINE_SYSCALL (write, 3, fd, buf, count);
+
+#ifndef NOT_IN_libc
+  LIBC_CANCEL_RESET (oldtype);
+#endif
+
+  return result;
+}
+libc_hidden_def (__libc_write)
+strong_alias (__libc_write, __write)
+libc_hidden_weak (__write)
+weak_alias (__libc_write, write)