Update.
authorUlrich Drepper <drepper@redhat.com>
Fri, 13 Dec 2002 10:59:14 +0000 (10:59 +0000)
committerUlrich Drepper <drepper@redhat.com>
Fri, 13 Dec 2002 10:59:14 +0000 (10:59 +0000)
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.

22 files changed:
ChangeLog
misc/syslog.c
nptl/ChangeLog
nptl/Makefile
nptl/allocatestack.c
nptl/cancellation.c
nptl/descr.h
nptl/init.c
nptl/pthreadP.h
nptl/pthread_exit.c
nptl/pthread_setcancelstate.c
nptl/pthread_setcanceltype.c
nptl/sysdeps/i386/tls.h
nptl/sysdeps/pthread/bits/libc-lock.h
nptl/sysdeps/unix/sysv/linux/accept.S [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/i386/createthread.c
nptl/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S
nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h
nptl/sysdeps/unix/sysv/linux/i386/pt-socket.S [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c
nptl/sysdeps/unix/sysv/linux/read.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/write.c [new file with mode: 0644]

index 0b0101a..7062cdb 100644 (file)
--- 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
index c7d9297..c1fdf5b 100644 (file)
@@ -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
 
index 4ec9578..f1b48c4 100644 (file)
@@ -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
index 57dd89f..029d376 100644 (file)
@@ -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 \
index 3e057e9..2dfecf0 100644 (file)
@@ -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)
            {
index 0d0af1c..f136bbb 100644 (file)
 #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
index f3a9620..3dd6e12 100644 (file)
@@ -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;
index 7686e8c..66976ff 100644 (file)
@@ -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;
index 1813a04..94f169c 100644 (file)
@@ -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.  */
index 5822a2e..8206557 100644 (file)
@@ -27,5 +27,5 @@ pthread_exit (value)
 {
   THREAD_SETMEM (THREAD_SELF, result, value);
 
-  __do_cancel (CURRENT_STACK_FRAME);
+  __do_cancel ();
 }
index ad50d1c..a4466ca 100644 (file)
@@ -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;
        }
index be0056a..bb4b249 100644 (file)
@@ -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;
index a4bbf34..9f4b89f 100644 (file)
@@ -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.  */
index 555f05d..d46f748 100644 (file)
 #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 (file)
index 0000000..6b668df
--- /dev/null
@@ -0,0 +1,4 @@
+#define        socket  accept
+#define        __socket __libc_accept
+#define        NARGS   3
+#include <pt-socket.S>
index fc252e1..f9abce2 100644 (file)
@@ -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;
 }
index 65e39e7..27275e3 100644 (file)
@@ -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:
index 94c0314..7c516ee 100644 (file)
@@ -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 (file)
index 0000000..0b8523b
--- /dev/null
@@ -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
index d7f1c03..80b6dbc 100644 (file)
@@ -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 (file)
index 0000000..ea04002
--- /dev/null
@@ -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 (file)
index 0000000..ea9b60c
--- /dev/null
@@ -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)