Blame sysdeps/unix/sysv/linux/x86_64/lowlevellock.h

Packit 6c4009
/* Copyright (C) 2002-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#ifndef _LOWLEVELLOCK_H
Packit 6c4009
#define _LOWLEVELLOCK_H	1
Packit 6c4009
Packit 6c4009
#include <stap-probe.h>
Packit 6c4009
Packit 6c4009
#ifndef __ASSEMBLER__
Packit 6c4009
# include <time.h>
Packit 6c4009
# include <sys/param.h>
Packit 6c4009
# include <bits/pthreadtypes.h>
Packit 6c4009
# include <kernel-features.h>
Packit 6c4009
Packit 6c4009
# ifndef LOCK_INSTR
Packit 6c4009
#  ifdef UP
Packit 6c4009
#   define LOCK_INSTR	/* nothing */
Packit 6c4009
#  else
Packit 6c4009
#   define LOCK_INSTR "lock;"
Packit 6c4009
#  endif
Packit 6c4009
# endif
Packit 6c4009
#else
Packit 6c4009
# ifndef LOCK
Packit 6c4009
#  ifdef UP
Packit 6c4009
#   define LOCK
Packit 6c4009
#  else
Packit 6c4009
#   define LOCK lock
Packit 6c4009
#  endif
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#include <lowlevellock-futex.h>
Packit 6c4009
Packit 6c4009
/* XXX Remove when no assembler code uses futexes anymore.  */
Packit 6c4009
#define SYS_futex		__NR_futex
Packit 6c4009
Packit 6c4009
#ifndef __ASSEMBLER__
Packit 6c4009
Packit 6c4009
/* Initializer for lock.  */
Packit 6c4009
#define LLL_LOCK_INITIALIZER		(0)
Packit 6c4009
#define LLL_LOCK_INITIALIZER_LOCKED	(1)
Packit 6c4009
#define LLL_LOCK_INITIALIZER_WAITERS	(2)
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* NB: in the lll_trylock macro we simply return the value in %eax
Packit 6c4009
   after the cmpxchg instruction.  In case the operation succeded this
Packit 6c4009
   value is zero.  In case the operation failed, the cmpxchg instruction
Packit 6c4009
   has loaded the current value of the memory work which is guaranteed
Packit 6c4009
   to be nonzero.  */
Packit 6c4009
#if !IS_IN (libc) || defined UP
Packit 6c4009
# define __lll_trylock_asm LOCK_INSTR "cmpxchgl %2, %1"
Packit 6c4009
#else
Packit 6c4009
# define __lll_trylock_asm "cmpl $0, __libc_multiple_threads(%%rip)\n\t"      \
Packit 6c4009
			   "je 0f\n\t"					      \
Packit 6c4009
			   "lock; cmpxchgl %2, %1\n\t"			      \
Packit 6c4009
			   "jmp 1f\n\t"					      \
Packit 6c4009
			   "0:\tcmpxchgl %2, %1\n\t"			      \
Packit 6c4009
			   "1:"
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#define lll_trylock(futex) \
Packit 6c4009
  ({ int ret;								      \
Packit 6c4009
     __asm __volatile (__lll_trylock_asm				      \
Packit 6c4009
		       : "=a" (ret), "=m" (futex)			      \
Packit 6c4009
		       : "r" (LLL_LOCK_INITIALIZER_LOCKED), "m" (futex),      \
Packit 6c4009
			 "0" (LLL_LOCK_INITIALIZER)			      \
Packit 6c4009
		       : "memory");					      \
Packit 6c4009
     ret; })
Packit 6c4009
Packit 6c4009
#define lll_cond_trylock(futex) \
Packit 6c4009
  ({ int ret;								      \
Packit 6c4009
     __asm __volatile (LOCK_INSTR "cmpxchgl %2, %1"			      \
Packit 6c4009
		       : "=a" (ret), "=m" (futex)			      \
Packit 6c4009
		       : "r" (LLL_LOCK_INITIALIZER_WAITERS),		      \
Packit 6c4009
			 "m" (futex), "0" (LLL_LOCK_INITIALIZER)	      \
Packit 6c4009
		       : "memory");					      \
Packit 6c4009
     ret; })
Packit 6c4009
Packit 6c4009
#if !IS_IN (libc) || defined UP
Packit 6c4009
# define __lll_lock_asm_start LOCK_INSTR "cmpxchgl %4, %2\n\t"		      \
Packit 6c4009
			      "jz 24f\n\t"
Packit 6c4009
#else
Packit 6c4009
# define __lll_lock_asm_start "cmpl $0, __libc_multiple_threads(%%rip)\n\t"   \
Packit 6c4009
			      "je 0f\n\t"				      \
Packit 6c4009
			      "lock; cmpxchgl %4, %2\n\t"		      \
Packit 6c4009
			      "jnz 1f\n\t"				      \
Packit 6c4009
			      "jmp 24f\n"				      \
Packit 6c4009
			      "0:\tcmpxchgl %4, %2\n\t"			      \
Packit 6c4009
			      "jz 24f\n\t"
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#define lll_lock(futex, private) \
Packit 6c4009
  (void)								      \
Packit 6c4009
    ({ int ignore1, ignore2, ignore3;					      \
Packit 6c4009
       if (__builtin_constant_p (private) && (private) == LLL_PRIVATE)	      \
Packit 6c4009
	 __asm __volatile (__lll_lock_asm_start				      \
Packit 6c4009
			   "1:\tlea %2, %%" RDI_LP "\n"			      \
Packit 6c4009
			   "2:\tsub $128, %%" RSP_LP "\n"		      \
Packit 6c4009
			   ".cfi_adjust_cfa_offset 128\n"		      \
Packit 6c4009
			   "3:\tcallq __lll_lock_wait_private\n"	      \
Packit 6c4009
			   "4:\tadd $128, %%" RSP_LP "\n"		      \
Packit 6c4009
			   ".cfi_adjust_cfa_offset -128\n"		      \
Packit 6c4009
			   "24:"					      \
Packit 6c4009
			   : "=S" (ignore1), "=&D" (ignore2), "=m" (futex),   \
Packit 6c4009
			     "=a" (ignore3)				      \
Packit 6c4009
			   : "0" (1), "m" (futex), "3" (0)		      \
Packit 6c4009
			   : "cx", "r11", "cc", "memory");		      \
Packit 6c4009
       else								      \
Packit 6c4009
	 __asm __volatile (__lll_lock_asm_start				      \
Packit 6c4009
			   "1:\tlea %2, %%" RDI_LP "\n"			      \
Packit 6c4009
			   "2:\tsub $128, %%" RSP_LP "\n"		      \
Packit 6c4009
			   ".cfi_adjust_cfa_offset 128\n"		      \
Packit 6c4009
			   "3:\tcallq __lll_lock_wait\n"		      \
Packit 6c4009
			   "4:\tadd $128, %%" RSP_LP "\n"		      \
Packit 6c4009
			   ".cfi_adjust_cfa_offset -128\n"		      \
Packit 6c4009
			   "24:"					      \
Packit 6c4009
			   : "=S" (ignore1), "=D" (ignore2), "=m" (futex),    \
Packit 6c4009
			     "=a" (ignore3)				      \
Packit 6c4009
			   : "1" (1), "m" (futex), "3" (0), "0" (private)     \
Packit 6c4009
			   : "cx", "r11", "cc", "memory");		      \
Packit 6c4009
    })									      \
Packit 6c4009
Packit 6c4009
#define lll_cond_lock(futex, private) \
Packit 6c4009
  (void)								      \
Packit 6c4009
    ({ int ignore1, ignore2, ignore3;					      \
Packit 6c4009
       __asm __volatile (LOCK_INSTR "cmpxchgl %4, %2\n\t"		      \
Packit 6c4009
			 "jz 24f\n"					      \
Packit 6c4009
			 "1:\tlea %2, %%" RDI_LP "\n"			      \
Packit 6c4009
			 "2:\tsub $128, %%" RSP_LP "\n"			      \
Packit 6c4009
			 ".cfi_adjust_cfa_offset 128\n"			      \
Packit 6c4009
			 "3:\tcallq __lll_lock_wait\n"			      \
Packit 6c4009
			 "4:\tadd $128, %%" RSP_LP "\n"			      \
Packit 6c4009
			 ".cfi_adjust_cfa_offset -128\n"		      \
Packit 6c4009
			 "24:"						      \
Packit 6c4009
			 : "=S" (ignore1), "=D" (ignore2), "=m" (futex),      \
Packit 6c4009
			   "=a" (ignore3)				      \
Packit 6c4009
			 : "1" (2), "m" (futex), "3" (0), "0" (private)	      \
Packit 6c4009
			 : "cx", "r11", "cc", "memory");		      \
Packit 6c4009
    })
Packit 6c4009
Packit 6c4009
#define lll_timedlock(futex, timeout, private) \
Packit 6c4009
  ({ int result, ignore1, ignore2, ignore3;				      \
Packit 6c4009
     __asm __volatile (LOCK_INSTR "cmpxchgl %1, %4\n\t"			      \
Packit 6c4009
		       "jz 24f\n"					      \
Packit 6c4009
		       "1:\tlea %4, %%" RDI_LP "\n"			      \
Packit 6c4009
		       "0:\tmov %8, %%" RDX_LP "\n"			      \
Packit 6c4009
		       "2:\tsub $128, %%" RSP_LP "\n"			      \
Packit 6c4009
		       ".cfi_adjust_cfa_offset 128\n"			      \
Packit 6c4009
		       "3:\tcallq __lll_timedlock_wait\n"		      \
Packit 6c4009
		       "4:\tadd $128, %%" RSP_LP "\n"			      \
Packit 6c4009
		       ".cfi_adjust_cfa_offset -128\n"			      \
Packit 6c4009
		       "24:"						      \
Packit 6c4009
		       : "=a" (result), "=D" (ignore1), "=S" (ignore2),	      \
Packit 6c4009
			 "=&d" (ignore3), "=m" (futex)			      \
Packit 6c4009
		       : "0" (0), "1" (1), "m" (futex), "m" (timeout),	      \
Packit 6c4009
			 "2" (private)					      \
Packit 6c4009
		       : "memory", "cx", "cc", "r10", "r11");		      \
Packit 6c4009
     result; })
Packit 6c4009
Packit 6c4009
extern int __lll_timedlock_elision (int *futex, short *adapt_count,
Packit 6c4009
					 const struct timespec *timeout,
Packit 6c4009
					 int private) attribute_hidden;
Packit 6c4009
Packit 6c4009
#define lll_timedlock_elision(futex, adapt_count, timeout, private)	\
Packit 6c4009
  __lll_timedlock_elision(&(futex), &(adapt_count), timeout, private)
Packit 6c4009
Packit 6c4009
#if !IS_IN (libc) || defined UP
Packit 6c4009
# define __lll_unlock_asm_start LOCK_INSTR "decl %0\n\t"		      \
Packit 6c4009
				"je 24f\n\t"
Packit 6c4009
#else
Packit 6c4009
# define __lll_unlock_asm_start "cmpl $0, __libc_multiple_threads(%%rip)\n\t" \
Packit 6c4009
				"je 0f\n\t"				      \
Packit 6c4009
				"lock; decl %0\n\t"			      \
Packit 6c4009
				"jne 1f\n\t"				      \
Packit 6c4009
				"jmp 24f\n\t"				      \
Packit 6c4009
				"0:\tdecl %0\n\t"			      \
Packit 6c4009
				"je 24f\n\t"
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#define lll_unlock(futex, private) \
Packit 6c4009
  (void)								      \
Packit 6c4009
    ({ int ignore;							      \
Packit 6c4009
       if (__builtin_constant_p (private) && (private) == LLL_PRIVATE)	      \
Packit 6c4009
	 __asm __volatile (__lll_unlock_asm_start			      \
Packit 6c4009
			   "1:\tlea %0, %%" RDI_LP "\n"			      \
Packit 6c4009
			   "2:\tsub $128, %%" RSP_LP "\n"		      \
Packit 6c4009
			   ".cfi_adjust_cfa_offset 128\n"		      \
Packit 6c4009
			   "3:\tcallq __lll_unlock_wake_private\n"	      \
Packit 6c4009
			   "4:\tadd $128, %%" RSP_LP "\n"		      \
Packit 6c4009
			   ".cfi_adjust_cfa_offset -128\n"		      \
Packit 6c4009
			   "24:"					      \
Packit 6c4009
			   : "=m" (futex), "=&D" (ignore)		      \
Packit 6c4009
			   : "m" (futex)				      \
Packit 6c4009
			   : "ax", "cx", "r11", "cc", "memory");	      \
Packit 6c4009
       else								      \
Packit 6c4009
	 __asm __volatile (__lll_unlock_asm_start			      \
Packit 6c4009
			   "1:\tlea %0, %%" RDI_LP "\n"			      \
Packit 6c4009
			   "2:\tsub $128, %%" RSP_LP "\n"		      \
Packit 6c4009
			   ".cfi_adjust_cfa_offset 128\n"		      \
Packit 6c4009
			   "3:\tcallq __lll_unlock_wake\n"		      \
Packit 6c4009
			   "4:\tadd $128, %%" RSP_LP "\n"		      \
Packit 6c4009
			   ".cfi_adjust_cfa_offset -128\n"		      \
Packit 6c4009
			   "24:"					      \
Packit 6c4009
			   : "=m" (futex), "=&D" (ignore)		      \
Packit 6c4009
			   : "m" (futex), "S" (private)			      \
Packit 6c4009
			   : "ax", "cx", "r11", "cc", "memory");	      \
Packit 6c4009
    })
Packit 6c4009
Packit 6c4009
#define lll_islocked(futex) \
Packit 6c4009
  (futex != LLL_LOCK_INITIALIZER)
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* The kernel notifies a process which uses CLONE_CHILD_CLEARTID via futex
Packit 6c4009
   wake-up when the clone terminates.  The memory location contains the
Packit 6c4009
   thread ID while the clone is running and is reset to zero by the kernel
Packit 6c4009
   afterwards.  The kernel up to version 3.16.3 does not use the private futex
Packit 6c4009
   operations for futex wake-up when the clone terminates.  */
Packit 6c4009
#define lll_wait_tid(tid) \
Packit 6c4009
  do {					\
Packit 6c4009
    __typeof (tid) __tid;		\
Packit 6c4009
    while ((__tid = (tid)) != 0)	\
Packit 6c4009
      lll_futex_wait (&(tid), __tid, LLL_SHARED);\
Packit 6c4009
  } while (0)
Packit 6c4009
Packit 6c4009
extern int __lll_timedwait_tid (int *, const struct timespec *)
Packit 6c4009
     attribute_hidden;
Packit 6c4009
Packit 6c4009
/* As lll_wait_tid, but with a timeout.  If the timeout occurs then return
Packit 6c4009
   ETIMEDOUT.  If ABSTIME is invalid, return EINVAL.
Packit 6c4009
   XXX Note that this differs from the generic version in that we do the
Packit 6c4009
   error checking here and not in __lll_timedwait_tid.  */
Packit 6c4009
#define lll_timedwait_tid(tid, abstime) \
Packit 6c4009
  ({									      \
Packit 6c4009
    int __result = 0;							      \
Packit 6c4009
    if ((tid) != 0)							      \
Packit 6c4009
      __result = __lll_timedwait_tid (&(tid), (abstime));		      \
Packit 6c4009
    __result; })
Packit 6c4009
Packit 6c4009
extern int __lll_lock_elision (int *futex, short *adapt_count, int private)
Packit 6c4009
  attribute_hidden;
Packit 6c4009
Packit 6c4009
extern int __lll_unlock_elision (int *lock, int private)
Packit 6c4009
  attribute_hidden;
Packit 6c4009
Packit 6c4009
extern int __lll_trylock_elision (int *lock, short *adapt_count)
Packit 6c4009
  attribute_hidden;
Packit 6c4009
Packit 6c4009
#define lll_lock_elision(futex, adapt_count, private) \
Packit 6c4009
  __lll_lock_elision (&(futex), &(adapt_count), private)
Packit 6c4009
#define lll_unlock_elision(futex, adapt_count, private) \
Packit 6c4009
  __lll_unlock_elision (&(futex), private)
Packit 6c4009
#define lll_trylock_elision(futex, adapt_count) \
Packit 6c4009
  __lll_trylock_elision (&(futex), &(adapt_count))
Packit 6c4009
Packit 6c4009
#endif  /* !__ASSEMBLER__ */
Packit 6c4009
Packit 6c4009
#endif	/* lowlevellock.h */