+2002-12-12 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/unix/sysv/linux/fork-gen.c: Renamed to...
+ * sysdeps/unix/sysv/linux/libc_pthread_init.c: ...this.
+ Initialize __libc_locking_needed.
+ * init.c (__pthread_initialize_minimal): Call __libc_pthread_init
+ instead of __register_pthread_fork_handler.
+ * sysdeps/pthread/bits/libc-lock.h: Declare __libc_locking_needed.
+ * sysdeps/unix/sysv/linux/Makefile (sysdep_routimes): Replace
+ fork-gen with libc_pthread_init.
+ * sysdeps/unix/sysv/linux/Versions: Use __libc_pthread_init instead
+ of __register_pthread_fork_handler.
+ * sysdeps/unix/sysv/linux/fork.h: Declare __libc_pthread_init instead
+ of __register_pthread_fork_handler.
+ * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Use
+ __libc_locking_needed to determine whether lock prefix can be avoided.
+ * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Likewise.
+
2002-12-11 Ulrich Drepper <drepper@redhat.com>
* Makefile (tests): Add tst-cleanup1.
__static_tls_size = roundup (__static_tls_size, __static_tls_align);
/* Register the fork generation counter with the libc. */
- __register_pthread_fork_handler (&__fork_generation, __reclaim_stacks);
+ __libc_pthread_init (&__fork_generation, __reclaim_stacks);
}
#include <stddef.h>
+/* Nonzero if locking is needed. */
+extern int __libc_locking_needed attribute_hidden;
+
+
/* 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
# 02111-1307 USA. */
ifeq ($(subdir),nptl)
-sysdep_routines += register-atfork unregister-atfork fork-gen
+sysdep_routines += register-atfork unregister-atfork libc_pthread_init
libpthread-sysdep_routines += pt-fork
endif
libc {
GLIBC_PRIVATE {
- __register_atfork; __register_pthread_fork_handler;
+ __register_atfork; __libc_pthread_init;
__libc_current_sigrtmin_private; __libc_current_sigrtmax_private;
__libc_allocate_rtsig_private;
}
void *dso_handle);
/* Register the generation counter in the libpthread with the libc. */
-extern void __register_pthread_fork_handler (unsigned long int *__ptr,
- void (*reclaim) (void));
+extern void __libc_pthread_int (unsigned long int *__ptr,
+ void (*reclaim) (void));
-#include "lowlevellock.S"
+/* 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 <sysdep.h>
+
+ .text
+
+#define SYS_gettimeofday __NR_gettimeofday
+#define SYS_futex 240
+#define FUTEX_WAIT 0
+#define FUTEX_WAKE 1
+
+#define ETIMEDOUT 110
+
+
+ .globl __lll_lock_wait
+ .type __lll_lock_wait,@function
+ .hidden __lll_lock_wait
+ .align 16
+__lll_lock_wait:
+ pushl %esi
+ pushl %ebx
+ pushl %edx
+
+ movl %ecx, %ebx
+ xorl %esi, %esi /* No timeout. */
+ xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */
+1:
+ leal -1(%eax), %edx /* account for the preceeded xadd. */
+ movl $SYS_futex, %eax
+ int $0x80
+
+ orl $-1, %eax /* Load -1. */
+#ifndef UP
+ cmpl $0, __libc_locking_needed
+ je,pt 0f
+ lock
+0:
+#endif
+ xaddl %eax, (%ebx)
+ jne 1b
+
+ movl $-1, (%ebx)
+
+ popl %edx
+ popl %ebx
+ popl %esi
+ ret
+ .size __lll_lock_wait,.-__lll_lock_wait
+
+
+ .globl lll_unlock_wake_cb
+ .type lll_unlock_wake_cb,@function
+ .hidden lll_unlock_wake_cb
+ .align 16
+lll_unlock_wake_cb:
+ pushl %esi
+ pushl %ebx
+ pushl %ecx
+ pushl %edx
+
+ movl 20(%esp), %ebx
+#ifndef UP
+ cmpl $0, __libc_locking_needed
+ je,pt 0f
+ lock
+0:
+#endif
+ incl (%ebx)
+ jng 1f
+
+ popl %edx
+ popl %ecx
+ popl %ebx
+ popl %esi
+ ret
+ .size lll_unlock_wake_cb,.-lll_unlock_wake_cb
+
+
+ .globl __lll_unlock_wake
+ .type __lll_unlock_wake,@function
+ .hidden __lll_unlock_wake
+__lll_unlock_wake:
+ pushl %esi
+ pushl %ebx
+ pushl %ecx
+ pushl %edx
+
+ movl %eax, %ebx
+1: movl $FUTEX_WAKE, %ecx
+ movl $1, %edx /* Wake one thread. */
+ xorl %esi, %esi
+ movl %edx, (%ebx) /* Stores '$1'. */
+ movl $SYS_futex, %eax
+ int $0x80
+
+ popl %edx
+ popl %ecx
+ popl %ebx
+ popl %esi
+ ret
+ .size __lll_unlock_wake,.-__lll_unlock_wake
+
+
+ .globl __lll_timedwait_tid
+ .type __lll_timedwait_tid,@function
+ .hidden __lll_timedwait_tid
+__lll_timedwait_tid:
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+ pushl %ebp
+
+ movl %eax, %ebp
+ movl %edx, %edi
+ subl $8, %esp
+
+ /* Get current time. */
+2: movl %esp, %ebx
+ xorl %ecx, %ecx
+ movl $SYS_gettimeofday, %eax
+ int $0x80
+
+ /* Compute relative timeout. */
+ movl 4(%esp), %eax
+ movl $1000, %edx
+ mul %edx /* Milli seconds to nano seconds. */
+ movl (%edi), %ecx
+ movl 4(%edi), %edx
+ subl (%esp), %ecx
+ subl %eax, %edx
+ jns 5f
+ addl $1000000000, %edx
+ decl %ecx
+5: testl %ecx, %ecx
+ js 6f /* Time is already up. */
+
+ movl %ecx, (%esp) /* Store relative timeout. */
+ movl %edx, 4(%esp)
+
+ movl (%ebp), %edx
+ testl %edx, %edx
+ jz 4f
+
+ movl %esp, %esi
+ xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */
+ movl %ebp, %ebx
+ movl $SYS_futex, %eax
+ int $0x80
+
+ movl %eax, %edx
+
+ cmpl $0, (%ebx)
+ jne 1f
+4: xorl %eax, %eax
+
+3: addl $8, %esp
+ popl %ebp
+ popl %ebx
+ popl %esi
+ popl %edi
+ ret
+
+1: cmpl $-ETIMEDOUT, %edx
+ jne 2b
+6: movl $ETIMEDOUT, %eax
+ jmp 3b
+ .size __lll_timedwait_tid,.-__lll_timedwait_tid
<0 - taken by more users */
-#define lll_trylock(futex) \
+#if defined NOT_IN_libc || defined UP
+# define lll_trylock(futex) \
({ unsigned char ret; \
__asm __volatile (LOCK_INSTR "cmpxchgl %2, %1; setne %0" \
: "=a" (ret), "=m" (futex) \
ret; })
-#define lll_lock(futex) \
+# define lll_lock(futex) \
(void) ({ int ignore1, ignore2; \
__asm __volatile (LOCK_INSTR "xaddl %0, %2\n\t" \
"jne 1f\n\t" \
: "memory"); })
-#define lll_unlock(futex) \
+# define lll_unlock(futex) \
(void) ({ int ignore; \
__asm __volatile (LOCK_INSTR "incl %0\n\t" \
"jng 1f\n\t" \
: "=m" (futex), "=&a" (ignore) \
: "0" (futex) \
: "memory"); })
+#else
+/* Special versions of the macros for use in libc itself. They avoid
+ the lock prefix when the thread library is not used.
+
+ XXX In future we might even want to avoid it on UP machines. */
+
+# define lll_trylock(futex) \
+ ({ unsigned char ret; \
+ __asm __volatile ("cmpl $0, __libc_locking_needed\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) \
+ : "memory"); \
+ ret; })
+
+
+# define lll_lock(futex) \
+ (void) ({ int ignore1, ignore2; \
+ __asm __volatile ("cmpl $0, __libc_locking_needed\n\t" \
+ "je,pt 0f\n\t" \
+ "lock\n" \
+ "0:\txaddl %0, %2\n\t" \
+ "jne 1f\n\t" \
+ ".subsection 1\n" \
+ "1:\tleal %2, %%ecx\n\t" \
+ "call __lll_lock_wait\n\t" \
+ "jmp 2f\n\t" \
+ ".previous\n" \
+ "2:" \
+ : "=a" (ignore1), "=&c" (ignore2), "=m" (futex) \
+ : "0" (-1), "2" (futex) \
+ : "memory"); })
+
+
+# define lll_unlock(futex) \
+ (void) ({ int ignore; \
+ __asm __volatile ("cmpl $0, __libc_locking_needed\n\t" \
+ "je,pt 0f\n\t" \
+ "lock\n" \
+ "0:\tincl %0\n\t" \
+ "jng 1f\n\t" \
+ ".subsection 1\n" \
+ "1:\tleal %0, %%eax\n\t" \
+ "call __lll_unlock_wake\n\t" \
+ "jmp 2f\n\t" \
+ ".previous\n" \
+ "2:" \
+ : "=m" (futex), "=&a" (ignore) \
+ : "0" (futex) \
+ : "memory"); })
+#endif
#define lll_islocked(futex) \
#include <list.h>
#include "fork.h"
+#include <bits/libc-lock.h>
static struct fork_handler pthread_child_handler;
+/* Global variable signalled when locking is needed. */
+int __libc_locking_needed;
+
void
-__register_pthread_fork_handler (ptr, reclaim)
+__libc_pthread_init (ptr, reclaim)
unsigned long int *ptr;
void (*reclaim) (void);
{
+ /* Remember the pointer to the generation counter in libpthread. */
__fork_generation_pointer = ptr;
+ /* Called by a child after fork. */
pthread_child_handler.handler = 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;
}