~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/my_pthread.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 */