Add generic versions of pthread_spin_lock and pthread_spin_trylock.

This commit is contained in:
Maxim Kuvyrkov 2012-08-15 16:29:06 -07:00
parent 329bc01868
commit ef4009734b
14 changed files with 123 additions and 166 deletions

View File

@ -1,3 +1,8 @@
2012-08-15 Maxim Kuvyrkov <maxim@codesourcery.com>
* pthread_spin_lock.c: New file.
* pthread_spin_trylock.c: New file.
2012-08-08 Joseph Myers <joseph@codesourcery.com>
* allocatestack.c (setxid_signal_thread) [__ASSUME_TGKILL]: Make

69
nptl/pthread_spin_lock.c Normal file
View File

@ -0,0 +1,69 @@
/* pthread_spin_lock -- lock a spin lock. Generic version.
Copyright (C) 2012 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, see
<http://www.gnu.org/licenses/>. */
#include <atomic.h>
#include "pthreadP.h"
/* A machine-specific version can define SPIN_LOCK_READS_BETWEEN_CMPXCHG
to the number of plain reads that it's optimal to spin on between uses
of atomic_compare_and_exchange_val_acq. If spinning forever is optimal
then use -1. If no plain reads here would ever be optimal, use 0. */
#ifndef SPIN_LOCK_READS_BETWEEN_CMPXCHG
# warning machine-dependent file should define SPIN_LOCK_READS_BETWEEN_CMPXCHG
# define SPIN_LOCK_READS_BETWEEN_CMPXCHG 1000
#endif
int
pthread_spin_lock (pthread_spinlock_t *lock)
{
/* atomic_exchange usually takes less instructions than
atomic_compare_and_exchange. On the other hand,
atomic_compare_and_exchange potentially generates less bus traffic
when the lock is locked.
We assume that the first try mostly will be successful, and we use
atomic_exchange. For the subsequent tries we use
atomic_compare_and_exchange. */
if (atomic_exchange_acq (lock, 1) == 0)
return 0;
do
{
/* The lock is contended and we need to wait. Going straight back
to cmpxchg is not a good idea on many targets as that will force
expensive memory synchronizations among processors and penalize other
running threads.
On the other hand, we do want to update memory state on the local core
once in a while to avoid spinning indefinitely until some event that
will happen to update local memory as a side-effect. */
if (SPIN_LOCK_READS_BETWEEN_CMPXCHG >= 0)
{
int wait = SPIN_LOCK_READS_BETWEEN_CMPXCHG;
while (*lock != 0 && wait > 0)
--wait;
}
else
{
while (*lock != 0)
;
}
}
while (atomic_compare_and_exchange_val_acq (lock, 1, 0) != 0);
return 0;
}

View File

@ -1,4 +1,5 @@
/* Copyright (C) 2008 Free Software Foundation, Inc.
/* pthread_spin_trylock -- trylock a spin lock. Generic version.
Copyright (C) 2012 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
@ -12,7 +13,7 @@
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, see
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#include <errno.h>
@ -22,5 +23,5 @@
int
pthread_spin_trylock (pthread_spinlock_t *lock)
{
return atomic_compare_and_exchange_val_acq (lock, 1, 0) ? EBUSY : 0;
return atomic_exchange_acq (lock, 1) ? EBUSY : 0;
}

View File

@ -1,3 +1,8 @@
2012-08-15 Maxim Kuvyrkov <maxim@codesourcery.com>
* sysdeps/arm/nptl/pthread_spin_lock.c: Use generic code.
* sysdeps/arm/nptl/pthread_spin_trylock.c: Remove, use generic version.
2012-08-14 Roland McGrath <roland@hack.frob.com>
* sysdeps/unix/sysv/linux/arm/nptl/bits/atomic.h: Renamed to ...

View File

@ -1,3 +1,8 @@
2012-08-15 Maxim Kuvyrkov <maxim@codesourcery.com>
* sysdeps/hppa/nptl/pthread_spin_lock.c: Use generic code.
* sysdeps/hppa/nptl/pthread_spin_trylock.c: Remove, use generic version.
2012-08-12 Mike Frysinger <vapier@gentoo.org>
* sysdeps/unix/sysv/linux/hppa/syscalls.list: Add prlimit64.

View File

@ -1,3 +1,8 @@
2012-08-15 Maxim Kuvyrkov <maxim@codesourcery.com>
* sysdeps/m68k/nptl/pthread_spin_lock.c: Use generic code.
* sysdeps/m68k/nptl/pthread_spin_trylock.c: Remove, use generic version.
2012-08-10 Andreas Schwab <schwab@linux-m68k.org>
* sysdeps/m68k/ldsodefs.h (m68k_gnu_pltenter): Remove const on

View File

@ -1,3 +1,9 @@
2012-08-15 Maxim Kuvyrkov <maxim@codesourcery.com>
* sysdeps/mips/nptl/pthread_spin_lock.S: Remove, use generic version.
* sysdeps/mips/nptl/pthread_spin_lock.c: New file.
* sysdeps/mips/nptl/pthread_spin_trylock.S: Remove, use generic version.
2012-08-15 Joseph Myers <joseph@codesourcery.com>
* sysdeps/mips/dl-lookup.c: Update from generic version.

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2008 Free Software Foundation, Inc.
/* Copyright (C) 2008-2012 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
@ -15,15 +15,9 @@
License along with the GNU C Library. If not, see
<http://www.gnu.org/licenses/>. */
#include <atomic.h>
#include "pthreadP.h"
#define SPIN_LOCK_READS_BETWEEN_CMPXCHG 1000
int
pthread_spin_lock (pthread_spinlock_t *lock)
{
while (atomic_compare_and_exchange_val_acq (lock, 1, 0) != 0)
while (*lock != 0)
;
return 0;
}
/* We can't use the normal "#include <nptl/pthread_spin_lock.c>" because
it will resolve to this very file. Using "sysdeps/.." as reference to the
top level directory does the job. */
#include <sysdeps/../nptl/pthread_spin_lock.c>

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2005 Free Software Foundation, Inc.
/* Copyright (C) 2005-2012 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
@ -15,23 +15,9 @@
License along with the GNU C Library. If not, see
<http://www.gnu.org/licenses/>. */
#include <atomic.h>
#include "pthreadP.h"
#define SPIN_LOCK_READS_BETWEEN_CMPXCHG 1000
int
pthread_spin_lock (pthread_spinlock_t *lock)
{
#if 0
volatile unsigned int *addr = __ldcw_align (lock);
while (__ldcw (addr) == 0)
while (*addr == 0) ;
return 0;
#endif
while (atomic_compare_and_exchange_val_acq(lock, 1, 0) == 1)
while (*lock == 1);
return 0;
}
/* We can't use the normal "#include <nptl/pthread_spin_lock.c>" because
it will resolve to this very file. Using "sysdeps/.." as reference to the
top level directory does the job. */
#include <sysdeps/../nptl/pthread_spin_lock.c>

View File

@ -1,33 +0,0 @@
/* Copyright (C) 2005 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, see
<http://www.gnu.org/licenses/>. */
#include <errno.h>
#include <atomic.h>
#include "pthreadP.h"
int
pthread_spin_trylock (pthread_spinlock_t *lock)
{
#if 0
volatile unsigned int *a = __ldcw_align (lock);
return __ldcw (a) ? 0 : EBUSY;
#endif
return atomic_compare_and_exchange_val_acq(lock, 1, 0) ? EBUSY : 0;
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010 Free Software Foundation, Inc.
/* Copyright (C) 2010-2012 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
@ -16,15 +16,9 @@
License along with the GNU C Library. If not, see
<http://www.gnu.org/licenses/>. */
#include <atomic.h>
#include "pthreadP.h"
#define SPIN_LOCK_READS_BETWEEN_CMPXCHG 1000
int
pthread_spin_lock (pthread_spinlock_t *lock)
{
while (atomic_compare_and_exchange_val_acq(lock, 1, 0) != 0)
while (*lock != 0)
;
return 0;
}
/* We can't use the normal "#include <nptl/pthread_spin_lock.c>" because
it will resolve to this very file. Using "sysdeps/.." as reference to the
top level directory does the job. */
#include <sysdeps/../nptl/pthread_spin_lock.c>

View File

@ -1,36 +0,0 @@
/* Copyright (C) 2005 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, see
<http://www.gnu.org/licenses/>. */
#include <sys/asm.h>
#include <sysdep.h>
#include <sgidefs.h>
ENTRY (pthread_spin_lock)
.set push
#if _MIPS_SIM == _ABIO32
.set mips2
#endif
1: ll a2, 0(a0)
li a1, 1
bnez a2, 1b
sc a1, 0(a0)
beqz a1, 1b
MIPS_SYNC
.set pop
li v0, 0
ret
PSEUDO_END (pthread_spin_lock)

View File

@ -1,6 +1,5 @@
/* Copyright (C) 2010 Free Software Foundation, Inc.
/* Copyright (C) 2012 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@ -16,12 +15,9 @@
License along with the GNU C Library. If not, see
<http://www.gnu.org/licenses/>. */
#include <errno.h>
#include <atomic.h>
#include "pthreadP.h"
#define SPIN_LOCK_READS_BETWEEN_CMPXCHG 1000
int
pthread_spin_trylock (pthread_spinlock_t *lock)
{
return atomic_compare_and_exchange_val_acq(lock, 1, 0) ? EBUSY : 0;
}
/* We can't use the normal "#include <nptl/pthread_spin_lock.c>" because
it will resolve to this very file. Using "sysdeps/.." as reference to the
top level directory does the job. */
#include <sysdeps/../nptl/pthread_spin_lock.c>

View File

@ -1,40 +0,0 @@
/* Copyright (C) 2005 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, see
<http://www.gnu.org/licenses/>. */
#include <sys/asm.h>
#include <sysdep.h>
#define _ERRNO_H 1
#include <bits/errno.h>
#include <sgidefs.h>
ENTRY (pthread_spin_trylock)
.set push
#if _MIPS_SIM == _ABIO32
.set mips2
#endif
ll a2, 0(a0)
li a1, 1
bnez a2, 1f
sc a1, 0(a0)
beqz a1, 1f
MIPS_SYNC
.set pop
li v0, 0
ret
1: li v0, EBUSY
ret
PSEUDO_END (pthread_spin_trylock)