~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/thr_mutex.c

  • Committer: Stewart Smith
  • Date: 2010-11-03 03:30:27 UTC
  • mto: (1902.1.1 build) (1910.1.2 build)
  • mto: This revision was merged to the branch mainline in revision 1903.
  • Revision ID: stewart@flamingspork.com-20101103033027-lskb6gxwwforfz71
fix docs warning: underline/overline too short for replace.rst

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2000-2003 MySQL AB
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 as published by
5
 
   the Free Software Foundation; version 2 of the License.
6
 
 
7
 
   This program is distributed in the hope that it will be useful,
8
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 
   GNU General Public License for more details.
11
 
 
12
 
   You should have received a copy of the GNU General Public License
13
 
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
 
 
16
 
/* This makes a wrapper for mutex handling to make it easier to debug mutex */
17
 
 
18
 
#include "mysys_priv.h"
19
 
 
20
 
#if defined(TARGET_OS_LINUX) && !defined (__USE_UNIX98)
21
 
#define __USE_UNIX98                    /* To get rw locks under Linux */
22
 
#endif
23
 
#if defined(SAFE_MUTEX)
24
 
#undef SAFE_MUTEX                       /* Avoid safe_mutex redefinitions */
25
 
#include "mysys_priv.h"
26
 
#include "my_static.h"
27
 
#include <m_string.h>
28
 
 
29
 
#ifndef DO_NOT_REMOVE_THREAD_WRAPPERS
30
 
/* Remove wrappers */
31
 
#undef pthread_mutex_t
32
 
#undef pthread_mutex_init
33
 
#undef pthread_mutex_lock
34
 
#undef pthread_mutex_unlock
35
 
#undef pthread_mutex_destroy
36
 
#undef pthread_cond_wait
37
 
#undef pthread_cond_timedwait
38
 
#ifdef HAVE_NONPOSIX_PTHREAD_MUTEX_INIT
39
 
#define pthread_mutex_init(a,b) my_pthread_mutex_init((a),(b))
40
 
#endif
41
 
#endif /* DO_NOT_REMOVE_THREAD_WRAPPERS */
42
 
 
43
 
static pthread_mutex_t THR_LOCK_mutex;
44
 
static uint32_t safe_mutex_count= 0;            /* Number of mutexes created */
45
 
#ifdef SAFE_MUTEX_DETECT_DESTROY
46
 
static struct st_safe_mutex_info_t *safe_mutex_root= NULL;
47
 
#endif
48
 
 
49
 
void safe_mutex_global_init(void)
50
 
{
51
 
  pthread_mutex_init(&THR_LOCK_mutex,MY_MUTEX_INIT_FAST);
52
 
}
53
 
 
54
 
 
55
 
int safe_mutex_init(safe_mutex_t *mp,
56
 
                    const pthread_mutexattr_t *attr __attribute__((unused)),
57
 
                    const char *file,
58
 
                    uint32_t line)
59
 
{
60
 
  memset(mp, 0, sizeof(*mp));
61
 
  pthread_mutex_init(&mp->global,MY_MUTEX_INIT_ERRCHK);
62
 
  pthread_mutex_init(&mp->mutex,attr);
63
 
  /* Mark that mutex is initialized */
64
 
  mp->file= file;
65
 
  mp->line= line;
66
 
 
67
 
#ifdef SAFE_MUTEX_DETECT_DESTROY
68
 
  /*
69
 
    Monitor the freeing of mutexes.  This code depends on single thread init
70
 
    and destroy
71
 
  */
72
 
  if ((mp->info= (safe_mutex_info_t *) malloc(sizeof(safe_mutex_info_t))))
73
 
  {
74
 
    struct st_safe_mutex_info_t *info =mp->info;
75
 
 
76
 
    info->init_file= file;
77
 
    info->init_line= line;
78
 
    info->prev= NULL;
79
 
    info->next= NULL;
80
 
 
81
 
    pthread_mutex_lock(&THR_LOCK_mutex);
82
 
    if ((info->next= safe_mutex_root))
83
 
      safe_mutex_root->prev= info;
84
 
    safe_mutex_root= info;
85
 
    safe_mutex_count++;
86
 
    pthread_mutex_unlock(&THR_LOCK_mutex);
87
 
  }
88
 
#else
89
 
  thread_safe_increment(safe_mutex_count, &THR_LOCK_mutex);
90
 
#endif /* SAFE_MUTEX_DETECT_DESTROY */
91
 
  return 0;
92
 
}
93
 
 
94
 
 
95
 
int safe_mutex_lock(safe_mutex_t *mp, bool try_lock, const char *file, uint32_t line)
96
 
{
97
 
  int error;
98
 
  if (!mp->file)
99
 
  {
100
 
    fprintf(stderr,
101
 
            "safe_mutex: Trying to lock unitialized mutex at %s, line %d\n",
102
 
            file, line);
103
 
    fflush(stderr);
104
 
    abort();
105
 
  }
106
 
 
107
 
  pthread_mutex_lock(&mp->global);
108
 
  if (mp->count > 0)
109
 
  {
110
 
    if (try_lock)
111
 
    {
112
 
      pthread_mutex_unlock(&mp->global);
113
 
      return EBUSY;
114
 
    }
115
 
    else if (pthread_equal(pthread_self(),mp->thread))
116
 
    {
117
 
      fprintf(stderr,
118
 
              "safe_mutex: Trying to lock mutex at %s, line %d, when the"
119
 
              " mutex was already locked at %s, line %d in thread %s\n",
120
 
              file,line,mp->file, mp->line, my_thread_name());
121
 
      fflush(stderr);
122
 
      abort();
123
 
    }
124
 
  }
125
 
  pthread_mutex_unlock(&mp->global);
126
 
 
127
 
  /*
128
 
    If we are imitating trylock(), we need to take special
129
 
    precautions.
130
 
 
131
 
    - We cannot use pthread_mutex_lock() only since another thread can
132
 
      overtake this thread and take the lock before this thread
133
 
      causing pthread_mutex_trylock() to hang. In this case, we should
134
 
      just return EBUSY. Hence, we use pthread_mutex_trylock() to be
135
 
      able to return immediately.
136
 
 
137
 
    - We cannot just use trylock() and continue execution below, since
138
 
      this would generate an error and abort execution if the thread
139
 
      was overtaken and trylock() returned EBUSY . In this case, we
140
 
      instead just return EBUSY, since this is the expected behaviour
141
 
      of trylock().
142
 
   */
143
 
  if (try_lock)
144
 
  {
145
 
    error= pthread_mutex_trylock(&mp->mutex);
146
 
    if (error == EBUSY)
147
 
      return error;
148
 
  }
149
 
  else
150
 
    error= pthread_mutex_lock(&mp->mutex);
151
 
 
152
 
  if (error || (error=pthread_mutex_lock(&mp->global)))
153
 
  {
154
 
    fprintf(stderr,"Got error %d when trying to lock mutex at %s, line %d\n",
155
 
            error, file, line);
156
 
    fflush(stderr);
157
 
    abort();
158
 
  }
159
 
  mp->thread= pthread_self();
160
 
  if (mp->count++)
161
 
  {
162
 
    fprintf(stderr,"safe_mutex: Error in thread libray: Got mutex at %s, \
163
 
line %d more than 1 time\n", file,line);
164
 
    fflush(stderr);
165
 
    abort();
166
 
  }
167
 
  mp->file= file;
168
 
  mp->line=line;
169
 
  pthread_mutex_unlock(&mp->global);
170
 
  return error;
171
 
}
172
 
 
173
 
 
174
 
int safe_mutex_unlock(safe_mutex_t *mp,const char *file, uint32_t line)
175
 
{
176
 
  int error;
177
 
  pthread_mutex_lock(&mp->global);
178
 
  if (mp->count == 0)
179
 
  {
180
 
    fprintf(stderr,"safe_mutex: Trying to unlock mutex that wasn't locked at %s, line %d\n            Last used at %s, line: %d\n",
181
 
            file,line,mp->file ? mp->file : "",mp->line);
182
 
    fflush(stderr);
183
 
    abort();
184
 
  }
185
 
  if (!pthread_equal(pthread_self(),mp->thread))
186
 
  {
187
 
    fprintf(stderr,"safe_mutex: Trying to unlock mutex at %s, line %d  that was locked by another thread at: %s, line: %d\n",
188
 
            file,line,mp->file,mp->line);
189
 
    fflush(stderr);
190
 
    abort();
191
 
  }
192
 
  mp->thread= 0;
193
 
  mp->count--;
194
 
  error=pthread_mutex_unlock(&mp->mutex);
195
 
  if (error)
196
 
  {
197
 
    fprintf(stderr,"safe_mutex: Got error: %d (%d) when trying to unlock mutex at %s, line %d\n", error, errno, file, line);
198
 
    fflush(stderr);
199
 
    abort();
200
 
  }
201
 
  pthread_mutex_unlock(&mp->global);
202
 
  return error;
203
 
}
204
 
 
205
 
 
206
 
int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp, const char *file,
207
 
                   uint32_t line)
208
 
{
209
 
  int error;
210
 
  pthread_mutex_lock(&mp->global);
211
 
  if (mp->count == 0)
212
 
  {
213
 
    fprintf(stderr,"safe_mutex: Trying to cond_wait on a unlocked mutex at %s, line %d\n",file,line);
214
 
    fflush(stderr);
215
 
    abort();
216
 
  }
217
 
  if (!pthread_equal(pthread_self(),mp->thread))
218
 
  {
219
 
    fprintf(stderr,"safe_mutex: Trying to cond_wait on a mutex at %s, line %d  that was locked by another thread at: %s, line: %d\n",
220
 
            file,line,mp->file,mp->line);
221
 
    fflush(stderr);
222
 
    abort();
223
 
  }
224
 
 
225
 
  if (mp->count-- != 1)
226
 
  {
227
 
    fprintf(stderr,"safe_mutex:  Count was %d on locked mutex at %s, line %d\n",
228
 
            mp->count+1, file, line);
229
 
    fflush(stderr);
230
 
    abort();
231
 
  }
232
 
  pthread_mutex_unlock(&mp->global);
233
 
  error=pthread_cond_wait(cond,&mp->mutex);
234
 
  pthread_mutex_lock(&mp->global);
235
 
  if (error)
236
 
  {
237
 
    fprintf(stderr,"safe_mutex: Got error: %d (%d) when doing a safe_mutex_wait at %s, line %d\n", error, errno, file, line);
238
 
    fflush(stderr);
239
 
    abort();
240
 
  }
241
 
  mp->thread=pthread_self();
242
 
  if (mp->count++)
243
 
  {
244
 
    fprintf(stderr,
245
 
            "safe_mutex:  Count was %d in thread 0x%lx when locking mutex at %s, line %d\n",
246
 
            mp->count-1, my_thread_dbug_id(), file, line);
247
 
    fflush(stderr);
248
 
    abort();
249
 
  }
250
 
  mp->file= file;
251
 
  mp->line=line;
252
 
  pthread_mutex_unlock(&mp->global);
253
 
  return error;
254
 
}
255
 
 
256
 
 
257
 
int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp,
258
 
                        struct timespec *abstime,
259
 
                        const char *file, uint32_t line)
260
 
{
261
 
  int error;
262
 
  pthread_mutex_lock(&mp->global);
263
 
  if (mp->count != 1 || !pthread_equal(pthread_self(),mp->thread))
264
 
  {
265
 
    fprintf(stderr,"safe_mutex: Trying to cond_wait at %s, line %d on a not hold mutex\n",file,line);
266
 
    fflush(stderr);
267
 
    abort();
268
 
  }
269
 
  mp->count--;                                  /* Mutex will be released */
270
 
  pthread_mutex_unlock(&mp->global);
271
 
  error=pthread_cond_timedwait(cond,&mp->mutex,abstime);
272
 
#ifdef EXTRA_DEBUG
273
 
  if (error && (error != EINTR && error != ETIMEDOUT && error != ETIME))
274
 
  {
275
 
    fprintf(stderr,"safe_mutex: Got error: %d (%d) when doing a safe_mutex_timedwait at %s, line %d\n", error, errno, file, line);
276
 
  }
277
 
#endif
278
 
  pthread_mutex_lock(&mp->global);
279
 
  mp->thread=pthread_self();
280
 
  if (mp->count++)
281
 
  {
282
 
    fprintf(stderr,
283
 
            "safe_mutex:  Count was %d in thread 0x%lx when locking mutex at %s, line %d (error: %d (%d))\n",
284
 
            mp->count-1, my_thread_dbug_id(), file, line, error, error);
285
 
    fflush(stderr);
286
 
    abort();
287
 
  }
288
 
  mp->file= file;
289
 
  mp->line=line;
290
 
  pthread_mutex_unlock(&mp->global);
291
 
  return error;
292
 
}
293
 
 
294
 
 
295
 
int safe_mutex_destroy(safe_mutex_t *mp, const char *file, uint32_t line)
296
 
{
297
 
  int error=0;
298
 
  if (!mp->file)
299
 
  {
300
 
    fprintf(stderr,
301
 
            "safe_mutex: Trying to destroy unitialized mutex at %s, line %d\n",
302
 
            file, line);
303
 
    fflush(stderr);
304
 
    abort();
305
 
  }
306
 
  if (mp->count != 0)
307
 
  {
308
 
    fprintf(stderr,"safe_mutex: Trying to destroy a mutex that was locked at %s, line %d at %s, line %d\n",
309
 
            mp->file,mp->line, file, line);
310
 
    fflush(stderr);
311
 
    abort();
312
 
  }
313
 
  if (pthread_mutex_destroy(&mp->global))
314
 
    error=1;
315
 
  if (pthread_mutex_destroy(&mp->mutex))
316
 
    error=1;
317
 
  mp->file= 0;                                  /* Mark destroyed */
318
 
 
319
 
#ifdef SAFE_MUTEX_DETECT_DESTROY
320
 
  if (mp->info)
321
 
  {
322
 
    struct st_safe_mutex_info_t *info= mp->info;
323
 
    pthread_mutex_lock(&THR_LOCK_mutex);
324
 
 
325
 
    if (info->prev)
326
 
      info->prev->next = info->next;
327
 
    else
328
 
      safe_mutex_root = info->next;
329
 
    if (info->next)
330
 
      info->next->prev = info->prev;
331
 
    safe_mutex_count--;
332
 
 
333
 
    pthread_mutex_unlock(&THR_LOCK_mutex);
334
 
    free(info);
335
 
    mp->info= NULL;                             /* Get crash if double free */
336
 
  }
337
 
#else
338
 
  thread_safe_sub(safe_mutex_count, 1, &THR_LOCK_mutex);
339
 
#endif /* SAFE_MUTEX_DETECT_DESTROY */
340
 
  return error;
341
 
}
342
 
 
343
 
 
344
 
/*
345
 
  Free global resources and check that all mutex has been destroyed
346
 
 
347
 
  SYNOPSIS
348
 
    safe_mutex_end()
349
 
    file                Print errors on this file
350
 
 
351
 
  NOTES
352
 
 
353
 
   In MySQL one may get one warning for a mutex created in my_thr_init.c
354
 
   This is ok, as this thread may not yet have been exited.
355
 
*/
356
 
 
357
 
void safe_mutex_end(int *file __attribute__((unused)))
358
 
{
359
 
  if (!safe_mutex_count)                        /* safetly */
360
 
    pthread_mutex_destroy(&THR_LOCK_mutex);
361
 
#ifdef SAFE_MUTEX_DETECT_DESTROY
362
 
  if (!file)
363
 
    return;
364
 
 
365
 
  if (safe_mutex_count)
366
 
  {
367
 
    fprintf(file, "Warning: Not destroyed mutex: %lu\n", safe_mutex_count);
368
 
    (void) fflush(file);
369
 
  }
370
 
  {
371
 
    struct st_safe_mutex_info_t *ptr;
372
 
    for (ptr= safe_mutex_root ; ptr ; ptr= ptr->next)
373
 
    {
374
 
      fprintf(file, "\tMutex initiated at line %4u in '%s'\n",
375
 
              ptr->init_line, ptr->init_file);
376
 
      (void) fflush(file);
377
 
    }
378
 
  }
379
 
#endif /* SAFE_MUTEX_DETECT_DESTROY */
380
 
}
381
 
 
382
 
#endif /* THREAD && SAFE_MUTEX */
383
 
 
384
 
#if defined(MY_PTHREAD_FASTMUTEX) && !defined(SAFE_MUTEX)
385
 
 
386
 
#include "mysys_priv.h"
387
 
#include "my_static.h"
388
 
#include <m_string.h>
389
 
 
390
 
#include <m_ctype.h>
391
 
#include <myisampack.h>
392
 
#include <mysys_err.h>
393
 
#include <my_sys.h>
394
 
 
395
 
#undef pthread_mutex_t
396
 
#undef pthread_mutex_init
397
 
#undef pthread_mutex_lock
398
 
#undef pthread_mutex_trylock
399
 
#undef pthread_mutex_unlock
400
 
#undef pthread_mutex_destroy
401
 
#undef pthread_cond_wait
402
 
#undef pthread_cond_timedwait
403
 
 
404
 
uint32_t mutex_delay(uint32_t delayloops)
405
 
{
406
 
  uint32_t      i;
407
 
  volatile uint32_t j;
408
 
 
409
 
  j = 0;
410
 
 
411
 
  for (i = 0; i < delayloops * 50; i++)
412
 
    j += i;
413
 
 
414
 
  return(j); 
415
 
}       
416
 
 
417
 
#define MY_PTHREAD_FASTMUTEX_SPINS 8
418
 
#define MY_PTHREAD_FASTMUTEX_DELAY 4
419
 
 
420
 
static int cpu_count= 0;
421
 
 
422
 
int my_pthread_fastmutex_init(my_pthread_fastmutex_t *mp,
423
 
                              const pthread_mutexattr_t *attr)
424
 
{
425
 
  if ((cpu_count > 1) && (attr == MY_MUTEX_INIT_FAST))
426
 
    mp->spins= MY_PTHREAD_FASTMUTEX_SPINS; 
427
 
  else
428
 
    mp->spins= 0;
429
 
  return pthread_mutex_init(&mp->mutex, attr); 
430
 
}
431
 
 
432
 
int my_pthread_fastmutex_lock(my_pthread_fastmutex_t *mp)
433
 
{
434
 
  int   res;
435
 
  uint32_t  i;
436
 
  uint32_t  maxdelay= MY_PTHREAD_FASTMUTEX_DELAY;
437
 
 
438
 
  for (i= 0; i < mp->spins; i++)
439
 
  {
440
 
    res= pthread_mutex_trylock(&mp->mutex);
441
 
 
442
 
    if (res == 0)
443
 
      return 0;
444
 
 
445
 
    if (res != EBUSY)
446
 
      return res;
447
 
 
448
 
    mutex_delay(maxdelay);
449
 
    maxdelay += ((double) random() / (double) RAND_MAX) * 
450
 
                MY_PTHREAD_FASTMUTEX_DELAY + 1;
451
 
  }
452
 
  return pthread_mutex_lock(&mp->mutex);
453
 
}
454
 
 
455
 
 
456
 
void fastmutex_global_init(void)
457
 
{
458
 
#ifdef _SC_NPROCESSORS_CONF
459
 
  cpu_count= sysconf(_SC_NPROCESSORS_CONF);
460
 
#endif
461
 
}
462
 
  
463
 
#endif /* defined(MY_PTHREAD_FASTMUTEX) && !defined(SAFE_MUTEX) */