01572d99ce65a950aeafc962cd2a25807ba51b4e
[platform/upstream/glibc.git] / sysdeps / powerpc / nptl / elide.h
1 /* elide.h: Generic lock elision support for powerpc.
2    Copyright (C) 2014 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
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.
9
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.
14
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/>.  */
18
19 #ifndef ELIDE_PPC_H
20 # define ELIDE_PPC_H
21
22 #ifdef ENABLE_LOCK_ELISION
23 # include <htm.h>
24 # include <elision-conf.h>
25
26 /* Returns true if the lock defined by is_lock_free as elided.
27    ADAPT_COUNT is a pointer to per-lock state variable. */
28
29 static inline bool
30 __elide_lock (uint8_t *adapt_count, int is_lock_free)
31 {
32   if (*adapt_count > 0)
33     {
34       (*adapt_count)--;
35       return false;
36     }
37
38   for (int i = __elision_aconf.try_tbegin; i > 0; i--)
39     {
40       if (__builtin_tbegin (0))
41         {
42           if (is_lock_free)
43             return true;
44           /* Lock was busy.  */
45           __builtin_tabort (_ABORT_LOCK_BUSY);
46         }
47       else
48         {
49           /* A persistent failure indicates that a retry will probably
50              result in another failure.  Use normal locking now and
51              for the next couple of calls.  */
52           if (_TEXASRU_FAILURE_PERSISTENT (__builtin_get_texasru ()))
53             {
54               if (__elision_aconf.skip_lock_internal_abort > 0)
55                 *adapt_count = __elision_aconf.skip_lock_internal_abort;
56               break;
57             }
58           /* Same logic as above, but for a number of temporary failures in a
59              a row.  */
60           else if (__elision_aconf.skip_lock_out_of_tbegin_retries > 0
61                    && __elision_aconf.try_tbegin > 0)
62             *adapt_count = __elision_aconf.skip_lock_out_of_tbegin_retries;
63         }
64      }
65
66   return false;
67 }
68
69 # define ELIDE_LOCK(adapt_count, is_lock_free) \
70   __elide_lock (&(adapt_count), is_lock_free)
71
72
73 static inline bool
74 __elide_trylock (uint8_t *adapt_count, int is_lock_free, int write)
75 {
76   if (__elision_aconf.try_tbegin > 0)
77     {
78       if (write)
79         __builtin_tabort (_ABORT_NESTED_TRYLOCK);
80       return __elide_lock (adapt_count, is_lock_free);
81     }
82   return false;
83 }
84
85 # define ELIDE_TRYLOCK(adapt_count, is_lock_free, write)        \
86   __elide_trylock (&(adapt_count), is_lock_free, write)
87
88
89 static inline bool
90 __elide_unlock (int is_lock_free)
91 {
92   if (is_lock_free)
93     {
94       __builtin_tend (0);
95       return true;
96     }
97   return false;
98 }
99
100 # define ELIDE_UNLOCK(is_lock_free) \
101   __elide_unlock (is_lock_free)
102
103 # else
104
105 # define ELIDE_LOCK(adapt_count, is_lock_free) 0
106 # define ELIDE_TRYLOCK(adapt_count, is_lock_free, write) 0
107 # define ELIDE_UNLOCK(is_lock_free) 0
108
109 #endif /* ENABLE_LOCK_ELISION  */
110
111 #endif