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