~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
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
146 by Brian Aker
my_bool cleanup.
82
bool my_thread_global_init(void)
1 by brian
clean slate
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;
146 by Brian Aker
my_bool cleanup.
171
  bool all_threads_killed= 1;
1 by brian
clean slate
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
/*
51.3.28 by Jay Pipes
DBUG entirely removed from server and client
230
  Allocate thread specific memory for the thread, used by mysys
1 by brian
clean slate
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
  RETURN
242
    0  ok
243
    1  Fatal error; mysys/dbug functions can't be used
244
*/
245
146 by Brian Aker
my_bool cleanup.
246
bool my_thread_init(void)
1 by brian
clean slate
247
{
248
  struct st_my_thread_var *tmp;
146 by Brian Aker
my_bool cleanup.
249
  bool error=0;
1 by brian
clean slate
250
251
#ifdef EXTRA_DEBUG_THREADS
252
  fprintf(stderr,"my_thread_init(): thread_id: 0x%lx\n",
253
          (ulong) pthread_self());
254
#endif  
255
5 by Brian Aker
Removed my_pthread_setprio()
256
  if (pthread_getspecific(THR_KEY_mysys))
1 by brian
clean slate
257
  {
258
#ifdef EXTRA_DEBUG_THREADS
259
    fprintf(stderr,"my_thread_init() called more than once in thread 0x%lx\n",
260
            (long) pthread_self());
261
#endif    
262
    goto end;
263
  }
264
  if (!(tmp= (struct st_my_thread_var *) calloc(1, sizeof(*tmp))))
265
  {
266
    error= 1;
267
    goto end;
268
  }
269
  pthread_setspecific(THR_KEY_mysys,tmp);
270
  tmp->pthread_self= pthread_self();
271
  pthread_mutex_init(&tmp->mutex,MY_MUTEX_INIT_FAST);
272
  pthread_cond_init(&tmp->suspend, NULL);
273
  tmp->init= 1;
274
275
  pthread_mutex_lock(&THR_LOCK_threads);
276
  tmp->id= ++thread_id;
277
  ++THR_thread_count;
278
  pthread_mutex_unlock(&THR_LOCK_threads);
279
280
end:
281
  return error;
282
}
283
284
285
/*
286
  Deallocate memory used by the thread for book-keeping
287
288
  SYNOPSIS
289
    my_thread_end()
290
291
  NOTE
292
    This may be called multiple times for a thread.
293
    This happens for example when one calls 'mysql_server_init()'
294
    mysql_server_end() and then ends with a mysql_end().
295
*/
296
297
void my_thread_end(void)
298
{
299
  struct st_my_thread_var *tmp;
5 by Brian Aker
Removed my_pthread_setprio()
300
  tmp= (struct st_my_thread_var *)pthread_getspecific(THR_KEY_mysys);
1 by brian
clean slate
301
302
#ifdef EXTRA_DEBUG_THREADS
303
  fprintf(stderr,"my_thread_end(): tmp: 0x%lx  pthread_self: 0x%lx  thread_id: %ld\n",
304
	  (long) tmp, (long) pthread_self(), tmp ? (long) tmp->id : 0L);
305
#endif  
306
  if (tmp && tmp->init)
307
  {
308
#if !defined(__bsdi__) && !defined(__OpenBSD__)
309
 /* bsdi and openbsd 3.5 dumps core here */
310
    pthread_cond_destroy(&tmp->suspend);
311
#endif
312
    pthread_mutex_destroy(&tmp->mutex);
313
#if defined(USE_TLS)
314
    free(tmp);
315
#else
316
    tmp->init= 0;
317
#endif
318
319
    /*
320
      Decrement counter for number of running threads. We are using this
321
      in my_thread_global_end() to wait until all threads have called
322
      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
323
      my_thread_init() 
1 by brian
clean slate
324
    */
325
    pthread_mutex_lock(&THR_LOCK_threads);
51.3.15 by Jay Pipes
Phase 3 removal of DBUG in mysys
326
    assert(THR_thread_count != 0);
1 by brian
clean slate
327
    if (--THR_thread_count == 0)
328
      pthread_cond_signal(&THR_COND_threads);
329
   pthread_mutex_unlock(&THR_LOCK_threads);
330
  }
331
  /* The following free has to be done, even if my_thread_var() is 0 */
332
#if defined(USE_TLS)
333
  pthread_setspecific(THR_KEY_mysys,0);
334
#endif
335
}
336
337
struct st_my_thread_var *_my_thread_var(void)
338
{
5 by Brian Aker
Removed my_pthread_setprio()
339
  struct st_my_thread_var *tmp= (struct st_my_thread_var*)pthread_getspecific(THR_KEY_mysys);
1 by brian
clean slate
340
#if defined(USE_TLS)
341
  /* This can only happen in a .DLL */
342
  if (!tmp)
343
  {
344
    my_thread_init();
345
    tmp=my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
346
  }
347
#endif
348
  return tmp;
349
}
350
351
352
/****************************************************************************
353
  Get name of current thread.
354
****************************************************************************/
355
356
my_thread_id my_thread_dbug_id()
357
{
358
  return my_thread_var->id;
359
}
360
361
static uint get_thread_lib(void)
362
{
363
#ifdef _CS_GNU_LIBPTHREAD_VERSION
364
  char buff[64];
365
    
366
  confstr(_CS_GNU_LIBPTHREAD_VERSION, buff, sizeof(buff));
367
368
  if (!strncasecmp(buff, "NPTL", 4))
369
    return THD_LIB_NPTL;
370
  if (!strncasecmp(buff, "linuxthreads", 12))
371
    return THD_LIB_LT;
372
#endif
373
  return THD_LIB_OTHER;
374
}