Skip to content
Permalink
3a4d1e1e49
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
181 lines (147 sloc) 4.22 KB
/* Copyright (C) 2002, 2003 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 <unwindbuf.h>
#include <sysdep.h>
#ifndef UP
# define LOCK lock
#else
# define LOCK
#endif
#define SYS_futex 240
#define FUTEX_WAKE 1
.comm __fork_generation, 4, 4
.text
.globl __pthread_once
.type __pthread_once,@function
.align 16
cfi_startproc
__pthread_once:
movl 4(%esp), %ecx
testl $2, (%ecx)
jz 1f
xorl %eax, %eax
ret
1: pushl %ebx
cfi_adjust_cfa_offset (4)
cfi_rel_offset (3, 0)
pushl %esi
cfi_adjust_cfa_offset (4)
cfi_rel_offset (6, 0)
movl %ecx, %ebx
xorl %esi, %esi
/* Not yet initialized or initialization in progress.
Get the fork generation counter now. */
6: movl (%ebx), %eax
#ifdef PIC
call __i686.get_pc_thunk.cx
addl $_GLOBAL_OFFSET_TABLE_, %ecx
#endif
5: movl %eax, %edx
testl $2, %eax
jnz 4f
andl $3, %edx
#ifdef PIC
orl __fork_generation@GOTOFF(%ecx), %edx
#else
orl __fork_generation, %edx
#endif
orl $1, %edx
LOCK
cmpxchgl %edx, (%ebx)
jnz 5b
/* Check whether another thread already runs the initializer. */
testl $1, %eax
jz 3f /* No -> do it. */
/* Check whether the initializer execution was interrupted
by a fork. */
xorl %edx, %eax
testl $0xfffffffc, %eax
jnz 3f /* Different for generation -> run initializer. */
/* Somebody else got here first. Wait. */
movl %esi, %ecx /* movl $FUTEX_WAIT, %ecx */
movl $SYS_futex, %eax
ENTER_KERNEL
jmp 6b
3: /* Call the initializer function after setting up the
cancellation handler. Note that it is not possible here
to use the unwind-based cleanup handling. This would require
that the user-provided function and all the code it calls
is compiled with exceptions. Unfortunately this cannot be
guaranteed. */
subl $UNWINDBUFSIZE+8, %esp
cfi_adjust_cfa_offset (UNWINDBUFSIZE+8)
movl %ecx, %ebx /* PIC register value. */
leal 8+UWJMPBUF(%esp), %eax
movl $0, 4(%esp)
movl %eax, (%esp)
call __sigsetjmp@PLT
jne 7f
leal 8(%esp), %eax
call __pthread_register_cancel
/* Call the user-provided initialization function. */
call *24+UNWINDBUFSIZE(%esp)
/* Pop the cleanup handler. */
leal 8(%esp), %eax
call __pthread_unregister_cancel
addl $UNWINDBUFSIZE+8, %esp
cfi_adjust_cfa_offset (-UNWINDBUFSIZE-8)
/* Sucessful run of the initializer. Signal that we are done. */
movl 12(%esp), %ebx
LOCK
addl $1, (%ebx)
/* Wake up all other threads. */
movl $0x7fffffff, %edx
movl $FUTEX_WAKE, %ecx
movl $SYS_futex, %eax
ENTER_KERNEL
4: popl %esi
cfi_adjust_cfa_offset (-4)
cfi_restore (6)
popl %ebx
cfi_adjust_cfa_offset (-4)
cfi_restore (3)
xorl %eax, %eax
ret
7: /* __sigsetjmp returned for the second time. */
movl 20+UNWINDBUFSIZE(%esp), %ebx
cfi_adjust_cfa_offset (UNWINDBUFSIZE+16)
cfi_offset (3, -8)
cfi_offset (6, -12)
movl $0, (%ebx)
movl $0x7fffffff, %edx
movl $FUTEX_WAKE, %ecx
movl $SYS_futex, %eax
ENTER_KERNEL
leal 8(%esp), %eax
call __pthread_unwind_next /* Note: no @PLT. */
/* NOTREACHED */
hlt
cfi_endproc
.size __pthread_once,.-__pthread_once
.globl __pthread_once_internal
__pthread_once_internal = __pthread_once
.globl pthread_once
pthread_once = __pthread_once
#ifdef PIC
.section .gnu.linkonce.t.__i686.get_pc_thunk.cx,"ax",@progbits
.globl __i686.get_pc_thunk.cx
.hidden __i686.get_pc_thunk.cx
.type __i686.get_pc_thunk.cx,@function
__i686.get_pc_thunk.cx:
movl (%esp), %ecx;
ret
.size __i686.get_pc_thunk.cx,.-__i686.get_pc_thunk.cx
#endif