~mysql/mysql-server/mysql-6.0

« back to all changes in this revision

Viewing changes to mysys/my_pthread.c

  • Committer: bk at mysql
  • Date: 2000-07-31 19:29:14 UTC
  • Revision ID: sp1r-bk@work.mysql.com-20000731192914-08846
Import changeset

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
 
2
   
 
3
   This library is free software; you can redistribute it and/or
 
4
   modify it under the terms of the GNU Library General Public
 
5
   License as published by the Free Software Foundation; either
 
6
   version 2 of the License, or (at your option) any later version.
 
7
   
 
8
   This library is distributed in the hope that it will be useful,
 
9
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
11
   Library General Public License for more details.
 
12
   
 
13
   You should have received a copy of the GNU Library General Public
 
14
   License along with this library; if not, write to the Free
 
15
   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 
16
   MA 02111-1307, USA */
 
17
 
 
18
/* Functions to get threads more portable */
 
19
 
 
20
#include "mysys_priv.h"
 
21
#ifdef THREAD
 
22
#include <signal.h>
 
23
#include <m_string.h>
 
24
#include <thr_alarm.h>
 
25
#include <assert.h>
 
26
#if !defined(MSDOS) && !defined(__WIN__)
 
27
#include <netdb.h>
 
28
#endif
 
29
 
 
30
#if (defined(__BSD__) || defined(_BSDI_VERSION)) && !defined(HAVE_mit_thread)
 
31
#define SCHED_POLICY SCHED_RR
 
32
#else
 
33
#define SCHED_POLICY SCHED_OTHER
 
34
#endif
 
35
 
 
36
#ifndef my_pthread_setprio
 
37
void my_pthread_setprio(pthread_t thread_id,int prior)
 
38
{
 
39
#ifdef HAVE_PTHREAD_SETSCHEDPARAM
 
40
  struct sched_param tmp_sched_param;
 
41
  bzero((char*) &tmp_sched_param,sizeof(tmp_sched_param));
 
42
  tmp_sched_param.sched_priority=prior;
 
43
  VOID(pthread_setschedparam(thread_id,SCHED_POLICY,&tmp_sched_param));
 
44
#endif
 
45
}
 
46
#endif
 
47
 
 
48
#ifndef my_pthread_getprio
 
49
int my_pthread_getprio(pthread_t thread_id)
 
50
{
 
51
#ifdef HAVE_PTHREAD_SETSCHEDPARAM
 
52
  struct sched_param tmp_sched_param;
 
53
  int policy;
 
54
  if (!pthread_getschedparam(thread_id,&policy,&tmp_sched_param))
 
55
  {
 
56
    DBUG_PRINT("thread",("policy: %d  priority: %d",
 
57
                         policy,tmp_sched_param.sched_priority));
 
58
    return tmp_sched_param.sched_priority;
 
59
  }
 
60
#endif
 
61
  return -1;
 
62
}
 
63
#endif
 
64
 
 
65
#ifndef my_pthread_attr_setprio
 
66
void my_pthread_attr_setprio(pthread_attr_t *attr, int priority)
 
67
{
 
68
#ifdef HAVE_PTHREAD_SETSCHEDPARAM
 
69
  struct sched_param tmp_sched_param;
 
70
  bzero((char*) &tmp_sched_param,sizeof(tmp_sched_param));
 
71
  tmp_sched_param.sched_priority=priority;
 
72
  VOID(pthread_attr_setschedparam(attr,&tmp_sched_param));
 
73
#endif
 
74
}
 
75
#endif
 
76
 
 
77
 
 
78
/* To allow use of pthread_getspecific with two arguments */
 
79
 
 
80
#ifdef HAVE_NONPOSIX_PTHREAD_GETSPECIFIC
 
81
#undef pthread_getspecific
 
82
#ifdef HAVE_UNIXWARE7_THREADS
 
83
#define pthread_getspecific thr_getspecific
 
84
#endif
 
85
 
 
86
void *my_pthread_getspecific_imp(pthread_key_t key)
 
87
{
 
88
  void *value;
 
89
  if (pthread_getspecific(key,(void *) &value))
 
90
    return 0;
 
91
  return value;
 
92
}
 
93
#endif
 
94
 
 
95
 
 
96
/* Some functions for RTS threads, AIX, Siemens Unix and UnixWare 7
 
97
   (and DEC OSF/1 3.2 too) */
 
98
 
 
99
int my_pthread_create_detached=1;
 
100
 
 
101
#if defined(HAVE_NONPOSIX_SIGWAIT) || defined(HAVE_DEC_3_2_THREADS)
 
102
 
 
103
int my_sigwait(sigset_t *set,int *sig)
 
104
{
 
105
  int signal=sigwait(set);
 
106
  if (signal < 0)
 
107
    return errno;
 
108
  *sig=signal;
 
109
  return 0;
 
110
}
 
111
#endif
 
112
 
 
113
/* localtime_r for SCO 3.2V4.2 */
 
114
 
 
115
#ifndef HAVE_LOCALTIME_R
 
116
 
 
117
extern pthread_mutex_t LOCK_localtime_r;
 
118
 
 
119
struct tm *localtime_r(const time_t *clock, struct tm *res)
 
120
{
 
121
  struct tm *tmp;
 
122
  pthread_mutex_lock(&LOCK_localtime_r);
 
123
  tmp=localtime(clock);
 
124
  *res= *tmp;
 
125
  pthread_mutex_unlock(&LOCK_localtime_r);
 
126
  return res;
 
127
}
 
128
#endif
 
129
 
 
130
 
 
131
/****************************************************************************
 
132
** Replacement of sigwait if the system doesn't have one (like BSDI 3.0)
 
133
**
 
134
** Note:
 
135
** This version of sigwait() is assumed to called in a loop so the signalmask
 
136
** is permanently modified to reflect the signal set. This is done to get
 
137
** a much faster implementation.
 
138
**
 
139
** This implementation isn't thread safe: It assumes that only one
 
140
** thread is using sigwait.
 
141
**
 
142
** If one later supplies a different signal mask, all old signals that
 
143
** was used before are unblocked and set to SIGDFL.
 
144
**
 
145
** Author: Gary Wisniewski <garyw@spidereye.com.au>, much modified by Monty
 
146
****************************************************************************/
 
147
 
 
148
#if !defined(HAVE_SIGWAIT) && !defined(HAVE_mit_thread) && !defined(sigwait) && !defined(__WIN__) && !defined(HAVE_rts_threads) && !defined(HAVE_NONPOSIX_SIGWAIT) && !defined(HAVE_DEC_3_2_THREADS)
 
149
 
 
150
#if !defined(DONT_USE_SIGSUSPEND)
 
151
 
 
152
static sigset_t sigwait_set,rev_sigwait_set,px_recd;
 
153
 
 
154
void px_handle_sig(int sig)
 
155
{
 
156
  sigaddset(&px_recd, sig);
 
157
}
 
158
 
 
159
 
 
160
void sigwait_setup(sigset_t *set)
 
161
{
 
162
  int i;
 
163
  struct sigaction sact,sact1;
 
164
  sigset_t unblock_mask;
 
165
 
 
166
  sact.sa_flags = 0;
 
167
  sact.sa_handler = px_handle_sig;
 
168
  memcpy_fixed(&sact.sa_mask,set,sizeof(*set)); /* handler isn't thread_safe */
 
169
  sigemptyset(&unblock_mask);
 
170
  pthread_sigmask(SIG_UNBLOCK,(sigset_t*) 0,&rev_sigwait_set);
 
171
 
 
172
  for (i = 1; i <= sizeof(sigwait_set)*8; i++)
 
173
  {
 
174
    if (sigismember(set,i))
 
175
    {
 
176
      sigdelset(&rev_sigwait_set,i);
 
177
      if (!sigismember(&sigwait_set,i))
 
178
        sigaction(i, &sact, (struct sigaction*) 0);
 
179
    }
 
180
    else
 
181
    {
 
182
      sigdelset(&px_recd,i);                    /* Don't handle this */
 
183
      if (sigismember(&sigwait_set,i))
 
184
      {                                         /* Remove the old handler */
 
185
        sigaddset(&unblock_mask,i);
 
186
        sigdelset(&rev_sigwait_set,i);
 
187
        sact1.sa_flags = 0;
 
188
        sact1.sa_handler = SIG_DFL;
 
189
        sigemptyset(&sact1.sa_mask);
 
190
        sigaction(i, &sact1, 0);
 
191
      }
 
192
    }
 
193
  }
 
194
  memcpy_fixed(&sigwait_set,set,sizeof(*set));
 
195
  pthread_sigmask(SIG_BLOCK,(sigset_t*) set,(sigset_t*) 0);
 
196
  pthread_sigmask(SIG_UNBLOCK,&unblock_mask,(sigset_t*) 0);
 
197
}
 
198
 
 
199
 
 
200
int sigwait(sigset_t *setp, int *sigp)
 
201
{
 
202
  if (memcmp(setp,&sigwait_set,sizeof(sigwait_set)))
 
203
    sigwait_setup(setp);                        /* Init or change of set */
 
204
 
 
205
  for (;;)
 
206
  {
 
207
    /*
 
208
      This is a fast, not 100% portable implementation to find the signal.
 
209
      Because the handler is blocked there should be at most 1 bit set, but
 
210
      the specification on this is somewhat shady so we use a set instead a
 
211
      single variable.
 
212
      */
 
213
 
 
214
    ulong *ptr= (ulong*) &px_recd;
 
215
    ulong *end=ptr+sizeof(px_recd)/sizeof(ulong);
 
216
 
 
217
    for ( ; ptr != end ; ptr++)
 
218
    {
 
219
      if (*ptr)
 
220
      {
 
221
        ulong set= *ptr;
 
222
        int found= (int) ((char*) ptr - (char*) &px_recd)*8+1;
 
223
        while (!(set & 1))
 
224
        {
 
225
          found++;
 
226
          set>>=1;
 
227
        }
 
228
        *sigp=found;
 
229
        sigdelset(&px_recd,found);
 
230
        return 0;
 
231
      }
 
232
    }
 
233
    sigsuspend(&rev_sigwait_set);
 
234
  }
 
235
  return 0;
 
236
}
 
237
#else  /* !DONT_USE_SIGSUSPEND */
 
238
 
 
239
/****************************************************************************
 
240
** Replacement of sigwait if the system doesn't have one (like BSDI 3.0)
 
241
**
 
242
** Note:
 
243
** This version of sigwait() is assumed to called in a loop so the signalmask
 
244
** is permanently modified to reflect the signal set. This is done to get
 
245
** a much faster implementation.
 
246
**
 
247
** This implementation uses a extra thread to handle the signals and one
 
248
** must always call sigwait() with the same signal mask!
 
249
**
 
250
** BSDI 3.0 NOTE:
 
251
**
 
252
** pthread_kill() doesn't work on a thread in a select() or sleep() loop?
 
253
** After adding the sleep to sigwait_thread, all signals are checked and
 
254
** delivered every second. This isn't that terrible performance vice, but
 
255
** someone should report this to BSDI and ask for a fix!
 
256
** Another problem is that when the sleep() ends, every select() in other
 
257
** threads are interrupted!
 
258
****************************************************************************/
 
259
 
 
260
static sigset_t pending_set;
 
261
static bool inited=0;
 
262
static pthread_cond_t  COND_sigwait;
 
263
static pthread_mutex_t LOCK_sigwait;
 
264
 
 
265
 
 
266
void sigwait_handle_sig(int sig)
 
267
{
 
268
  pthread_mutex_lock(&LOCK_sigwait);
 
269
  sigaddset(&pending_set, sig);
 
270
  VOID(pthread_cond_signal(&COND_sigwait)); /* inform sigwait() about signal */
 
271
  pthread_mutex_unlock(&LOCK_sigwait);
 
272
}
 
273
 
 
274
extern pthread_t alarm_thread;
 
275
 
 
276
void *sigwait_thread(void *set_arg)
 
277
{
 
278
  sigset_t *set=(sigset_t*) set_arg;
 
279
 
 
280
  int i;
 
281
  struct sigaction sact;
 
282
  sact.sa_flags = 0;
 
283
  sact.sa_handler = sigwait_handle_sig;
 
284
  memcpy_fixed(&sact.sa_mask,set,sizeof(*set)); /* handler isn't thread_safe */
 
285
  sigemptyset(&pending_set);
 
286
 
 
287
  for (i = 1; i <= sizeof(pending_set)*8; i++)
 
288
  {
 
289
    if (sigismember(set,i))
 
290
    {
 
291
      sigaction(i, &sact, (struct sigaction*) 0);
 
292
    }
 
293
  }
 
294
  sigaddset(set,THR_CLIENT_ALARM);
 
295
  pthread_sigmask(SIG_UNBLOCK,(sigset_t*) set,(sigset_t*) 0);
 
296
  alarm_thread=pthread_self();                  /* For thr_alarm */
 
297
 
 
298
  for (;;)
 
299
  {                                             /* Wait for signals */
 
300
#ifdef HAVE_NOT_BROKEN_SELECT
 
301
    fd_set fd;
 
302
    FD_ZERO(&fd);
 
303
    select(0,&fd,0,0,0);
 
304
#else
 
305
    sleep(1);                                   /* Because of broken BSDI */
 
306
#endif
 
307
  }
 
308
}
 
309
 
 
310
 
 
311
int sigwait(sigset_t *setp, int *sigp)
 
312
{
 
313
  if (!inited)
 
314
  {
 
315
    pthread_attr_t thr_attr;
 
316
    pthread_t sigwait_thread_id;
 
317
    inited=1;
 
318
    sigemptyset(&pending_set);
 
319
    pthread_mutex_init(&LOCK_sigwait,NULL);
 
320
    pthread_cond_init(&COND_sigwait,NULL);
 
321
 
 
322
    pthread_attr_init(&thr_attr);
 
323
    pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
 
324
    pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
 
325
    pthread_attr_setstacksize(&thr_attr,8196);
 
326
    my_pthread_attr_setprio(&thr_attr,100);     /* Very high priority */
 
327
    VOID(pthread_create(&sigwait_thread_id,&thr_attr,sigwait_thread,setp));
 
328
    VOID(pthread_attr_destroy(&thr_attr));
 
329
  }
 
330
 
 
331
  pthread_mutex_lock(&LOCK_sigwait);
 
332
  for (;;)
 
333
  {
 
334
    ulong *ptr= (ulong*) &pending_set;
 
335
    ulong *end=ptr+sizeof(pending_set)/sizeof(ulong);
 
336
 
 
337
    for ( ; ptr != end ; ptr++)
 
338
    {
 
339
      if (*ptr)
 
340
      {
 
341
        ulong set= *ptr;
 
342
        int found= (int) ((char*) ptr - (char*) &pending_set)*8+1;
 
343
        while (!(set & 1))
 
344
        {
 
345
          found++;
 
346
          set>>=1;
 
347
        }
 
348
        *sigp=found;
 
349
        sigdelset(&pending_set,found);
 
350
        pthread_mutex_unlock(&LOCK_sigwait);
 
351
        return 0;
 
352
      }
 
353
    }
 
354
    VOID(pthread_cond_wait(&COND_sigwait,&LOCK_sigwait));
 
355
  }
 
356
  return 0;
 
357
}
 
358
 
 
359
#endif /* DONT_USE_SIGSUSPEND */
 
360
#endif /* HAVE_SIGWAIT */
 
361
 
 
362
/*****************************************************************************
 
363
** Implement pthread_signal for systems that can't use signal() with threads
 
364
** Currently this is only used with BSDI 3.0
 
365
*****************************************************************************/
 
366
 
 
367
#ifdef USE_PTHREAD_SIGNAL
 
368
 
 
369
int pthread_signal(int sig, void (*func)())
 
370
{
 
371
  struct sigaction sact;
 
372
  sact.sa_flags= 0;
 
373
  sact.sa_handler= func;
 
374
  sigemptyset(&sact.sa_mask);
 
375
  sigaction(sig, &sact, (struct sigaction*) 0);
 
376
  return 0;
 
377
}
 
378
 
 
379
#endif
 
380
 
 
381
/*****************************************************************************
 
382
** Patches for AIX and DEC OSF/1 3.2
 
383
*****************************************************************************/
 
384
 
 
385
#if (defined(HAVE_NONPOSIX_PTHREAD_MUTEX_INIT) && !defined(HAVE_UNIXWARE7_THREADS)) || defined(HAVE_DEC_3_2_THREADS)
 
386
#undef pthread_mutex_init
 
387
#undef pthread_cond_init
 
388
 
 
389
#include <netdb.h>
 
390
 
 
391
int my_pthread_mutex_init(pthread_mutex_t *mp, const pthread_mutexattr_t *attr)
 
392
{
 
393
  int error;
 
394
  if (!attr)
 
395
    error=pthread_mutex_init(mp,pthread_mutexattr_default);
 
396
  else
 
397
    error=pthread_mutex_init(mp,*attr);
 
398
  return error;
 
399
}
 
400
 
 
401
int my_pthread_cond_init(pthread_cond_t *mp, const pthread_condattr_t *attr)
 
402
{
 
403
  int error;
 
404
  if (!attr)
 
405
    error=pthread_cond_init(mp,pthread_condattr_default);
 
406
  else
 
407
    error=pthread_cond_init(mp,*attr);
 
408
  return error;
 
409
}
 
410
 
 
411
#endif
 
412
 
 
413
/*
 
414
** Emulate SOLARIS style calls, not because it's better, but just to make the
 
415
** usage of getbostbyname_r simpler.
 
416
*/
 
417
 
 
418
#if !defined(my_gethostbyname_r) && defined(HAVE_GETHOSTBYNAME_R)
 
419
 
 
420
#if defined(HAVE_GLIBC2_STYLE_GETHOSTBYNAME_R)
 
421
 
 
422
struct hostent *my_gethostbyname_r(const char *name,
 
423
                                   struct hostent *result, char *buffer,
 
424
                                   int buflen, int *h_errnop)
 
425
{
 
426
  struct hostent *hp;
 
427
  assert((size_t) buflen >= sizeof(*result));
 
428
  if (gethostbyname_r(name,result, buffer, (size_t) buflen, &hp, h_errnop))
 
429
    return 0;
 
430
  return hp;
 
431
}
 
432
 
 
433
#elif defined(_HPUX_SOURCE) || (defined(_AIX) && !defined(_AIX32_THREADS))
 
434
 
 
435
struct hostent *my_gethostbyname_r(const char *name,
 
436
                                   struct hostent *result, char *buffer,
 
437
                                   int buflen, int *h_errnop)
 
438
{
 
439
  assert(buflen >= sizeof(struct hostent_data));
 
440
  if (gethostbyname_r(name,result,(struct hostent_data *) buffer) == -1)
 
441
  {
 
442
    *h_errnop= errno;
 
443
    return 0;
 
444
  }
 
445
  return result;
 
446
}
 
447
 
 
448
#else
 
449
 
 
450
struct hostent *my_gethostbyname_r(const char *name,
 
451
                                   struct hostent *result, char *buffer,
 
452
                                   int buflen, int *h_errnop)
 
453
{
 
454
  struct hostent *hp;
 
455
  assert(buflen >= sizeof(struct hostent_data));
 
456
  hp= gethostbyname_r(name,result,(struct hostent_data *) buffer);
 
457
  *h_errnop= errno;
 
458
  return hp;
 
459
}
 
460
 
 
461
#endif /* GLIBC2_STYLE_GETHOSTBYNAME_R */
 
462
#endif
 
463
 
 
464
 
 
465
/* Some help functions */
 
466
 
 
467
int pthread_no_free(void *not_used __attribute__((unused)))
 
468
{
 
469
  return 0;
 
470
}
 
471
 
 
472
int pthread_dummy(int ret)
 
473
{
 
474
  return ret;
 
475
}
 
476
#endif /* THREAD */