1 /* Copyright (c) 2012, 2021, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24 #ifndef MT_LOCK_HPP
25 #define MT_LOCK_HPP
26
27 #include <ndb_global.h>
28 #include "mt-asm.h"
29 #include <NdbMutex.h>
30
31 #define JAM_FILE_ID 323
32
33
34 struct mt_lock_stat
35 {
36 const void * m_ptr;
37 char * m_name;
38 Uint32 m_contended_count;
39 Uint32 m_spin_count;
40 };
41
42 static void register_lock(const void * ptr, const char * name);
43
44 /**
45 * We will disable use of spinlocks since it doesn't work properly
46 * with realtime settings. Will also provide more stable results in
47 * some environments at the expense of a minor optimisation. If
48 * desirable to have optimal performance without usage of realtime
49 * and always ensuring that each thread runs in its own processor,
50 * then enable spinlocks again by removing comment on
51 * #ifdef NDB_HAVE_XCNG
52 */
53 #if defined(NDB_HAVE_XCNG) && defined(NDB_USE_SPINLOCK)
54 static mt_lock_stat * lookup_lock(const void * ptr);
55 struct thr_spin_lock
56 {
thr_spin_lockthr_spin_lock57 thr_spin_lock(const char * name = 0)
58 {
59 m_lock = 0;
60 register_lock(this, name);
61 }
62
63 volatile Uint32 m_lock;
64 };
65
66 static
67 ATTRIBUTE_NOINLINE
68 void
lock_slow(void * sl,volatile unsigned * val)69 lock_slow(void * sl, volatile unsigned * val)
70 {
71 mt_lock_stat* s = lookup_lock(sl); // lookup before owning lock
72
73 loop:
74 Uint32 spins = 0;
75 do {
76 spins++;
77 cpu_pause();
78 } while (* val == 1);
79
80 if (unlikely(xcng(val, 1) != 0))
81 goto loop;
82
83 if (s)
84 {
85 s->m_spin_count += spins;
86 Uint32 count = ++s->m_contended_count;
87 Uint32 freq = (count > 10000 ? 5000 : (count > 20 ? 200 : 1));
88
89 if ((count % freq) == 0)
90 printf("%s waiting for lock, contentions: %u spins: %u\n",
91 s->m_name, count, s->m_spin_count);
92 }
93 }
94
95 static
96 inline
97 void
lock(struct thr_spin_lock * sl)98 lock(struct thr_spin_lock* sl)
99 {
100 volatile unsigned* val = &sl->m_lock;
101 if (likely(xcng(val, 1) == 0))
102 return;
103
104 lock_slow(sl, val);
105 }
106
107 static
108 inline
109 void
unlock(struct thr_spin_lock * sl)110 unlock(struct thr_spin_lock* sl)
111 {
112 /**
113 * Memory barrier here, to make sure all of our stores are visible before
114 * the lock release is.
115 *
116 * NOTE: Bug#13870457 UNNECESSARY STRONG MEMORY BARRIER ...
117 * Suggest that a 'wmb' may have been sufficient here.
118 * However, as spinlocks are not used anymore,
119 * (see fix for bug#16961971) this will not be fixed.
120 */
121 mb();
122 sl->m_lock = 0;
123 }
124
125 static
126 inline
127 int
trylock(struct thr_spin_lock * sl)128 trylock(struct thr_spin_lock* sl)
129 {
130 volatile unsigned* val = &sl->m_lock;
131 return xcng(val, 1);
132 }
133 #else
134 #define thr_spin_lock thr_mutex
135 #endif
136
137 struct thr_mutex
138 {
thr_mutexthr_mutex139 thr_mutex(const char * name = 0) {
140 NdbMutex_Init(&m_mutex);
141 register_lock(this, name);
142 }
143
144 NdbMutex m_mutex;
145 };
146
147 static
148 inline
149 void
lock(struct thr_mutex * sl)150 lock(struct thr_mutex* sl)
151 {
152 NdbMutex_Lock(&sl->m_mutex);
153 }
154
155 static
156 inline
157 void
unlock(struct thr_mutex * sl)158 unlock(struct thr_mutex* sl)
159 {
160 NdbMutex_Unlock(&sl->m_mutex);
161 }
162
163 static
164 inline
165 int
trylock(struct thr_mutex * sl)166 trylock(struct thr_mutex* sl)
167 {
168 return NdbMutex_Trylock(&sl->m_mutex);
169 }
170
171
172 #undef JAM_FILE_ID
173
174 #endif
175