~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/my_thr_init.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000 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
/*
 
17
  Functions to handle initializating and allocationg of all mysys & debug
 
18
  thread variables.
 
19
*/
 
20
 
 
21
#include "mysys_priv.h"
 
22
#include <m_string.h>
 
23
#include <signal.h>
 
24
 
 
25
#ifdef THREAD
 
26
#ifdef USE_TLS
 
27
pthread_key(struct st_my_thread_var*, THR_KEY_mysys);
 
28
#else
 
29
pthread_key(struct st_my_thread_var, THR_KEY_mysys);
 
30
#endif /* USE_TLS */
 
31
pthread_mutex_t THR_LOCK_malloc,THR_LOCK_open,
 
32
                THR_LOCK_lock,THR_LOCK_isam,THR_LOCK_myisam,THR_LOCK_heap,
 
33
                THR_LOCK_net, THR_LOCK_charset, THR_LOCK_threads, THR_LOCK_time;
 
34
pthread_cond_t  THR_COND_threads;
 
35
uint            THR_thread_count= 0;
 
36
uint            my_thread_end_wait_time= 5;
 
37
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
 
38
pthread_mutex_t LOCK_localtime_r;
 
39
#endif
 
40
#ifndef HAVE_GETHOSTBYNAME_R
 
41
pthread_mutex_t LOCK_gethostbyname_r;
 
42
#endif
 
43
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
 
44
pthread_mutexattr_t my_fast_mutexattr;
 
45
#endif
 
46
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
 
47
pthread_mutexattr_t my_errorcheck_mutexattr;
 
48
#endif
 
49
 
 
50
#ifdef TARGET_OS_LINUX
 
51
 
 
52
/*
 
53
  Dummy thread spawned in my_thread_global_init() below to avoid
 
54
  race conditions in NPTL pthread_exit code.
 
55
*/
 
56
 
 
57
static pthread_handler_t
 
58
nptl_pthread_exit_hack_handler(void *arg __attribute((unused)))
 
59
{
 
60
  /* Do nothing! */
 
61
  pthread_exit(0);
 
62
  return 0;
 
63
}
 
64
 
 
65
#endif /* TARGET_OS_LINUX */
 
66
 
 
67
 
 
68
static uint get_thread_lib(void);
 
69
 
 
70
/*
 
71
  initialize thread environment
 
72
 
 
73
  SYNOPSIS
 
74
    my_thread_global_init()
 
75
 
 
76
  RETURN
 
77
    0  ok
 
78
    1  error (Couldn't create THR_KEY_mysys)
 
79
*/
 
80
 
 
81
my_bool my_thread_global_init(void)
 
82
{
 
83
  int pth_ret;
 
84
  thd_lib_detected= get_thread_lib();
 
85
 
 
86
  if ((pth_ret= pthread_key_create(&THR_KEY_mysys, NULL)) != 0)
 
87
  {
 
88
    fprintf(stderr,"Can't initialize threads: error %d\n", pth_ret);
 
89
    return 1;
 
90
  }
 
91
 
 
92
#ifdef TARGET_OS_LINUX
 
93
  /*
 
94
    BUG#24507: Race conditions inside current NPTL pthread_exit()
 
95
    implementation.
 
96
 
 
97
    To avoid a possible segmentation fault during concurrent
 
98
    executions of pthread_exit(), a dummy thread is spawned which
 
99
    initializes internal variables of pthread lib. See bug description
 
100
    for a full explanation.
 
101
 
 
102
    TODO: Remove this code when fixed versions of glibc6 are in common
 
103
    use.
 
104
  */
 
105
  if (thd_lib_detected == THD_LIB_NPTL)
 
106
  {
 
107
    pthread_t       dummy_thread;
 
108
    pthread_attr_t  dummy_thread_attr;
 
109
 
 
110
    pthread_attr_init(&dummy_thread_attr);
 
111
    pthread_attr_setdetachstate(&dummy_thread_attr, PTHREAD_CREATE_DETACHED);
 
112
 
 
113
    pthread_create(&dummy_thread,&dummy_thread_attr,
 
114
                   nptl_pthread_exit_hack_handler, NULL);
 
115
  }
 
116
#endif /* TARGET_OS_LINUX */
 
117
 
 
118
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
 
119
  /*
 
120
    Set mutex type to "fast" a.k.a "adaptive"
 
121
 
 
122
    In this case the thread may steal the mutex from some other thread
 
123
    that is waiting for the same mutex.  This will save us some
 
124
    context switches but may cause a thread to 'starve forever' while
 
125
    waiting for the mutex (not likely if the code within the mutex is
 
126
    short).
 
127
  */
 
128
  pthread_mutexattr_init(&my_fast_mutexattr);
 
129
  pthread_mutexattr_settype(&my_fast_mutexattr,
 
130
                            PTHREAD_MUTEX_ADAPTIVE_NP);
 
131
#endif
 
132
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
 
133
  /*
 
134
    Set mutex type to "errorcheck"
 
135
  */
 
136
  pthread_mutexattr_init(&my_errorcheck_mutexattr);
 
137
  pthread_mutexattr_settype(&my_errorcheck_mutexattr,
 
138
                            PTHREAD_MUTEX_ERRORCHECK);
 
139
#endif
 
140
 
 
141
  pthread_mutex_init(&THR_LOCK_malloc,MY_MUTEX_INIT_FAST);
 
142
  pthread_mutex_init(&THR_LOCK_open,MY_MUTEX_INIT_FAST);
 
143
  pthread_mutex_init(&THR_LOCK_lock,MY_MUTEX_INIT_FAST);
 
144
  pthread_mutex_init(&THR_LOCK_isam,MY_MUTEX_INIT_SLOW);
 
145
  pthread_mutex_init(&THR_LOCK_myisam,MY_MUTEX_INIT_SLOW);
 
146
  pthread_mutex_init(&THR_LOCK_heap,MY_MUTEX_INIT_FAST);
 
147
  pthread_mutex_init(&THR_LOCK_net,MY_MUTEX_INIT_FAST);
 
148
  pthread_mutex_init(&THR_LOCK_charset,MY_MUTEX_INIT_FAST);
 
149
  pthread_mutex_init(&THR_LOCK_threads,MY_MUTEX_INIT_FAST);
 
150
  pthread_mutex_init(&THR_LOCK_time,MY_MUTEX_INIT_FAST);
 
151
  pthread_cond_init(&THR_COND_threads, NULL);
 
152
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
 
153
  pthread_mutex_init(&LOCK_localtime_r,MY_MUTEX_INIT_SLOW);
 
154
#endif
 
155
#ifndef HAVE_GETHOSTBYNAME_R
 
156
  pthread_mutex_init(&LOCK_gethostbyname_r,MY_MUTEX_INIT_SLOW);
 
157
#endif
 
158
  if (my_thread_init())
 
159
  {
 
160
    my_thread_global_end();                     /* Clean up */
 
161
    return 1;
 
162
  }
 
163
  return 0;
 
164
}
 
165
 
 
166
 
 
167
void my_thread_global_end(void)
 
168
{
 
169
  struct timespec abstime;
 
170
  my_bool all_threads_killed= 1;
 
171
 
 
172
  set_timespec(abstime, my_thread_end_wait_time);
 
173
  pthread_mutex_lock(&THR_LOCK_threads);
 
174
  while (THR_thread_count > 0)
 
175
  {
 
176
    int error= pthread_cond_timedwait(&THR_COND_threads, &THR_LOCK_threads,
 
177
                                      &abstime);
 
178
    if (error == ETIMEDOUT || error == ETIME)
 
179
    {
 
180
#ifdef HAVE_PTHREAD_KILL
 
181
      /*
 
182
        We shouldn't give an error here, because if we don't have
 
183
        pthread_kill(), programs like mysqld can't ensure that all threads
 
184
        are killed when we enter here.
 
185
      */
 
186
      if (THR_thread_count)
 
187
        fprintf(stderr,
 
188
                "Error in my_thread_global_end(): %d threads didn't exit\n",
 
189
                THR_thread_count);
 
190
#endif
 
191
      all_threads_killed= 0;
 
192
      break;
 
193
    }
 
194
  }
 
195
  pthread_mutex_unlock(&THR_LOCK_threads);
 
196
 
 
197
  pthread_key_delete(THR_KEY_mysys);
 
198
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
 
199
  pthread_mutexattr_destroy(&my_fast_mutexattr);
 
200
#endif
 
201
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
 
202
  pthread_mutexattr_destroy(&my_errorcheck_mutexattr);
 
203
#endif
 
204
  pthread_mutex_destroy(&THR_LOCK_malloc);
 
205
  pthread_mutex_destroy(&THR_LOCK_open);
 
206
  pthread_mutex_destroy(&THR_LOCK_lock);
 
207
  pthread_mutex_destroy(&THR_LOCK_isam);
 
208
  pthread_mutex_destroy(&THR_LOCK_myisam);
 
209
  pthread_mutex_destroy(&THR_LOCK_heap);
 
210
  pthread_mutex_destroy(&THR_LOCK_net);
 
211
  pthread_mutex_destroy(&THR_LOCK_time);
 
212
  pthread_mutex_destroy(&THR_LOCK_charset);
 
213
  if (all_threads_killed)
 
214
  {
 
215
    pthread_mutex_destroy(&THR_LOCK_threads);
 
216
    pthread_cond_destroy(&THR_COND_threads);
 
217
  }
 
218
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
 
219
  pthread_mutex_destroy(&LOCK_localtime_r);
 
220
#endif
 
221
#ifndef HAVE_GETHOSTBYNAME_R
 
222
  pthread_mutex_destroy(&LOCK_gethostbyname_r);
 
223
#endif
 
224
}
 
225
 
 
226
static my_thread_id thread_id= 0;
 
227
 
 
228
/*
 
229
  Allocate thread specific memory for the thread, used by mysys and dbug
 
230
 
 
231
  SYNOPSIS
 
232
    my_thread_init()
 
233
 
 
234
  NOTES
 
235
    We can't use mutex_locks here if we are using windows as
 
236
    we may have compiled the program with SAFE_MUTEX, in which
 
237
    case the checking of mutex_locks will not work until
 
238
    the pthread_self thread specific variable is initialized.
 
239
 
 
240
   This function may called multiple times for a thread, for example
 
241
   if one uses my_init() followed by mysql_server_init().
 
242
 
 
243
  RETURN
 
244
    0  ok
 
245
    1  Fatal error; mysys/dbug functions can't be used
 
246
*/
 
247
 
 
248
my_bool my_thread_init(void)
 
249
{
 
250
  struct st_my_thread_var *tmp;
 
251
  my_bool error=0;
 
252
 
 
253
#ifdef EXTRA_DEBUG_THREADS
 
254
  fprintf(stderr,"my_thread_init(): thread_id: 0x%lx\n",
 
255
          (ulong) pthread_self());
 
256
#endif  
 
257
 
 
258
  if (my_pthread_getspecific(struct st_my_thread_var *,THR_KEY_mysys))
 
259
  {
 
260
#ifdef EXTRA_DEBUG_THREADS
 
261
    fprintf(stderr,"my_thread_init() called more than once in thread 0x%lx\n",
 
262
            (long) pthread_self());
 
263
#endif    
 
264
    goto end;
 
265
  }
 
266
  if (!(tmp= (struct st_my_thread_var *) calloc(1, sizeof(*tmp))))
 
267
  {
 
268
    error= 1;
 
269
    goto end;
 
270
  }
 
271
  pthread_setspecific(THR_KEY_mysys,tmp);
 
272
  tmp->pthread_self= pthread_self();
 
273
  pthread_mutex_init(&tmp->mutex,MY_MUTEX_INIT_FAST);
 
274
  pthread_cond_init(&tmp->suspend, NULL);
 
275
  tmp->init= 1;
 
276
 
 
277
  pthread_mutex_lock(&THR_LOCK_threads);
 
278
  tmp->id= ++thread_id;
 
279
  ++THR_thread_count;
 
280
  pthread_mutex_unlock(&THR_LOCK_threads);
 
281
#ifndef DBUG_OFF
 
282
  /* Generate unique name for thread */
 
283
  (void) my_thread_name();
 
284
#endif
 
285
 
 
286
end:
 
287
  return error;
 
288
}
 
289
 
 
290
 
 
291
/*
 
292
  Deallocate memory used by the thread for book-keeping
 
293
 
 
294
  SYNOPSIS
 
295
    my_thread_end()
 
296
 
 
297
  NOTE
 
298
    This may be called multiple times for a thread.
 
299
    This happens for example when one calls 'mysql_server_init()'
 
300
    mysql_server_end() and then ends with a mysql_end().
 
301
*/
 
302
 
 
303
void my_thread_end(void)
 
304
{
 
305
  struct st_my_thread_var *tmp;
 
306
  tmp= my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
 
307
 
 
308
#ifdef EXTRA_DEBUG_THREADS
 
309
  fprintf(stderr,"my_thread_end(): tmp: 0x%lx  pthread_self: 0x%lx  thread_id: %ld\n",
 
310
          (long) tmp, (long) pthread_self(), tmp ? (long) tmp->id : 0L);
 
311
#endif  
 
312
  if (tmp && tmp->init)
 
313
  {
 
314
#if !defined(DBUG_OFF)
 
315
    /* tmp->dbug is allocated inside DBUG library */
 
316
    if (tmp->dbug)
 
317
    {
 
318
      DBUG_POP();
 
319
      free(tmp->dbug);
 
320
      tmp->dbug=0;
 
321
    }
 
322
#endif
 
323
#if !defined(__bsdi__) && !defined(__OpenBSD__)
 
324
 /* bsdi and openbsd 3.5 dumps core here */
 
325
    pthread_cond_destroy(&tmp->suspend);
 
326
#endif
 
327
    pthread_mutex_destroy(&tmp->mutex);
 
328
#if defined(USE_TLS)
 
329
    free(tmp);
 
330
#else
 
331
    tmp->init= 0;
 
332
#endif
 
333
 
 
334
    /*
 
335
      Decrement counter for number of running threads. We are using this
 
336
      in my_thread_global_end() to wait until all threads have called
 
337
      my_thread_end and thus freed all memory they have allocated in
 
338
      my_thread_init() and DBUG_xxxx
 
339
    */
 
340
    pthread_mutex_lock(&THR_LOCK_threads);
 
341
    DBUG_ASSERT(THR_thread_count != 0);
 
342
    if (--THR_thread_count == 0)
 
343
      pthread_cond_signal(&THR_COND_threads);
 
344
   pthread_mutex_unlock(&THR_LOCK_threads);
 
345
  }
 
346
  /* The following free has to be done, even if my_thread_var() is 0 */
 
347
#if defined(USE_TLS)
 
348
  pthread_setspecific(THR_KEY_mysys,0);
 
349
#endif
 
350
}
 
351
 
 
352
struct st_my_thread_var *_my_thread_var(void)
 
353
{
 
354
  struct st_my_thread_var *tmp=
 
355
    my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
 
356
#if defined(USE_TLS)
 
357
  /* This can only happen in a .DLL */
 
358
  if (!tmp)
 
359
  {
 
360
    my_thread_init();
 
361
    tmp=my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
 
362
  }
 
363
#endif
 
364
  return tmp;
 
365
}
 
366
 
 
367
 
 
368
/****************************************************************************
 
369
  Get name of current thread.
 
370
****************************************************************************/
 
371
 
 
372
my_thread_id my_thread_dbug_id()
 
373
{
 
374
  return my_thread_var->id;
 
375
}
 
376
 
 
377
#ifdef DBUG_OFF
 
378
const char *my_thread_name(void)
 
379
{
 
380
  return "no_name";
 
381
}
 
382
 
 
383
#else
 
384
 
 
385
const char *my_thread_name(void)
 
386
{
 
387
  char name_buff[100];
 
388
  struct st_my_thread_var *tmp=my_thread_var;
 
389
  if (!tmp->name[0])
 
390
  {
 
391
    my_thread_id id= my_thread_dbug_id();
 
392
    sprintf(name_buff,"T@%lu", (ulong) id);
 
393
    strmake(tmp->name,name_buff,THREAD_NAME_SIZE);
 
394
  }
 
395
  return tmp->name;
 
396
}
 
397
#endif /* DBUG_OFF */
 
398
 
 
399
 
 
400
static uint get_thread_lib(void)
 
401
{
 
402
#ifdef _CS_GNU_LIBPTHREAD_VERSION
 
403
  char buff[64];
 
404
    
 
405
  confstr(_CS_GNU_LIBPTHREAD_VERSION, buff, sizeof(buff));
 
406
 
 
407
  if (!strncasecmp(buff, "NPTL", 4))
 
408
    return THD_LIB_NPTL;
 
409
  if (!strncasecmp(buff, "linuxthreads", 12))
 
410
    return THD_LIB_LT;
 
411
#endif
 
412
  return THD_LIB_OTHER;
 
413
}
 
414
 
 
415
#endif /* THREAD */