+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
static void
log_cleanup (void *arg)
{
- __libc_lock_unlock (*(__libc_lock_t *) arg);
+ __libc_lock_unlock (syslog_lock);
}
void
{
#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
{
#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
+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
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 \
/* 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. */
/* 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)
{
#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. */
if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval))
{
THREAD_SETMEM (self, result, PTHREAD_CANCELED);
- __do_cancel (CURRENT_STACK_FRAME);
+ __do_cancel ();
}
break;
void
-attribute_hidden
+internal_function attribute_hidden
__pthread_disable_asynccancel (int oldtype)
{
/* If asynchronous cancellation was enabled before we do not have
/* 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
union dtv *dtvp;
struct pthread *self; /* Pointer to this structure */
list_t list;
+ int multiple_threads;
} data;
void *__padding[16];
} header;
/* Run the registered destructors and terminate the
thread. */
- __do_cancel (CURRENT_STACK_FRAME);
+ __do_cancel ();
}
break;
if (CANCEL_ENABLED_AND_CANCELED (cancelhandling)) \
{ \
THREAD_SETMEM (self, result, PTHREAD_CANCELED); \
- __do_cancel (CURRENT_STACK_FRAME); \
+ __do_cancel (); \
} \
} while (0)
#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. */
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. */
{
THREAD_SETMEM (THREAD_SELF, result, value);
- __do_cancel (CURRENT_STACK_FRAME);
+ __do_cancel ();
}
oldval) == 0)
{
if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval))
- __do_cancel (CURRENT_STACK_FRAME);
+ __do_cancel ();
break;
}
if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval))
{
THREAD_SETMEM (self, result, PTHREAD_CANCELED);
- __do_cancel (CURRENT_STACK_FRAME);
+ __do_cancel ();
}
break;
# include <stddef.h>
# include <stdint.h>
# include <stdlib.h>
+# include <list.h>
/* Type for the dtv. */
thread descriptor used by libpthread. */
dtv_t *dtv;
void *self; /* Pointer to the thread descriptor. */
+ list_t list;
+ int multiple_threads;
} tcbhead_t;
#endif
/* 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. */
#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
--- /dev/null
+#define socket accept
+#define __socket __libc_accept
+#define NARGS 3
+#include <pt-socket.S>
/* 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
/* Failed. */
return errno;
+ /* We now have for sure more than one thread. */
+ pd->header.data.multiple_threads = 1;
+
return 0;
}
02111-1307 USA. */
#include <sysdep.h>
+#include <tls.h>
.text
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:
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:
#define _LOWLEVELLOCK_H 1
#include <time.h>
+#include <sys/param.h>
#include <bits/pthreadtypes.h>
#ifndef LOCK_INSTR
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" \
"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" \
".previous\n" \
"2:" \
: "=m" (futex), "=&a" (ignore) \
- : "0" (futex), "m" (__libc_locking_needed) \
+ : "0" (futex), \
+ "i" (offsetof (tcbhead_t, multiple_threads)) \
: "memory"); })
#endif
--- /dev/null
+/* 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
static struct fork_handler pthread_child_handler;
-/* Global variable signalled when locking is needed. */
-int __libc_locking_needed;
-
void
__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;
}
--- /dev/null
+/* 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)
--- /dev/null
+/* 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)