#include "mysys_priv.h"
#ifdef THREAD
#include <signal.h>
#include <m_string.h>
#include <thr_alarm.h>
#include <assert.h>
#if !defined(MSDOS) && !defined(__WIN__)
#include <netdb.h>
#endif
#if (defined(__BSD__) || defined(_BSDI_VERSION)) && !defined(HAVE_mit_thread)
#define SCHED_POLICY SCHED_RR
#else
#define SCHED_POLICY SCHED_OTHER
#endif
#ifndef my_pthread_setprio
void my_pthread_setprio(pthread_t thread_id,int prior)
{
#ifdef HAVE_PTHREAD_SETSCHEDPARAM
struct sched_param tmp_sched_param;
bzero((char*) &tmp_sched_param,sizeof(tmp_sched_param));
tmp_sched_param.sched_priority=prior;
VOID(pthread_setschedparam(thread_id,SCHED_POLICY,&tmp_sched_param));
#endif
}
#endif
#ifndef my_pthread_getprio
int my_pthread_getprio(pthread_t thread_id)
{
#ifdef HAVE_PTHREAD_SETSCHEDPARAM
struct sched_param tmp_sched_param;
int policy;
if (!pthread_getschedparam(thread_id,&policy,&tmp_sched_param))
{
DBUG_PRINT("thread",("policy: %d priority: %d",
policy,tmp_sched_param.sched_priority));
return tmp_sched_param.sched_priority;
}
#endif
return -1;
}
#endif
#ifndef my_pthread_attr_setprio
void my_pthread_attr_setprio(pthread_attr_t *attr, int priority)
{
#ifdef HAVE_PTHREAD_SETSCHEDPARAM
struct sched_param tmp_sched_param;
bzero((char*) &tmp_sched_param,sizeof(tmp_sched_param));
tmp_sched_param.sched_priority=priority;
VOID(pthread_attr_setschedparam(attr,&tmp_sched_param));
#endif
}
#endif
#ifdef HAVE_NONPOSIX_PTHREAD_GETSPECIFIC
#undef pthread_getspecific
#ifdef HAVE_UNIXWARE7_THREADS
#define pthread_getspecific thr_getspecific
#endif
void *my_pthread_getspecific_imp(pthread_key_t key)
{
void *value;
if (pthread_getspecific(key,(void *) &value))
return 0;
return value;
}
#endif
int my_pthread_create_detached=1;
#if defined(HAVE_NONPOSIX_SIGWAIT) || defined(HAVE_DEC_3_2_THREADS)
int my_sigwait(const sigset_t *set,int *sig)
{
int signal=sigwait((sigset_t*) set);
if (signal < 0)
return errno;
*sig=signal;
return 0;
}
#endif
#ifndef HAVE_LOCALTIME_R
extern pthread_mutex_t LOCK_localtime_r;
struct tm *localtime_r(const time_t *clock, struct tm *res)
{
struct tm *tmp;
pthread_mutex_lock(&LOCK_localtime_r);
tmp=localtime(clock);
*res= *tmp;
pthread_mutex_unlock(&LOCK_localtime_r);
return res;
}
#endif
#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) && !defined(OS2)
#if !defined(DONT_USE_SIGSUSPEND)
static sigset_t sigwait_set,rev_sigwait_set,px_recd;
void px_handle_sig(int sig)
{
sigaddset(&px_recd, sig);
}
void sigwait_setup(sigset_t *set)
{
int i;
struct sigaction sact,sact1;
sigset_t unblock_mask;
sact.sa_flags = 0;
sact.sa_handler = px_handle_sig;
memcpy_fixed(&sact.sa_mask,set,sizeof(*set));
sigemptyset(&unblock_mask);
pthread_sigmask(SIG_UNBLOCK,(sigset_t*) 0,&rev_sigwait_set);
for (i = 1; i <= sizeof(sigwait_set)*8; i++)
{
if (sigismember(set,i))
{
sigdelset(&rev_sigwait_set,i);
if (!sigismember(&sigwait_set,i))
sigaction(i, &sact, (struct sigaction*) 0);
}
else
{
sigdelset(&px_recd,i);
if (sigismember(&sigwait_set,i))
{
sigaddset(&unblock_mask,i);
sigdelset(&rev_sigwait_set,i);
sact1.sa_flags = 0;
sact1.sa_handler = SIG_DFL;
sigemptyset(&sact1.sa_mask);
sigaction(i, &sact1, 0);
}
}
}
memcpy_fixed(&sigwait_set,set,sizeof(*set));
pthread_sigmask(SIG_BLOCK,(sigset_t*) set,(sigset_t*) 0);
pthread_sigmask(SIG_UNBLOCK,&unblock_mask,(sigset_t*) 0);
}
int sigwait(sigset_t *setp, int *sigp)
{
if (memcmp(setp,&sigwait_set,sizeof(sigwait_set)))
sigwait_setup(setp);
for (;;)
{
ulong *ptr= (ulong*) &px_recd;
ulong *end=ptr+sizeof(px_recd)/sizeof(ulong);
for ( ; ptr != end ; ptr++)
{
if (*ptr)
{
ulong set= *ptr;
int found= (int) ((char*) ptr - (char*) &px_recd)*8+1;
while (!(set & 1))
{
found++;
set>>=1;
}
*sigp=found;
sigdelset(&px_recd,found);
return 0;
}
}
sigsuspend(&rev_sigwait_set);
}
return 0;
}
#else
static sigset_t pending_set;
static bool inited=0;
static pthread_cond_t COND_sigwait;
static pthread_mutex_t LOCK_sigwait;
void sigwait_handle_sig(int sig)
{
pthread_mutex_lock(&LOCK_sigwait);
sigaddset(&pending_set, sig);
VOID(pthread_cond_signal(&COND_sigwait));
pthread_mutex_unlock(&LOCK_sigwait);
}
extern pthread_t alarm_thread;
void *sigwait_thread(void *set_arg)
{
sigset_t *set=(sigset_t*) set_arg;
int i;
struct sigaction sact;
sact.sa_flags = 0;
sact.sa_handler = sigwait_handle_sig;
memcpy_fixed(&sact.sa_mask,set,sizeof(*set));
sigemptyset(&pending_set);
for (i = 1; i <= sizeof(pending_set)*8; i++)
{
if (sigismember(set,i))
{
sigaction(i, &sact, (struct sigaction*) 0);
}
}
sigaddset(set,THR_CLIENT_ALARM);
pthread_sigmask(SIG_UNBLOCK,(sigset_t*) set,(sigset_t*) 0);
alarm_thread=pthread_self();
for (;;)
{
#ifdef HAVE_NOT_BROKEN_SELECT
fd_set fd;
FD_ZERO(&fd);
select(0,&fd,0,0,0);
#else
sleep(1);
#endif
}
}
int sigwait(sigset_t *setp, int *sigp)
{
if (!inited)
{
pthread_attr_t thr_attr;
pthread_t sigwait_thread_id;
inited=1;
sigemptyset(&pending_set);
pthread_mutex_init(&LOCK_sigwait,MY_MUTEX_INIT_FAST);
pthread_cond_init(&COND_sigwait,NULL);
pthread_attr_init(&thr_attr);
pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
pthread_attr_setstacksize(&thr_attr,8196);
my_pthread_attr_setprio(&thr_attr,100);
VOID(pthread_create(&sigwait_thread_id,&thr_attr,sigwait_thread,setp));
VOID(pthread_attr_destroy(&thr_attr));
}
pthread_mutex_lock(&LOCK_sigwait);
for (;;)
{
ulong *ptr= (ulong*) &pending_set;
ulong *end=ptr+sizeof(pending_set)/sizeof(ulong);
for ( ; ptr != end ; ptr++)
{
if (*ptr)
{
ulong set= *ptr;
int found= (int) ((char*) ptr - (char*) &pending_set)*8+1;
while (!(set & 1))
{
found++;
set>>=1;
}
*sigp=found;
sigdelset(&pending_set,found);
pthread_mutex_unlock(&LOCK_sigwait);
return 0;
}
}
VOID(pthread_cond_wait(&COND_sigwait,&LOCK_sigwait));
}
return 0;
}
#endif
#endif
#ifdef USE_PTHREAD_SIGNAL
int pthread_signal(int sig, void (*func)())
{
struct sigaction sact;
sact.sa_flags= 0;
sact.sa_handler= func;
sigemptyset(&sact.sa_mask);
sigaction(sig, &sact, (struct sigaction*) 0);
return 0;
}
#endif
#if (defined(HAVE_NONPOSIX_PTHREAD_MUTEX_INIT) && !defined(HAVE_UNIXWARE7_THREADS)) || defined(HAVE_DEC_3_2_THREADS)
#undef pthread_mutex_init
#undef pthread_cond_init
#include <netdb.h>
int my_pthread_mutex_init(pthread_mutex_t *mp, const pthread_mutexattr_t *attr)
{
int error;
if (!attr)
error=pthread_mutex_init(mp,pthread_mutexattr_default);
else
error=pthread_mutex_init(mp,*attr);
return error;
}
int my_pthread_cond_init(pthread_cond_t *mp, const pthread_condattr_t *attr)
{
int error;
if (!attr)
error=pthread_cond_init(mp,pthread_condattr_default);
else
error=pthread_cond_init(mp,*attr);
return error;
}
#endif
#if !defined(my_gethostbyname_r) && defined(HAVE_GETHOSTBYNAME_R)
#if defined(HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE)
struct hostent *my_gethostbyname_r(const char *name,
struct hostent *result, char *buffer,
int buflen, int *h_errnop)
{
struct hostent *hp;
dbug_assert((size_t) buflen >= sizeof(*result));
if (gethostbyname_r(name,result, buffer, (size_t) buflen, &hp, h_errnop))
return 0;
return hp;
}
#elif defined(HAVE_GETHOSTBYNAME_R_RETURN_INT)
struct hostent *my_gethostbyname_r(const char *name,
struct hostent *result, char *buffer,
int buflen, int *h_errnop)
{
dbug_assert(buflen >= sizeof(struct hostent_data));
if (gethostbyname_r(name,result,(struct hostent_data *) buffer) == -1)
{
*h_errnop= errno;
return 0;
}
return result;
}
#else
struct hostent *my_gethostbyname_r(const char *name,
struct hostent *result, char *buffer,
int buflen, int *h_errnop)
{
struct hostent *hp;
dbug_assert(buflen >= sizeof(struct hostent_data));
hp= gethostbyname_r(name,result,(struct hostent_data *) buffer);
*h_errnop= errno;
return hp;
}
#endif
#endif
int pthread_no_free(void *not_used __attribute__((unused)))
{
return 0;
}
int pthread_dummy(int ret)
{
return ret;
}
#endif