1
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
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.
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.
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,
18
/* Functions to get threads more portable */
20
#include "mysys_priv.h"
24
#include <thr_alarm.h>
26
#if !defined(MSDOS) && !defined(__WIN__)
30
#if (defined(__BSD__) || defined(_BSDI_VERSION)) && !defined(HAVE_mit_thread)
31
#define SCHED_POLICY SCHED_RR
33
#define SCHED_POLICY SCHED_OTHER
36
#ifndef my_pthread_setprio
37
void my_pthread_setprio(pthread_t thread_id,int prior)
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));
48
#ifndef my_pthread_getprio
49
int my_pthread_getprio(pthread_t thread_id)
51
#ifdef HAVE_PTHREAD_SETSCHEDPARAM
52
struct sched_param tmp_sched_param;
54
if (!pthread_getschedparam(thread_id,&policy,&tmp_sched_param))
56
DBUG_PRINT("thread",("policy: %d priority: %d",
57
policy,tmp_sched_param.sched_priority));
58
return tmp_sched_param.sched_priority;
65
#ifndef my_pthread_attr_setprio
66
void my_pthread_attr_setprio(pthread_attr_t *attr, int priority)
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));
78
/* To allow use of pthread_getspecific with two arguments */
80
#ifdef HAVE_NONPOSIX_PTHREAD_GETSPECIFIC
81
#undef pthread_getspecific
82
#ifdef HAVE_UNIXWARE7_THREADS
83
#define pthread_getspecific thr_getspecific
86
void *my_pthread_getspecific_imp(pthread_key_t key)
89
if (pthread_getspecific(key,(void *) &value))
96
/* Some functions for RTS threads, AIX, Siemens Unix and UnixWare 7
97
(and DEC OSF/1 3.2 too) */
99
int my_pthread_create_detached=1;
101
#if defined(HAVE_NONPOSIX_SIGWAIT) || defined(HAVE_DEC_3_2_THREADS)
103
int my_sigwait(sigset_t *set,int *sig)
105
int signal=sigwait(set);
113
/* localtime_r for SCO 3.2V4.2 */
115
#ifndef HAVE_LOCALTIME_R
117
extern pthread_mutex_t LOCK_localtime_r;
119
struct tm *localtime_r(const time_t *clock, struct tm *res)
122
pthread_mutex_lock(&LOCK_localtime_r);
123
tmp=localtime(clock);
125
pthread_mutex_unlock(&LOCK_localtime_r);
131
/****************************************************************************
132
** Replacement of sigwait if the system doesn't have one (like BSDI 3.0)
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.
139
** This implementation isn't thread safe: It assumes that only one
140
** thread is using sigwait.
142
** If one later supplies a different signal mask, all old signals that
143
** was used before are unblocked and set to SIGDFL.
145
** Author: Gary Wisniewski <garyw@spidereye.com.au>, much modified by Monty
146
****************************************************************************/
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)
150
#if !defined(DONT_USE_SIGSUSPEND)
152
static sigset_t sigwait_set,rev_sigwait_set,px_recd;
154
void px_handle_sig(int sig)
156
sigaddset(&px_recd, sig);
160
void sigwait_setup(sigset_t *set)
163
struct sigaction sact,sact1;
164
sigset_t unblock_mask;
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);
172
for (i = 1; i <= sizeof(sigwait_set)*8; i++)
174
if (sigismember(set,i))
176
sigdelset(&rev_sigwait_set,i);
177
if (!sigismember(&sigwait_set,i))
178
sigaction(i, &sact, (struct sigaction*) 0);
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);
188
sact1.sa_handler = SIG_DFL;
189
sigemptyset(&sact1.sa_mask);
190
sigaction(i, &sact1, 0);
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);
200
int sigwait(sigset_t *setp, int *sigp)
202
if (memcmp(setp,&sigwait_set,sizeof(sigwait_set)))
203
sigwait_setup(setp); /* Init or change of set */
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
214
ulong *ptr= (ulong*) &px_recd;
215
ulong *end=ptr+sizeof(px_recd)/sizeof(ulong);
217
for ( ; ptr != end ; ptr++)
222
int found= (int) ((char*) ptr - (char*) &px_recd)*8+1;
229
sigdelset(&px_recd,found);
233
sigsuspend(&rev_sigwait_set);
237
#else /* !DONT_USE_SIGSUSPEND */
239
/****************************************************************************
240
** Replacement of sigwait if the system doesn't have one (like BSDI 3.0)
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.
247
** This implementation uses a extra thread to handle the signals and one
248
** must always call sigwait() with the same signal mask!
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
****************************************************************************/
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;
266
void sigwait_handle_sig(int sig)
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);
274
extern pthread_t alarm_thread;
276
void *sigwait_thread(void *set_arg)
278
sigset_t *set=(sigset_t*) set_arg;
281
struct sigaction sact;
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);
287
for (i = 1; i <= sizeof(pending_set)*8; i++)
289
if (sigismember(set,i))
291
sigaction(i, &sact, (struct sigaction*) 0);
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 */
299
{ /* Wait for signals */
300
#ifdef HAVE_NOT_BROKEN_SELECT
305
sleep(1); /* Because of broken BSDI */
311
int sigwait(sigset_t *setp, int *sigp)
315
pthread_attr_t thr_attr;
316
pthread_t sigwait_thread_id;
318
sigemptyset(&pending_set);
319
pthread_mutex_init(&LOCK_sigwait,NULL);
320
pthread_cond_init(&COND_sigwait,NULL);
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));
331
pthread_mutex_lock(&LOCK_sigwait);
334
ulong *ptr= (ulong*) &pending_set;
335
ulong *end=ptr+sizeof(pending_set)/sizeof(ulong);
337
for ( ; ptr != end ; ptr++)
342
int found= (int) ((char*) ptr - (char*) &pending_set)*8+1;
349
sigdelset(&pending_set,found);
350
pthread_mutex_unlock(&LOCK_sigwait);
354
VOID(pthread_cond_wait(&COND_sigwait,&LOCK_sigwait));
359
#endif /* DONT_USE_SIGSUSPEND */
360
#endif /* HAVE_SIGWAIT */
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
*****************************************************************************/
367
#ifdef USE_PTHREAD_SIGNAL
369
int pthread_signal(int sig, void (*func)())
371
struct sigaction sact;
373
sact.sa_handler= func;
374
sigemptyset(&sact.sa_mask);
375
sigaction(sig, &sact, (struct sigaction*) 0);
381
/*****************************************************************************
382
** Patches for AIX and DEC OSF/1 3.2
383
*****************************************************************************/
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
391
int my_pthread_mutex_init(pthread_mutex_t *mp, const pthread_mutexattr_t *attr)
395
error=pthread_mutex_init(mp,pthread_mutexattr_default);
397
error=pthread_mutex_init(mp,*attr);
401
int my_pthread_cond_init(pthread_cond_t *mp, const pthread_condattr_t *attr)
405
error=pthread_cond_init(mp,pthread_condattr_default);
407
error=pthread_cond_init(mp,*attr);
414
** Emulate SOLARIS style calls, not because it's better, but just to make the
415
** usage of getbostbyname_r simpler.
418
#if !defined(my_gethostbyname_r) && defined(HAVE_GETHOSTBYNAME_R)
420
#if defined(HAVE_GLIBC2_STYLE_GETHOSTBYNAME_R)
422
struct hostent *my_gethostbyname_r(const char *name,
423
struct hostent *result, char *buffer,
424
int buflen, int *h_errnop)
427
assert((size_t) buflen >= sizeof(*result));
428
if (gethostbyname_r(name,result, buffer, (size_t) buflen, &hp, h_errnop))
433
#elif defined(_HPUX_SOURCE) || (defined(_AIX) && !defined(_AIX32_THREADS))
435
struct hostent *my_gethostbyname_r(const char *name,
436
struct hostent *result, char *buffer,
437
int buflen, int *h_errnop)
439
assert(buflen >= sizeof(struct hostent_data));
440
if (gethostbyname_r(name,result,(struct hostent_data *) buffer) == -1)
450
struct hostent *my_gethostbyname_r(const char *name,
451
struct hostent *result, char *buffer,
452
int buflen, int *h_errnop)
455
assert(buflen >= sizeof(struct hostent_data));
456
hp= gethostbyname_r(name,result,(struct hostent_data *) buffer);
461
#endif /* GLIBC2_STYLE_GETHOSTBYNAME_R */
465
/* Some help functions */
467
int pthread_no_free(void *not_used __attribute__((unused)))
472
int pthread_dummy(int ret)