~drizzle-trunk/drizzle/development

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