~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/my_thr_init.c

  • Committer: Monty Taylor
  • Date: 2008-07-15 21:40:58 UTC
  • mfrom: (77.1.113 codestyle32)
  • mto: This revision was merged to the branch mainline in revision 176.
  • Revision ID: mordred@camelot-20080715214058-rm3phulldos9xehv
Merged from codestyle.

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
 
12
12
   You should have received a copy of the GNU General Public License
13
13
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
16
/*
17
17
  Functions to handle initializating and allocationg of all mysys & debug
18
18
  thread variables.
19
19
*/
20
20
 
21
 
#include <config.h>
22
 
 
23
 
#include <drizzled/internal/my_sys.h>
24
 
#include <drizzled/internal/thread_var.h>
25
 
#include <drizzled/internal/m_string.h>
26
 
 
27
 
#include <cstdio>
 
21
#include "mysys_priv.h"
 
22
#include <m_string.h>
28
23
#include <signal.h>
29
24
 
30
 
#if TIME_WITH_SYS_TIME
31
 
# include <sys/time.h>
32
 
# include <time.h>
 
25
uint thd_lib_detected= 0;
 
26
 
 
27
#ifdef USE_TLS
 
28
pthread_key(struct st_my_thread_var*, THR_KEY_mysys);
33
29
#else
34
 
# if HAVE_SYS_TIME_H
35
 
#  include <sys/time.h>
36
 
# else
37
 
#  include <time.h>
38
 
# endif
39
 
#endif
40
 
 
41
 
#include <boost/thread/thread.hpp>
42
 
#include <boost/thread/mutex.hpp>
43
 
#include <boost/thread/tss.hpp>
44
 
 
45
 
namespace drizzled
46
 
{
47
 
namespace internal
48
 
{
49
 
 
50
 
boost::thread_specific_ptr<st_my_thread_var> THR_KEY_mysys;
51
 
boost::mutex THR_LOCK_threads;
 
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);
52
70
 
53
71
/*
54
72
  initialize thread environment
63
81
 
64
82
bool my_thread_global_init(void)
65
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
66
159
  if (my_thread_init())
67
160
  {
68
161
    my_thread_global_end();                     /* Clean up */
74
167
 
75
168
void my_thread_global_end(void)
76
169
{
 
170
  struct timespec abstime;
 
171
  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
77
225
}
78
226
 
79
 
static uint64_t thread_id= 0;
 
227
static my_thread_id thread_id= 0;
80
228
 
81
229
/*
82
 
  Allocate thread specific memory for the thread, used by mysys
 
230
  Allocate thread specific memory for the thread, used by mysys and dbug
83
231
 
84
232
  SYNOPSIS
85
233
    my_thread_init()
86
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
 
87
244
  RETURN
88
245
    0  ok
89
246
    1  Fatal error; mysys/dbug functions can't be used
91
248
 
92
249
bool my_thread_init(void)
93
250
{
94
 
  // We should mever see my_thread_init()  called twice
95
 
  if (THR_KEY_mysys.get())
96
 
    return 0;
97
 
 
98
 
  st_my_thread_var *tmp= new st_my_thread_var;
99
 
  if (tmp == NULL)
100
 
  {
101
 
    return true;
102
 
  }
103
 
  THR_KEY_mysys.reset(tmp);
104
 
 
105
 
  boost::mutex::scoped_lock scopedLock(THR_LOCK_threads);
 
251
  struct st_my_thread_var *tmp;
 
252
  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
 
 
259
  if (pthread_getspecific(THR_KEY_mysys))
 
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);
106
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
107
286
 
108
 
  return false;
 
287
end:
 
288
  return error;
109
289
}
110
290
 
111
291
 
117
297
 
118
298
  NOTE
119
299
    This may be called multiple times for a thread.
120
 
    This happens for example when one calls 'server_init()'
121
 
    server_end() and then ends with a end().
 
300
    This happens for example when one calls 'mysql_server_init()'
 
301
    mysql_server_end() and then ends with a mysql_end().
122
302
*/
123
303
 
124
304
void my_thread_end(void)
125
305
{
 
306
  struct st_my_thread_var *tmp;
 
307
  tmp= (struct st_my_thread_var *)pthread_getspecific(THR_KEY_mysys);
 
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
126
351
}
127
352
 
128
353
struct st_my_thread_var *_my_thread_var(void)
129
354
{
130
 
  return THR_KEY_mysys.get();
131
 
}
132
 
 
133
 
} /* namespace internal */
134
 
} /* namespace drizzled */
 
355
  struct st_my_thread_var *tmp= (struct st_my_thread_var*)pthread_getspecific(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
}