diff options
Diffstat (limited to 'nptl/sysdeps/unix')
-rw-r--r-- | nptl/sysdeps/unix/sysv/linux/Makefile | 2 | ||||
-rw-r--r-- | nptl/sysdeps/unix/sysv/linux/Versions | 2 | ||||
-rw-r--r-- | nptl/sysdeps/unix/sysv/linux/fork.h | 4 | ||||
-rw-r--r-- | nptl/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S | 185 | ||||
-rw-r--r-- | nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h | 60 | ||||
-rw-r--r-- | nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c (renamed from nptl/sysdeps/unix/sysv/linux/fork-gen.c) | 12 |
6 files changed, 256 insertions, 9 deletions
diff --git a/nptl/sysdeps/unix/sysv/linux/Makefile b/nptl/sysdeps/unix/sysv/linux/Makefile index 9a84534d5b..c079a4013d 100644 --- a/nptl/sysdeps/unix/sysv/linux/Makefile +++ b/nptl/sysdeps/unix/sysv/linux/Makefile @@ -18,7 +18,7 @@ # 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 diff --git a/nptl/sysdeps/unix/sysv/linux/Versions b/nptl/sysdeps/unix/sysv/linux/Versions index 117598c95f..8fea097e43 100644 --- a/nptl/sysdeps/unix/sysv/linux/Versions +++ b/nptl/sysdeps/unix/sysv/linux/Versions @@ -1,6 +1,6 @@ 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; } diff --git a/nptl/sysdeps/unix/sysv/linux/fork.h b/nptl/sysdeps/unix/sysv/linux/fork.h index 85722a59eb..0bc283d1bc 100644 --- a/nptl/sysdeps/unix/sysv/linux/fork.h +++ b/nptl/sysdeps/unix/sysv/linux/fork.h @@ -56,5 +56,5 @@ extern int __register_atfork (void (*__prepare) (void), 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)); 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 3ce1d6fe72..9a124ab0c2 100644 --- a/nptl/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S +++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S @@ -1 +1,184 @@ -#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 diff --git a/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h b/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h index a3c02498f4..470dcf6108 100644 --- a/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h +++ b/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h @@ -139,7 +139,8 @@ extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; <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) \ @@ -148,7 +149,7 @@ extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; 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" \ @@ -163,7 +164,7 @@ extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; : "memory"); }) -#define lll_unlock(futex) \ +# define lll_unlock(futex) \ (void) ({ int ignore; \ __asm __volatile (LOCK_INSTR "incl %0\n\t" \ "jng 1f\n\t" \ @@ -176,6 +177,59 @@ extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; : "=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) \ diff --git a/nptl/sysdeps/unix/sysv/linux/fork-gen.c b/nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c index ff00261404..d7f1c03b5e 100644 --- a/nptl/sysdeps/unix/sysv/linux/fork-gen.c +++ b/nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c @@ -19,19 +19,29 @@ #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; } |