~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/my_thr_init.c

  • Committer: Lee
  • Date: 2008-10-30 22:02:01 UTC
  • mto: (572.1.2 devel)
  • mto: This revision was merged to the branch mainline in revision 573.
  • Revision ID: lbieber@lbieber-desktop-20081030220201-elb6qprbzpn7c5a4
add my name to the AUTHORS file

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 <mystrings/m_string.h>
28
23
#include <signal.h>
29
24
 
30
25
#if TIME_WITH_SYS_TIME
36
31
# else
37
32
#  include <time.h>
38
33
# 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;
 
34
#endif  
 
35
 
 
36
uint32_t thd_lib_detected= 0;
 
37
 
 
38
#ifdef USE_TLS
 
39
pthread_key_t THR_KEY_mysys;
 
40
#else
 
41
pthread_key_t THR_KEY_mysys;
 
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;
 
47
uint32_t            THR_thread_count= 0;
 
48
uint32_t                my_thread_end_wait_time= 5;
 
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
 
 
80
static uint32_t get_thread_lib(void);
52
81
 
53
82
/*
54
83
  initialize thread environment
63
92
 
64
93
bool my_thread_global_init(void)
65
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
66
170
  if (my_thread_init())
67
171
  {
68
172
    my_thread_global_end();                     /* Clean up */
74
178
 
75
179
void my_thread_global_end(void)
76
180
{
 
181
  struct timespec abstime;
 
182
  bool all_threads_killed= 1;
 
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
77
236
}
78
237
 
79
 
static uint64_t thread_id= 0;
 
238
static my_thread_id thread_id= 0;
80
239
 
81
240
/*
82
241
  Allocate thread specific memory for the thread, used by mysys
84
243
  SYNOPSIS
85
244
    my_thread_init()
86
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
 
87
252
  RETURN
88
253
    0  ok
89
254
    1  Fatal error; mysys/dbug functions can't be used
91
256
 
92
257
bool my_thread_init(void)
93
258
{
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);
 
259
  struct st_my_thread_var *tmp;
 
260
  bool error=0;
 
261
 
 
262
#ifdef EXTRA_DEBUG_THREADS
 
263
  fprintf(stderr,"my_thread_init(): thread_id: 0x%lx\n",
 
264
          (uint32_t) pthread_self());
 
265
#endif  
 
266
 
 
267
  if (pthread_getspecific(THR_KEY_mysys))
 
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);
106
287
  tmp->id= ++thread_id;
 
288
  ++THR_thread_count;
 
289
  pthread_mutex_unlock(&THR_LOCK_threads);
107
290
 
108
 
  return false;
 
291
end:
 
292
  return error;
109
293
}
110
294
 
111
295
 
117
301
 
118
302
  NOTE
119
303
    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().
 
304
    This happens for example when one calls 'mysql_server_init()'
 
305
    mysql_server_end() and then ends with a mysql_end().
122
306
*/
123
307
 
124
308
void my_thread_end(void)
125
309
{
 
310
  struct st_my_thread_var *tmp;
 
311
  tmp= (struct st_my_thread_var *)pthread_getspecific(THR_KEY_mysys);
 
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
 
334
      my_thread_init() 
 
335
    */
 
336
    pthread_mutex_lock(&THR_LOCK_threads);
 
337
    assert(THR_thread_count != 0);
 
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
126
346
}
127
347
 
128
348
struct st_my_thread_var *_my_thread_var(void)
129
349
{
130
 
  return THR_KEY_mysys.get();
131
 
}
132
 
 
133
 
} /* namespace internal */
134
 
} /* namespace drizzled */
 
350
  struct st_my_thread_var *tmp= (struct st_my_thread_var*)pthread_getspecific(THR_KEY_mysys);
 
351
#if defined(USE_TLS)
 
352
  /* This can only happen in a .DLL */
 
353
  if (!tmp)
 
354
  {
 
355
    my_thread_init();
 
356
    tmp=(struct st_my_thread_var*)pthread_getspecific(THR_KEY_mysys);
 
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
 
 
372
static uint32_t get_thread_lib(void)
 
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
}