Update copyright dates with scripts/update-copyrights.
[glibc.git] / sysdeps / unix / sysv / linux / s390 / elision-lock.c
blobbb3bf0e2890a1ed6c344301f6beacfa8314ea178
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/>. */
19 #include <pthread.h>
20 #include <pthreadP.h>
21 #include <lowlevellock.h>
22 #include <htmintrin.h>
23 #include <elision-conf.h>
24 #include <stdint.h>
26 #if !defined(LLL_LOCK) && !defined(EXTRAARG)
27 /* Make sure the configuration code is always linked in for static
28 libraries. */
29 #include "elision-conf.c"
30 #endif
32 #ifndef EXTRAARG
33 #define EXTRAARG
34 #endif
35 #ifndef LLL_LOCK
36 #define LLL_LOCK(a,b) lll_lock(a,b), 0
37 #endif
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. */
45 int
46 __lll_lock_elision (int *futex, short *adapt_count, EXTRAARG int private)
48 if (*adapt_count > 0)
50 /* Lost updates are possible, but harmless. Due to races this might lead
51 to *adapt_count becoming less than zero. */
52 (*adapt_count)--;
53 goto use_lock;
56 __asm__ volatile (".machinemode \"zarch_nohighgprs\"\n\t"
57 ".machine \"all\""
58 : : : "memory");
60 int try_tbegin;
61 for (try_tbegin = aconf.try_tbegin;
62 try_tbegin > 0;
63 try_tbegin--)
65 unsigned status;
66 if (__builtin_expect
67 ((status = __builtin_tbegin((void *)0)) == _HTM_TBEGIN_STARTED, 1))
69 if (*futex == 0)
70 return 0;
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. */
76 __builtin_tend ();
77 if (aconf.skip_lock_busy > 0)
78 *adapt_count = aconf.skip_lock_busy;
79 goto use_lock;
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
89 is zero.
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);
97 else
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;
107 goto use_lock;
112 /* Same logic as above, but for for a number of temporary failures in a
113 row. */
114 if (aconf.skip_lock_out_of_tbegin_retries > 0 && aconf.try_tbegin > 0)
115 *adapt_count = aconf.skip_lock_out_of_tbegin_retries;
117 use_lock:
118 return LLL_LOCK ((*futex), private);