~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/thr_mutex.cc

Small fixes

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/my_static.h>
26
 
#include <mystrings/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 uint32_t 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 *, const char *file, uint32_t line)
56
 
{
57
 
  memset(mp, 0, sizeof(*mp));
58
 
  pthread_mutex_init(&mp->global,MY_MUTEX_INIT_ERRCHK);
59
 
  pthread_mutex_init(&mp->mutex,attr);
60
 
  /* Mark that mutex is initialized */
61
 
  mp->file= file;
62
 
  mp->line= line;
63
 
 
64
 
#ifdef SAFE_MUTEX_DETECT_DESTROY
65
 
  /*
66
 
    Monitor the freeing of mutexes.  This code depends on single thread init
67
 
    and destroy
68
 
  */
69
 
  if ((mp->info= (safe_mutex_info_t *) malloc(sizeof(safe_mutex_info_t))))
70
 
  {
71
 
    struct st_safe_mutex_info_t *info =mp->info;
72
 
 
73
 
    info->init_file= file;
74
 
    info->init_line= line;
75
 
    info->prev= NULL;
76
 
    info->next= NULL;
77
 
 
78
 
    pthread_mutex_lock(&THR_LOCK_mutex);
79
 
    if ((info->next= safe_mutex_root))
80
 
      safe_mutex_root->prev= info;
81
 
    safe_mutex_root= info;
82
 
    safe_mutex_count++;
83
 
    pthread_mutex_unlock(&THR_LOCK_mutex);
84
 
  }
85
 
#else
86
 
  thread_safe_increment(safe_mutex_count, &THR_LOCK_mutex);
87
 
#endif /* SAFE_MUTEX_DETECT_DESTROY */
88
 
  return 0;
89
 
}
90
 
 
91
 
 
92
 
int safe_mutex_lock(safe_mutex_t *mp, bool try_lock, const char *file, uint32_t line)
93
 
{
94
 
  int error;
95
 
  if (!mp->file)
96
 
  {
97
 
    fprintf(stderr,
98
 
            "safe_mutex: Trying to lock unitialized mutex at %s, line %d\n",
99
 
            file, line);
100
 
    fflush(stderr);
101
 
    abort();
102
 
  }
103
 
 
104
 
  pthread_mutex_lock(&mp->global);
105
 
  if (mp->count > 0)
106
 
  {
107
 
    if (try_lock)
108
 
    {
109
 
      pthread_mutex_unlock(&mp->global);
110
 
      return EBUSY;
111
 
    }
112
 
    else if (pthread_equal(pthread_self(),mp->thread))
113
 
    {
114
 
      fprintf(stderr,
115
 
              "safe_mutex: Trying to lock mutex at %s, line %d, when the"
116
 
              " mutex was already locked at %s, line %d in thread %s\n",
117
 
              file,line,mp->file, mp->line, my_thread_name());
118
 
      fflush(stderr);
119
 
      abort();
120
 
    }
121
 
  }
122
 
  pthread_mutex_unlock(&mp->global);
123
 
 
124
 
  /*
125
 
    If we are imitating trylock(), we need to take special
126
 
    precautions.
127
 
 
128
 
    - We cannot use pthread_mutex_lock() only since another thread can
129
 
      overtake this thread and take the lock before this thread
130
 
      causing pthread_mutex_trylock() to hang. In this case, we should
131
 
      just return EBUSY. Hence, we use pthread_mutex_trylock() to be
132
 
      able to return immediately.
133
 
 
134
 
    - We cannot just use trylock() and continue execution below, since
135
 
      this would generate an error and abort execution if the thread
136
 
      was overtaken and trylock() returned EBUSY . In this case, we
137
 
      instead just return EBUSY, since this is the expected behaviour
138
 
      of trylock().
139
 
   */
140
 
  if (try_lock)
141
 
  {
142
 
    error= pthread_mutex_trylock(&mp->mutex);
143
 
    if (error == EBUSY)
144
 
      return error;
145
 
  }
146
 
  else
147
 
    error= pthread_mutex_lock(&mp->mutex);
148
 
 
149
 
  if (error || (error=pthread_mutex_lock(&mp->global)))
150
 
  {
151
 
    fprintf(stderr,"Got error %d when trying to lock mutex at %s, line %d\n",
152
 
            error, file, line);
153
 
    fflush(stderr);
154
 
    abort();
155
 
  }
156
 
  mp->thread= pthread_self();
157
 
  if (mp->count++)
158
 
  {
159
 
    fprintf(stderr,"safe_mutex: Error in thread libray: Got mutex at %s, \
160
 
line %d more than 1 time\n", file,line);
161
 
    fflush(stderr);
162
 
    abort();
163
 
  }
164
 
  mp->file= file;
165
 
  mp->line=line;
166
 
  pthread_mutex_unlock(&mp->global);
167
 
  return error;
168
 
}
169
 
 
170
 
 
171
 
int safe_mutex_unlock(safe_mutex_t *mp,const char *file, uint32_t line)
172
 
{
173
 
  int error;
174
 
  pthread_mutex_lock(&mp->global);
175
 
  if (mp->count == 0)
176
 
  {
177
 
    fprintf(stderr,"safe_mutex: Trying to unlock mutex that wasn't locked at %s, line %d\n            Last used at %s, line: %d\n",
178
 
            file,line,mp->file ? mp->file : "",mp->line);
179
 
    fflush(stderr);
180
 
    abort();
181
 
  }
182
 
  if (!pthread_equal(pthread_self(),mp->thread))
183
 
  {
184
 
    fprintf(stderr,"safe_mutex: Trying to unlock mutex at %s, line %d  that was locked by another thread at: %s, line: %d\n",
185
 
            file,line,mp->file,mp->line);
186
 
    fflush(stderr);
187
 
    abort();
188
 
  }
189
 
  mp->thread= 0;
190
 
  mp->count--;
191
 
  error=pthread_mutex_unlock(&mp->mutex);
192
 
  if (error)
193
 
  {
194
 
    fprintf(stderr,"safe_mutex: Got error: %d (%d) when trying to unlock mutex at %s, line %d\n", error, errno, file, line);
195
 
    fflush(stderr);
196
 
    abort();
197
 
  }
198
 
  pthread_mutex_unlock(&mp->global);
199
 
  return error;
200
 
}
201
 
 
202
 
 
203
 
int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp, const char *file,
204
 
                   uint32_t line)
205
 
{
206
 
  int error;
207
 
  pthread_mutex_lock(&mp->global);
208
 
  if (mp->count == 0)
209
 
  {
210
 
    fprintf(stderr,"safe_mutex: Trying to cond_wait on a unlocked mutex at %s, line %d\n",file,line);
211
 
    fflush(stderr);
212
 
    abort();
213
 
  }
214
 
  if (!pthread_equal(pthread_self(),mp->thread))
215
 
  {
216
 
    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",
217
 
            file,line,mp->file,mp->line);
218
 
    fflush(stderr);
219
 
    abort();
220
 
  }
221
 
 
222
 
  if (mp->count-- != 1)
223
 
  {
224
 
    fprintf(stderr,"safe_mutex:  Count was %d on locked mutex at %s, line %d\n",
225
 
            mp->count+1, file, line);
226
 
    fflush(stderr);
227
 
    abort();
228
 
  }
229
 
  pthread_mutex_unlock(&mp->global);
230
 
  error=pthread_cond_wait(cond,&mp->mutex);
231
 
  pthread_mutex_lock(&mp->global);
232
 
  if (error)
233
 
  {
234
 
    fprintf(stderr,"safe_mutex: Got error: %d (%d) when doing a safe_mutex_wait at %s, line %d\n", error, errno, file, line);
235
 
    fflush(stderr);
236
 
    abort();
237
 
  }
238
 
  mp->thread=pthread_self();
239
 
  if (mp->count++)
240
 
  {
241
 
    fprintf(stderr,
242
 
            "safe_mutex:  Count was %d in thread 0x%lx when locking mutex at %s, line %d\n",
243
 
            mp->count-1, my_thread_dbug_id(), file, line);
244
 
    fflush(stderr);
245
 
    abort();
246
 
  }
247
 
  mp->file= file;
248
 
  mp->line=line;
249
 
  pthread_mutex_unlock(&mp->global);
250
 
  return error;
251
 
}
252
 
 
253
 
 
254
 
int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp,
255
 
                        struct timespec *abstime,
256
 
                        const char *file, uint32_t line)
257
 
{
258
 
  int error;
259
 
  pthread_mutex_lock(&mp->global);
260
 
  if (mp->count != 1 || !pthread_equal(pthread_self(),mp->thread))
261
 
  {
262
 
    fprintf(stderr,"safe_mutex: Trying to cond_wait at %s, line %d on a not hold mutex\n",file,line);
263
 
    fflush(stderr);
264
 
    abort();
265
 
  }
266
 
  mp->count--;                                  /* Mutex will be released */
267
 
  pthread_mutex_unlock(&mp->global);
268
 
  error=pthread_cond_timedwait(cond,&mp->mutex,abstime);
269
 
#ifdef EXTRA_DEBUG
270
 
  if (error && (error != EINTR && error != ETIMEDOUT && error != ETIME))
271
 
  {
272
 
    fprintf(stderr,"safe_mutex: Got error: %d (%d) when doing a safe_mutex_timedwait at %s, line %d\n", error, errno, file, line);
273
 
  }
274
 
#endif
275
 
  pthread_mutex_lock(&mp->global);
276
 
  mp->thread=pthread_self();
277
 
  if (mp->count++)
278
 
  {
279
 
    fprintf(stderr,
280
 
            "safe_mutex:  Count was %d in thread 0x%lx when locking mutex at %s, line %d (error: %d (%d))\n",
281
 
            mp->count-1, my_thread_dbug_id(), file, line, error, error);
282
 
    fflush(stderr);
283
 
    abort();
284
 
  }
285
 
  mp->file= file;
286
 
  mp->line=line;
287
 
  pthread_mutex_unlock(&mp->global);
288
 
  return error;
289
 
}
290
 
 
291
 
 
292
 
int safe_mutex_destroy(safe_mutex_t *mp, const char *file, uint32_t line)
293
 
{
294
 
  int error=0;
295
 
  if (!mp->file)
296
 
  {
297
 
    fprintf(stderr,
298
 
            "safe_mutex: Trying to destroy unitialized mutex at %s, line %d\n",
299
 
            file, line);
300
 
    fflush(stderr);
301
 
    abort();
302
 
  }
303
 
  if (mp->count != 0)
304
 
  {
305
 
    fprintf(stderr,"safe_mutex: Trying to destroy a mutex that was locked at %s, line %d at %s, line %d\n",
306
 
            mp->file,mp->line, file, line);
307
 
    fflush(stderr);
308
 
    abort();
309
 
  }
310
 
  if (pthread_mutex_destroy(&mp->global))
311
 
    error=1;
312
 
  if (pthread_mutex_destroy(&mp->mutex))
313
 
    error=1;
314
 
  mp->file= 0;                                  /* Mark destroyed */
315
 
 
316
 
#ifdef SAFE_MUTEX_DETECT_DESTROY
317
 
  if (mp->info)
318
 
  {
319
 
    struct st_safe_mutex_info_t *info= mp->info;
320
 
    pthread_mutex_lock(&THR_LOCK_mutex);
321
 
 
322
 
    if (info->prev)
323
 
      info->prev->next = info->next;
324
 
    else
325
 
      safe_mutex_root = info->next;
326
 
    if (info->next)
327
 
      info->next->prev = info->prev;
328
 
    safe_mutex_count--;
329
 
 
330
 
    pthread_mutex_unlock(&THR_LOCK_mutex);
331
 
    free(info);
332
 
    mp->info= NULL;                             /* Get crash if double free */
333
 
  }
334
 
#else
335
 
  thread_safe_sub(safe_mutex_count, 1, &THR_LOCK_mutex);
336
 
#endif /* SAFE_MUTEX_DETECT_DESTROY */
337
 
  return error;
338
 
}
339
 
 
340
 
 
341
 
/*
342
 
  Free global resources and check that all mutex has been destroyed
343
 
 
344
 
  SYNOPSIS
345
 
    safe_mutex_end()
346
 
    file                Print errors on this file
347
 
 
348
 
  NOTES
349
 
 
350
 
   In MySQL one may get one warning for a mutex created in my_thr_init.c
351
 
   This is ok, as this thread may not yet have been exited.
352
 
*/
353
 
 
354
 
void safe_mutex_end(int *)
355
 
{
356
 
  if (!safe_mutex_count)                        /* safetly */
357
 
    pthread_mutex_destroy(&THR_LOCK_mutex);
358
 
#ifdef SAFE_MUTEX_DETECT_DESTROY
359
 
  if (!file)
360
 
    return;
361
 
 
362
 
  if (safe_mutex_count)
363
 
  {
364
 
    fprintf(file, "Warning: Not destroyed mutex: %lu\n", safe_mutex_count);
365
 
    (void) fflush(file);
366
 
  }
367
 
  {
368
 
    struct st_safe_mutex_info_t *ptr;
369
 
    for (ptr= safe_mutex_root ; ptr ; ptr= ptr->next)
370
 
    {
371
 
      fprintf(file, "\tMutex initiated at line %4u in '%s'\n",
372
 
              ptr->init_line, ptr->init_file);
373
 
      (void) fflush(file);
374
 
    }
375
 
  }
376
 
#endif /* SAFE_MUTEX_DETECT_DESTROY */
377
 
}
378
 
 
379
 
#endif /* THREAD && SAFE_MUTEX */
380