~ubuntu-branches/ubuntu/quantal/mysql-workbench/quantal

« back to all changes in this revision

Viewing changes to ext/cppconn/thread/my_thr_init.c

  • Committer: Package Import Robot
  • Author(s): Dmitry Smirnov
  • Date: 2012-03-01 21:57:30 UTC
  • Revision ID: package-import@ubuntu.com-20120301215730-o7y8av8y38n162ro
Tags: upstream-5.2.38+dfsg
ImportĀ upstreamĀ versionĀ 5.2.38+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
 
3
 
 
4
The MySQL Connector/C++ is licensed under the terms of the GPLv2
 
5
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
 
6
MySQL Connectors. There are special exceptions to the terms and
 
7
conditions of the GPLv2 as it is applied to this software, see the
 
8
FLOSS License Exception
 
9
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
 
10
 
 
11
This program is free software; you can redistribute it and/or modify
 
12
it under the terms of the GNU General Public License as published
 
13
by the Free Software Foundation; version 2 of the License.
 
14
 
 
15
This program is distributed in the hope that it will be useful, but
 
16
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 
17
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 
18
for more details.
 
19
 
 
20
You should have received a copy of the GNU General Public License along
 
21
with this program; if not, write to the Free Software Foundation, Inc.,
 
22
51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
 
23
*/
 
24
 
 
25
 
 
26
 
 
27
/**
 
28
  @file
 
29
  Functions for initialization and allocation of all mysys & debug
 
30
  thread variables.
 
31
*/
 
32
 
 
33
#ifdef THREAD
 
34
#include "my_pthread.h"
 
35
extern pthread_mutex_t THR_LOCK_malloc, THR_LOCK_open, THR_LOCK_keycache;
 
36
extern pthread_mutex_t THR_LOCK_lock, THR_LOCK_isam, THR_LOCK_net;
 
37
extern pthread_mutex_t THR_LOCK_charset, THR_LOCK_time;
 
38
#else
 
39
#include "my_no_pthread.h"
 
40
#endif
 
41
 
 
42
//#include "mysys_priv.h"
 
43
//#include <m_string.h>
 
44
#include <signal.h>
 
45
 
 
46
#ifdef THREAD
 
47
pthread_key(struct st_my_thread_var*, THR_KEY_mysys);
 
48
pthread_mutex_t THR_LOCK_malloc,THR_LOCK_open,
 
49
                THR_LOCK_lock,THR_LOCK_isam,THR_LOCK_heap, THR_LOCK_net,
 
50
                THR_LOCK_charset, THR_LOCK_threads, THR_LOCK_time;
 
51
/** For insert/delete in the list of MyISAM open tables */
 
52
pthread_mutex_t THR_LOCK_myisam;
 
53
/** For writing to the MyISAM logs */
 
54
pthread_mutex_t THR_LOCK_myisam_log;
 
55
pthread_cond_t  THR_COND_threads;
 
56
uint            THR_thread_count= 0;
 
57
uint            my_thread_end_wait_time= 5;
 
58
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
 
59
pthread_mutex_t LOCK_localtime_r;
 
60
#endif
 
61
#ifndef HAVE_GETHOSTBYNAME_R
 
62
pthread_mutex_t LOCK_gethostbyname_r;
 
63
#endif
 
64
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
 
65
pthread_mutexattr_t my_fast_mutexattr;
 
66
#endif
 
67
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
 
68
pthread_mutexattr_t my_errorcheck_mutexattr;
 
69
#endif
 
70
#ifdef _MSC_VER
 
71
static void install_sigabrt_handler();
 
72
#endif
 
73
#ifdef TARGET_OS_LINUX
 
74
 
 
75
/*
 
76
  Dummy thread spawned in my_thread_global_init() below to avoid
 
77
  race conditions in NPTL pthread_exit code.
 
78
*/
 
79
 
 
80
static pthread_handler_t
 
81
nptl_pthread_exit_hack_handler(void *arg __attribute((unused)))
 
82
{
 
83
  /* Do nothing! */
 
84
  pthread_exit(0);
 
85
  return 0;
 
86
}
 
87
 
 
88
#endif /* TARGET_OS_LINUX */
 
89
 
 
90
 
 
91
 
 
92
/**
 
93
  Initialize thread attributes.
 
94
*/
 
95
 
 
96
void my_threadattr_global_init(void)
 
97
{
 
98
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
 
99
  /*
 
100
    Set mutex type to "fast" a.k.a "adaptive"
 
101
 
 
102
    In this case the thread may steal the mutex from some other thread
 
103
    that is waiting for the same mutex.  This will save us some
 
104
    context switches but may cause a thread to 'starve forever' while
 
105
    waiting for the mutex (not likely if the code within the mutex is
 
106
    short).
 
107
  */
 
108
  pthread_mutexattr_init(&my_fast_mutexattr);  /* ?= MY_MUTEX_INIT_FAST */
 
109
  pthread_mutexattr_settype(&my_fast_mutexattr,
 
110
                            PTHREAD_MUTEX_ADAPTIVE_NP);
 
111
#endif
 
112
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
 
113
  /*
 
114
    Set mutex type to "errorcheck"
 
115
  */
 
116
  pthread_mutexattr_init(&my_errorcheck_mutexattr);
 
117
  pthread_mutexattr_settype(&my_errorcheck_mutexattr,
 
118
                            PTHREAD_MUTEX_ERRORCHECK);
 
119
#endif
 
120
}
 
121
 
 
122
 
 
123
static uint get_thread_lib(void);
 
124
 
 
125
/*
 
126
  initialize thread environment
 
127
 
 
128
  SYNOPSIS
 
129
    my_thread_global_init()
 
130
 
 
131
  RETURN
 
132
    0  ok
 
133
    1  error (Couldn't create THR_KEY_mysys)
 
134
*/
 
135
 
 
136
my_bool my_thread_global_init(void)
 
137
{
 
138
  int pth_ret;
 
139
  thd_lib_detected= get_thread_lib();
 
140
 
 
141
  if ((pth_ret= pthread_key_create(&THR_KEY_mysys, NULL)) != 0)
 
142
  {
 
143
    fprintf(stderr,"Can't initialize threads: error %d\n", pth_ret);
 
144
    return 1;
 
145
  }
 
146
 
 
147
#ifdef TARGET_OS_LINUX
 
148
  /*
 
149
    BUG#24507: Race conditions inside current NPTL pthread_exit()
 
150
    implementation.
 
151
 
 
152
    To avoid a possible segmentation fault during concurrent
 
153
    executions of pthread_exit(), a dummy thread is spawned which
 
154
    initializes internal variables of pthread lib. See bug description
 
155
    for a full explanation.
 
156
 
 
157
    TODO: Remove this code when fixed versions of glibc6 are in common
 
158
    use.
 
159
  */
 
160
  if (thd_lib_detected == THD_LIB_NPTL)
 
161
  {
 
162
    pthread_t       dummy_thread;
 
163
    pthread_attr_t  dummy_thread_attr;
 
164
 
 
165
    pthread_attr_init(&dummy_thread_attr);
 
166
    pthread_attr_setdetachstate(&dummy_thread_attr, PTHREAD_CREATE_DETACHED);
 
167
 
 
168
    pthread_create(&dummy_thread,&dummy_thread_attr,
 
169
                   nptl_pthread_exit_hack_handler, NULL);
 
170
  }
 
171
#endif /* TARGET_OS_LINUX */
 
172
 
 
173
  /* Mutex used by my_thread_init() and after my_thread_destroy_mutex() */
 
174
  my_pthread_mutex_init(&THR_LOCK_threads, MY_MUTEX_INIT_FAST,
 
175
                        "THR_LOCK_threads", MYF_NO_DEADLOCK_DETECTION);
 
176
  my_pthread_mutex_init(&THR_LOCK_malloc, MY_MUTEX_INIT_FAST,
 
177
                        "THR_LOCK_malloc", MYF_NO_DEADLOCK_DETECTION);
 
178
 
 
179
  if (my_thread_init())
 
180
    return 1;
 
181
 
 
182
 
 
183
  /* Mutex uses by mysys */
 
184
  pthread_mutex_init(&THR_LOCK_open,MY_MUTEX_INIT_FAST);
 
185
  pthread_mutex_init(&THR_LOCK_lock,MY_MUTEX_INIT_FAST);
 
186
  pthread_mutex_init(&THR_LOCK_isam,MY_MUTEX_INIT_SLOW);
 
187
  pthread_mutex_init(&THR_LOCK_myisam,MY_MUTEX_INIT_SLOW);
 
188
  pthread_mutex_init(&THR_LOCK_myisam_log,MY_MUTEX_INIT_SLOW);
 
189
  pthread_mutex_init(&THR_LOCK_heap,MY_MUTEX_INIT_FAST);
 
190
  pthread_mutex_init(&THR_LOCK_net,MY_MUTEX_INIT_FAST);
 
191
  pthread_mutex_init(&THR_LOCK_charset,MY_MUTEX_INIT_FAST);
 
192
  pthread_mutex_init(&THR_LOCK_time,MY_MUTEX_INIT_FAST);
 
193
  pthread_cond_init(&THR_COND_threads, NULL);
 
194
 
 
195
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
 
196
  pthread_mutex_init(&LOCK_localtime_r,MY_MUTEX_INIT_SLOW);
 
197
#endif
 
198
#ifndef HAVE_GETHOSTBYNAME_R
 
199
  pthread_mutex_init(&LOCK_gethostbyname_r,MY_MUTEX_INIT_SLOW);
 
200
#endif
 
201
  return 0;
 
202
}
 
203
 
 
204
 
 
205
/**
 
206
   Wait for all threads in system to die
 
207
   @fn    my_wait_for_other_threads_to_die()
 
208
   @param number_of_threads  Wait until this number of threads
 
209
 
 
210
   @retval  0  Less or equal to number_of_threads left
 
211
   @retval  1  Wait failed
 
212
*/
 
213
 
 
214
my_bool my_wait_for_other_threads_to_die(uint number_of_threads)
 
215
{
 
216
  struct timespec abstime;
 
217
  my_bool all_threads_killed= 1;
 
218
 
 
219
  set_timespec(abstime, my_thread_end_wait_time);
 
220
  pthread_mutex_lock(&THR_LOCK_threads);
 
221
  while (THR_thread_count > number_of_threads)
 
222
  {
 
223
    int error= pthread_cond_timedwait(&THR_COND_threads, &THR_LOCK_threads,
 
224
                                      &abstime);
 
225
    if (error == ETIMEDOUT || error == ETIME)
 
226
    {
 
227
      all_threads_killed= 0;
 
228
      break;
 
229
    }
 
230
  }
 
231
  pthread_mutex_unlock(&THR_LOCK_threads);
 
232
  return all_threads_killed;
 
233
}
 
234
 
 
235
 
 
236
/**
 
237
   End the mysys thread system. Called when ending the last thread
 
238
*/
 
239
 
 
240
 
 
241
void my_thread_global_end(void)
 
242
{
 
243
  my_bool all_threads_killed;
 
244
 
 
245
  if (!(all_threads_killed= my_wait_for_other_threads_to_die(0)))
 
246
  {
 
247
#ifdef HAVE_PTHREAD_KILL
 
248
    /*
 
249
      We shouldn't give an error here, because if we don't have
 
250
      pthread_kill(), programs like mysqld can't ensure that all threads
 
251
      are killed when we enter here.
 
252
    */
 
253
    if (THR_thread_count)
 
254
      fprintf(stderr,
 
255
              "Error in my_thread_global_end(): %d threads didn't exit\n",
 
256
              THR_thread_count);
 
257
#endif
 
258
  }
 
259
 
 
260
  pthread_key_delete(THR_KEY_mysys);
 
261
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
 
262
  pthread_mutexattr_destroy(&my_fast_mutexattr);
 
263
#endif
 
264
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
 
265
  pthread_mutexattr_destroy(&my_errorcheck_mutexattr);
 
266
#endif
 
267
  if (all_threads_killed)
 
268
  {
 
269
    pthread_mutex_destroy(&THR_LOCK_threads);
 
270
    pthread_cond_destroy(&THR_COND_threads);
 
271
    pthread_mutex_destroy(&THR_LOCK_malloc);
 
272
  }
 
273
}
 
274
 
 
275
/* Free all mutex used by mysys */
 
276
 
 
277
void my_thread_destroy_mutex(void)
 
278
{
 
279
  struct st_my_thread_var *tmp;
 
280
  tmp= my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
 
281
  if (tmp)
 
282
  {
 
283
    safe_mutex_free_deadlock_data(&tmp->mutex);
 
284
  }
 
285
 
 
286
  pthread_mutex_destroy(&THR_LOCK_open);
 
287
  pthread_mutex_destroy(&THR_LOCK_lock);
 
288
  pthread_mutex_destroy(&THR_LOCK_isam);
 
289
  pthread_mutex_destroy(&THR_LOCK_myisam);
 
290
  pthread_mutex_destroy(&THR_LOCK_myisam_log);
 
291
  pthread_mutex_destroy(&THR_LOCK_heap);
 
292
  pthread_mutex_destroy(&THR_LOCK_net);
 
293
  pthread_mutex_destroy(&THR_LOCK_time);
 
294
  pthread_mutex_destroy(&THR_LOCK_charset);
 
295
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
 
296
  pthread_mutex_destroy(&LOCK_localtime_r);
 
297
#endif
 
298
#ifndef HAVE_GETHOSTBYNAME_R
 
299
  pthread_mutex_destroy(&LOCK_gethostbyname_r);
 
300
#endif
 
301
}
 
302
 
 
303
static my_thread_id thread_id= 0;
 
304
 
 
305
/*
 
306
  Allocate thread specific memory for the thread, used by mysys and dbug
 
307
 
 
308
  SYNOPSIS
 
309
    my_thread_init()
 
310
 
 
311
  NOTES
 
312
    We can't use mutex_locks here if we are using windows as
 
313
    we may have compiled the program with SAFE_MUTEX, in which
 
314
    case the checking of mutex_locks will not work until
 
315
    the pthread_self thread specific variable is initialized.
 
316
 
 
317
   This function may called multiple times for a thread, for example
 
318
   if one uses my_init() followed by mysql_server_init().
 
319
 
 
320
  RETURN
 
321
    0  ok
 
322
    1  Fatal error; mysys/dbug functions can't be used
 
323
*/
 
324
 
 
325
my_bool my_thread_init(void)
 
326
{
 
327
  struct st_my_thread_var *tmp;
 
328
  my_bool error=0;
 
329
 
 
330
#ifdef EXTRA_DEBUG_THREADS
 
331
  fprintf(stderr,"my_thread_init(): thread_id: 0x%lx\n",
 
332
          (ulong) pthread_self());
 
333
#endif
 
334
 
 
335
  if (my_pthread_getspecific(struct st_my_thread_var *,THR_KEY_mysys))
 
336
  {
 
337
#ifdef EXTRA_DEBUG_THREADS
 
338
    fprintf(stderr,"my_thread_init() called more than once in thread 0x%lx\n",
 
339
            (long) pthread_self());
 
340
#endif
 
341
    goto end;
 
342
  }
 
343
 
 
344
#ifdef _MSC_VER
 
345
  install_sigabrt_handler();
 
346
#endif
 
347
 
 
348
  if (!(tmp= (struct st_my_thread_var *) calloc(1, sizeof(*tmp))))
 
349
  {
 
350
    error= 1;
 
351
    goto end;
 
352
  }
 
353
  pthread_setspecific(THR_KEY_mysys,tmp);
 
354
  tmp->pthread_self= pthread_self();
 
355
  my_pthread_mutex_init(&tmp->mutex, MY_MUTEX_INIT_FAST, "mysys_var->mutex",
 
356
                        0);
 
357
  pthread_cond_init(&tmp->suspend, NULL);
 
358
 
 
359
  tmp->stack_ends_here= (char*)&tmp +
 
360
                         STACK_DIRECTION * (long)my_thread_stack_size;
 
361
 
 
362
  pthread_mutex_lock(&THR_LOCK_threads);
 
363
  tmp->id= ++thread_id;
 
364
  ++THR_thread_count;
 
365
  pthread_mutex_unlock(&THR_LOCK_threads);
 
366
  tmp->init= 1;
 
367
#ifndef DBUG_OFF
 
368
  /* Generate unique name for thread */
 
369
  (void) my_thread_name();
 
370
#endif
 
371
 
 
372
end:
 
373
  return error;
 
374
}
 
375
 
 
376
 
 
377
/*
 
378
  Deallocate memory used by the thread for book-keeping
 
379
 
 
380
  SYNOPSIS
 
381
    my_thread_end()
 
382
 
 
383
  NOTE
 
384
    This may be called multiple times for a thread.
 
385
    This happens for example when one calls 'mysql_server_init()'
 
386
    mysql_server_end() and then ends with a mysql_end().
 
387
*/
 
388
 
 
389
void my_thread_end(void)
 
390
{
 
391
  struct st_my_thread_var *tmp;
 
392
  tmp= my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
 
393
 
 
394
#ifdef EXTRA_DEBUG_THREADS
 
395
  fprintf(stderr,"my_thread_end(): tmp: 0x%lx  pthread_self: 0x%lx  thread_id: %ld\n",
 
396
          (long) tmp, (long) pthread_self(), tmp ? (long) tmp->id : 0L);
 
397
#endif
 
398
  if (tmp && tmp->init)
 
399
  {
 
400
 
 
401
#if !defined(__bsdi__) && !defined(__OpenBSD__)
 
402
 /* bsdi and openbsd 3.5 dumps core here */
 
403
    pthread_cond_destroy(&tmp->suspend);
 
404
#endif
 
405
    pthread_mutex_destroy(&tmp->mutex);
 
406
 
 
407
#if !defined(DBUG_OFF)
 
408
    /* tmp->dbug is allocated inside DBUG library */
 
409
    if (tmp->dbug)
 
410
    {
 
411
      /*
 
412
        Frees memory allocated in SET DEBUG=...; does nothing if there were no
 
413
        SET DEBUG in a thread.
 
414
      */
 
415
      DBUG_POP();
 
416
      free(tmp->dbug);
 
417
      tmp->dbug=0;
 
418
    }
 
419
#endif
 
420
#ifndef DBUG_OFF
 
421
    /* To find bugs when accessing unallocated data */
 
422
    bfill(tmp, sizeof(tmp), 0x8F);
 
423
#endif
 
424
    free(tmp);
 
425
    pthread_setspecific(THR_KEY_mysys,0);
 
426
    /*
 
427
      Decrement counter for number of running threads. We are using this
 
428
      in my_thread_global_end() to wait until all threads have called
 
429
      my_thread_end and thus freed all memory they have allocated in
 
430
      my_thread_init() and DBUG_xxxx
 
431
    */
 
432
    pthread_mutex_lock(&THR_LOCK_threads);
 
433
    DBUG_ASSERT(THR_thread_count != 0);
 
434
    if (--THR_thread_count == 0)
 
435
      pthread_cond_signal(&THR_COND_threads);
 
436
   pthread_mutex_unlock(&THR_LOCK_threads);
 
437
  }
 
438
  else
 
439
  {
 
440
    pthread_setspecific(THR_KEY_mysys,0);
 
441
  }
 
442
}
 
443
 
 
444
struct st_my_thread_var *_my_thread_var(void)
 
445
{
 
446
  return  my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
 
447
}
 
448
 
 
449
#ifndef DBUG_OFF
 
450
/* Return pointer to DBUG for holding current state */
 
451
 
 
452
extern void **my_thread_var_dbug()
 
453
{
 
454
  struct st_my_thread_var *tmp=
 
455
    my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
 
456
  return tmp && tmp->init ? &tmp->dbug : 0;
 
457
}
 
458
#endif
 
459
 
 
460
/* Return pointer to mutex_in_use */
 
461
 
 
462
safe_mutex_t **my_thread_var_mutex_in_use()
 
463
{
 
464
  struct st_my_thread_var *tmp=
 
465
    my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
 
466
  return tmp ? &tmp->mutex_in_use : 0;
 
467
}
 
468
 
 
469
/****************************************************************************
 
470
  Get name of current thread.
 
471
****************************************************************************/
 
472
 
 
473
my_thread_id my_thread_dbug_id()
 
474
{
 
475
  return my_thread_var->id;
 
476
}
 
477
 
 
478
#ifdef DBUG_OFF
 
479
const char *my_thread_name(void)
 
480
{
 
481
  return "no_name";
 
482
}
 
483
 
 
484
#else
 
485
 
 
486
const char *my_thread_name(void)
 
487
{
 
488
  char name_buff[100];
 
489
  struct st_my_thread_var *tmp=my_thread_var;
 
490
  if (!tmp->name[0])
 
491
  {
 
492
    my_thread_id id= my_thread_dbug_id();
 
493
    sprintf(name_buff,"T@%lu", (ulong) id);
 
494
    strmake(tmp->name,name_buff,THREAD_NAME_SIZE);
 
495
  }
 
496
  return tmp->name;
 
497
}
 
498
#endif /* DBUG_OFF */
 
499
 
 
500
 
 
501
static uint get_thread_lib(void)
 
502
{
 
503
#ifdef _CS_GNU_LIBPTHREAD_VERSION
 
504
  char buff[64];
 
505
 
 
506
  confstr(_CS_GNU_LIBPTHREAD_VERSION, buff, sizeof(buff));
 
507
 
 
508
  if (!strncasecmp(buff, "NPTL", 4))
 
509
    return THD_LIB_NPTL;
 
510
  if (!strncasecmp(buff, "linuxthreads", 12))
 
511
    return THD_LIB_LT;
 
512
#endif
 
513
  return THD_LIB_OTHER;
 
514
}
 
515
 
 
516
#ifdef _WIN32
 
517
/*
 
518
  In Visual Studio 2005 and later, default SIGABRT handler will overwrite
 
519
  any unhandled exception filter set by the application  and will try to
 
520
  call JIT debugger. This is not what we want, this we calling __debugbreak
 
521
  to stop in debugger, if process is being debugged or to generate
 
522
  EXCEPTION_BREAKPOINT and then handle_segfault will do its magic.
 
523
*/
 
524
 
 
525
#if (_MSC_VER >= 1400)
 
526
static void my_sigabrt_handler(int sig)
 
527
{
 
528
  __debugbreak();
 
529
}
 
530
#endif /*_MSC_VER >=1400 */
 
531
 
 
532
static void install_sigabrt_handler(void)
 
533
{
 
534
#if (_MSC_VER >=1400)
 
535
  /*abort() should not override our exception filter*/
 
536
  _set_abort_behavior(0,_CALL_REPORTFAULT);
 
537
  signal(SIGABRT,my_sigabrt_handler);
 
538
#endif /* _MSC_VER >=1400 */
 
539
}
 
540
#endif
 
541
 
 
542
#endif /* THREAD */