1 /* Elided pthread mutex lock.
2 Copyright (C) 2014-2015 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
21 #include <lowlevellock.h>
22 #include <htmintrin.h>
23 #include <elision-conf.h>
26 #if !defined(LLL_LOCK) && !defined(EXTRAARG)
27 /* Make sure the configuration code is always linked in for static
29 #include "elision-conf.c"
36 #define LLL_LOCK(a,b) lll_lock(a,b), 0
39 #define aconf __elision_aconf
41 /* Adaptive lock using transactions.
42 By default the lock region is run as a transaction, and when it
43 aborts or the lock is busy the lock adapts itself. */
46 __lll_lock_elision (int *futex
, short *adapt_count
, EXTRAARG
int private)
50 /* Lost updates are possible, but harmless. Due to races this might lead
51 to *adapt_count becoming less than zero. */
56 __asm__
volatile (".machinemode \"zarch_nohighgprs\"\n\t"
61 for (try_tbegin
= aconf
.try_tbegin
;
67 ((status
= __builtin_tbegin((void *)0)) == _HTM_TBEGIN_STARTED
, 1))
71 /* Lock was busy. Fall back to normal locking. */
72 if (__builtin_expect (__builtin_tx_nesting_depth (), 1))
74 /* In a non-nested transaction there is no need to abort,
75 which is expensive. */
77 if (aconf
.skip_lock_busy
> 0)
78 *adapt_count
= aconf
.skip_lock_busy
;
81 else /* nesting depth is > 1 */
83 /* A nested transaction will abort eventually because it
84 cannot make any progress before *futex changes back to 0.
85 So we may as well abort immediately.
86 This persistently aborts the outer transaction to force
87 the outer mutex use the default lock instead of retrying
88 with transactions until the try_tbegin of the outer mutex
90 The adapt_count of this inner mutex is not changed,
91 because using the default lock with the inner mutex
92 would abort the outer transaction.
94 __builtin_tabort (_HTM_FIRST_USER_ABORT_CODE
| 1);
99 if (status
!= _HTM_TBEGIN_TRANSIENT
)
101 /* A persistent abort (cc 1 or 3) indicates that a retry is
102 probably futile. Use the normal locking now and for the
103 next couple of calls.
104 Be careful to avoid writing to the lock. */
105 if (aconf
.skip_lock_internal_abort
> 0)
106 *adapt_count
= aconf
.skip_lock_internal_abort
;
112 /* Same logic as above, but for for a number of temporary failures in a
114 if (aconf
.skip_lock_out_of_tbegin_retries
> 0 && aconf
.try_tbegin
> 0)
115 *adapt_count
= aconf
.skip_lock_out_of_tbegin_retries
;
118 return LLL_LOCK ((*futex
), private);