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