~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to mysys/thr_mutex.c

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
Import upstream version 5.1.45

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