1 /*
2 Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25
26 #include <ndb_global.h>
27
28 #include <NdbMutex.h>
29 #include <NdbMem.h>
30
31 #ifdef NDB_MUTEX_STAT
32 static FILE * statout = 0;
33 #endif
34
NdbMutex_Create()35 NdbMutex* NdbMutex_Create()
36 {
37 return NdbMutex_CreateWithName(0);
38 }
39
NdbMutex_CreateWithName(const char * name)40 NdbMutex* NdbMutex_CreateWithName(const char * name)
41 {
42 NdbMutex* pNdbMutex;
43 int result;
44
45 pNdbMutex = (NdbMutex*)NdbMem_Allocate(sizeof(NdbMutex));
46
47 if (pNdbMutex == NULL)
48 return NULL;
49
50 result = NdbMutex_InitWithName(pNdbMutex, name);
51 if (result == 0)
52 {
53 return pNdbMutex;
54 }
55 NdbMem_Free(pNdbMutex);
56 return 0;
57 }
58
NdbMutex_Init(NdbMutex * pNdbMutex)59 int NdbMutex_Init(NdbMutex* pNdbMutex)
60 {
61 return NdbMutex_InitWithName(pNdbMutex, 0);
62 }
63
NdbMutex_InitWithName(NdbMutex * pNdbMutex,const char * name)64 int NdbMutex_InitWithName(NdbMutex* pNdbMutex, const char * name)
65 {
66 int result;
67 pthread_mutex_t * p;
68 DBUG_ENTER("NdbMutex_Init");
69
70 #ifdef NDB_MUTEX_STAT
71 bzero(pNdbMutex, sizeof(NdbMutex));
72 pNdbMutex->min_lock_wait_time_ns = ~(Uint64)0;
73 pNdbMutex->min_hold_time_ns = ~(Uint64)0;
74 p = &pNdbMutex->mutex;
75 if (name == 0)
76 {
77 snprintf(pNdbMutex->name, sizeof(pNdbMutex->name), "%p",
78 pNdbMutex);
79 }
80 else
81 {
82 snprintf(pNdbMutex->name, sizeof(pNdbMutex->name), "%p:%s",
83 pNdbMutex, name);
84 }
85 if (getenv("NDB_MUTEX_STAT") != 0)
86 {
87 statout = stdout;
88 }
89 #else
90 p = pNdbMutex;
91 (void)name;
92 #endif
93
94 #if defined(VM_TRACE) && \
95 defined(HAVE_PTHREAD_MUTEXATTR_INIT) && \
96 defined(HAVE_PTHREAD_MUTEXATTR_SETTYPE)
97
98 {
99 pthread_mutexattr_t t;
100 pthread_mutexattr_init(&t);
101 pthread_mutexattr_settype(&t, PTHREAD_MUTEX_ERRORCHECK);
102 result = pthread_mutex_init(p, &t);
103 assert(result == 0);
104 pthread_mutexattr_destroy(&t);
105 }
106 #else
107 result = pthread_mutex_init(p, 0);
108 #endif
109 DBUG_RETURN(result);
110 }
111
NdbMutex_Destroy(NdbMutex * p_mutex)112 int NdbMutex_Destroy(NdbMutex* p_mutex)
113 {
114 int result;
115
116 if (p_mutex == NULL)
117 return -1;
118
119 #ifdef NDB_MUTEX_STAT
120 result = pthread_mutex_destroy(&p_mutex->mutex);
121 #else
122 result = pthread_mutex_destroy(p_mutex);
123 #endif
124
125 NdbMem_Free(p_mutex);
126
127 return result;
128 }
129
130 #ifdef NDB_MUTEX_STAT
131 static
132 inline
133 Uint64
now()134 now()
135 {
136 struct timespec ts;
137 clock_gettime(CLOCK_MONOTONIC, &ts);
138 return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
139 }
140
141 static
142 void
dumpstat(NdbMutex * p)143 dumpstat(NdbMutex* p)
144 {
145 if (statout != 0)
146 {
147 fprintf(statout,
148 "%s : "
149 " lock [ cnt: %u con: %u wait: [ min: %llu avg: %llu max: %llu ] ]"
150 " trylock [ ok: %u nok: %u ]"
151 " hold: [ min: %llu avg: %llu max: %llu ]\n",
152 p->name,
153 p->cnt_lock,
154 p->cnt_lock_contention,
155 p->min_lock_wait_time_ns,
156 p->cnt_lock_contention ?
157 p->sum_lock_wait_time_ns / p->cnt_lock_contention : 0,
158 p->max_lock_wait_time_ns,
159 p->cnt_trylock_ok,
160 p->cnt_trylock_nok,
161 p->min_hold_time_ns,
162 (p->cnt_lock + p->cnt_trylock_ok) ?
163 p->sum_hold_time_ns / (p->cnt_lock + p->cnt_trylock_ok) : 0,
164 p->max_hold_time_ns);
165 }
166 p->cnt_lock = 0;
167 p->cnt_lock_contention = 0;
168 p->cnt_trylock_ok = 0;
169 p->cnt_trylock_nok = 0;
170 p->min_lock_wait_time_ns = ~(Uint64)0;
171 p->sum_lock_wait_time_ns = 0;
172 p->max_lock_wait_time_ns = 0;
173 p->min_hold_time_ns = ~(Uint64)0;
174 p->sum_hold_time_ns = 0;
175 p->max_hold_time_ns = 0;
176 }
177
178 #endif
179
NdbMutex_Lock(NdbMutex * p_mutex)180 int NdbMutex_Lock(NdbMutex* p_mutex)
181 {
182 int result;
183
184 if (p_mutex == NULL)
185 return -1;
186
187 #ifdef NDB_MUTEX_STAT
188 {
189 Uint64 stop;
190 if ((result = pthread_mutex_trylock(&p_mutex->mutex)) == 0)
191 {
192 stop = now();
193 }
194 else
195 {
196 Uint64 start = now();
197 assert(result == EBUSY);
198 result = pthread_mutex_lock(&p_mutex->mutex);
199 stop = now();
200 p_mutex->cnt_lock_contention++;
201 Uint64 t = (stop - start);
202 p_mutex->sum_lock_wait_time_ns += t;
203 if (t < p_mutex->min_lock_wait_time_ns)
204 p_mutex->min_lock_wait_time_ns = t;
205 if (t > p_mutex->max_lock_wait_time_ns)
206 p_mutex->max_lock_wait_time_ns = t;
207 }
208 p_mutex->cnt_lock++;
209 p_mutex->lock_start_time_ns = stop;
210 }
211 #else
212 result = pthread_mutex_lock(p_mutex);
213 #endif
214 assert(result == 0);
215
216 return result;
217 }
218
219
NdbMutex_Unlock(NdbMutex * p_mutex)220 int NdbMutex_Unlock(NdbMutex* p_mutex)
221 {
222 int result;
223
224 if (p_mutex == NULL)
225 return -1;
226
227 #ifdef NDB_MUTEX_STAT
228 {
229 Uint64 stop = now() - p_mutex->lock_start_time_ns;
230 p_mutex->sum_hold_time_ns += stop;
231 if (stop < p_mutex->min_hold_time_ns)
232 p_mutex->min_hold_time_ns = stop;
233 if (stop > p_mutex->max_hold_time_ns)
234 p_mutex->max_hold_time_ns = stop;
235 result = pthread_mutex_unlock(&p_mutex->mutex);
236 if (((p_mutex->sum_hold_time_ns + p_mutex->sum_lock_wait_time_ns)
237 >= 3*1000000000ULL) ||
238 p_mutex->cnt_lock >= 16384 ||
239 p_mutex->cnt_trylock_ok >= 16384)
240 {
241 dumpstat(p_mutex);
242 }
243 }
244 #else
245 result = pthread_mutex_unlock(p_mutex);
246 #endif
247 assert(result == 0);
248
249 return result;
250 }
251
252
NdbMutex_Trylock(NdbMutex * p_mutex)253 int NdbMutex_Trylock(NdbMutex* p_mutex)
254 {
255 int result;
256
257 if (p_mutex == NULL)
258 return -1;
259
260 #ifdef NDB_MUTEX_STAT
261 result = pthread_mutex_trylock(&p_mutex->mutex);
262 if (result == 0)
263 {
264 p_mutex->cnt_trylock_ok++;
265 p_mutex->lock_start_time_ns = now();
266 }
267 else
268 {
269 __sync_fetch_and_add(&p_mutex->cnt_trylock_nok, 1);
270 }
271 #else
272 result = pthread_mutex_trylock(p_mutex);
273 #endif
274 assert(result == 0 || result == EBUSY);
275
276 return result;
277 }
278
279