~drizzle-trunk/drizzle/development

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