MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
my_pthread.c
1 /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 /* Functions to get threads more portable */
17 
18 #define DONT_REMAP_PTHREAD_FUNCTIONS
19 
20 #include "mysys_priv.h"
21 #include <signal.h>
22 #include <m_string.h>
23 #include <thr_alarm.h>
24 
25 #if (defined(__BSD__) || defined(_BSDI_VERSION))
26 #define SCHED_POLICY SCHED_RR
27 #else
28 #define SCHED_POLICY SCHED_OTHER
29 #endif
30 
31 uint thd_lib_detected= 0;
32 
33 /* To allow use of pthread_getspecific with two arguments */
34 
35 #ifdef HAVE_NONPOSIX_PTHREAD_GETSPECIFIC
36 #undef pthread_getspecific
37 
38 void *my_pthread_getspecific_imp(pthread_key_t key)
39 {
40  void *value;
41  if (pthread_getspecific(key,(void *) &value))
42  return 0;
43  return value;
44 }
45 #endif
46 
47 /*
48  Some functions for RTS threads, AIX, Siemens Unix and UnixWare 7
49  (and DEC OSF/1 3.2 too)
50 */
51 
52 int my_pthread_create_detached=1;
53 
54 #if defined(HAVE_NONPOSIX_SIGWAIT) || defined(HAVE_DEC_3_2_THREADS)
55 
56 int my_sigwait(const sigset_t *set,int *sig)
57 {
58  int signal=sigwait((sigset_t*) set);
59  if (signal < 0)
60  return errno;
61  *sig=signal;
62  return 0;
63 }
64 #endif
65 
66 /* localtime_r for SCO 3.2V4.2 */
67 
68 #if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
69 
70 extern mysql_mutex_t LOCK_localtime_r;
71 
72 #endif
73 
74 #if !defined(HAVE_LOCALTIME_R)
75 struct tm *localtime_r(const time_t *clock, struct tm *res)
76 {
77  struct tm *tmp;
78  mysql_mutex_lock(&LOCK_localtime_r);
79  tmp=localtime(clock);
80  *res= *tmp;
81  mysql_mutex_unlock(&LOCK_localtime_r);
82  return res;
83 }
84 #endif
85 
86 #if !defined(HAVE_GMTIME_R)
87 /*
88  Reentrant version of standard gmtime() function.
89  Needed on some systems which don't implement it.
90 */
91 
92 struct tm *gmtime_r(const time_t *clock, struct tm *res)
93 {
94  struct tm *tmp;
95  mysql_mutex_lock(&LOCK_localtime_r);
96  tmp= gmtime(clock);
97  *res= *tmp;
98  mysql_mutex_unlock(&LOCK_localtime_r);
99  return res;
100 }
101 #endif
102 
103 /****************************************************************************
104 ** Replacement of sigwait if the system doesn't have one (like BSDI 3.0)
105 **
106 ** Note:
107 ** This version of sigwait() is assumed to called in a loop so the signalmask
108 ** is permanently modified to reflect the signal set. This is done to get
109 ** a much faster implementation.
110 **
111 ** This implementation isn't thread safe: It assumes that only one
112 ** thread is using sigwait.
113 **
114 ** If one later supplies a different signal mask, all old signals that
115 ** was used before are unblocked and set to SIGDFL.
116 **
117 ** Author: Gary Wisniewski <garyw@spidereye.com.au>, much modified by Monty
118 ****************************************************************************/
119 
120 #if !defined(HAVE_SIGWAIT) && !defined(sigwait) && !defined(__WIN__) && !defined(HAVE_rts_threads) && !defined(HAVE_NONPOSIX_SIGWAIT) && !defined(HAVE_DEC_3_2_THREADS)
121 
122 #if !defined(DONT_USE_SIGSUSPEND)
123 
124 static sigset_t sigwait_set,rev_sigwait_set,px_recd;
125 
126 void px_handle_sig(int sig)
127 {
128  sigaddset(&px_recd, sig);
129 }
130 
131 
132 void sigwait_setup(sigset_t *set)
133 {
134  int i;
135  struct sigaction sact,sact1;
136  sigset_t unblock_mask;
137 
138  sact.sa_flags = 0;
139  sact.sa_handler = px_handle_sig;
140  memcpy(&sact.sa_mask, set, sizeof(*set)); /* handler isn't thread_safe */
141  sigemptyset(&unblock_mask);
142  pthread_sigmask(SIG_UNBLOCK,(sigset_t*) 0,&rev_sigwait_set);
143 
144  for (i = 1; i <= sizeof(sigwait_set)*8; i++)
145  {
146  if (sigismember(set,i))
147  {
148  sigdelset(&rev_sigwait_set,i);
149  if (!sigismember(&sigwait_set,i))
150  sigaction(i, &sact, (struct sigaction*) 0);
151  }
152  else
153  {
154  sigdelset(&px_recd,i); /* Don't handle this */
155  if (sigismember(&sigwait_set,i))
156  { /* Remove the old handler */
157  sigaddset(&unblock_mask,i);
158  sigdelset(&rev_sigwait_set,i);
159  sact1.sa_flags = 0;
160  sact1.sa_handler = SIG_DFL;
161  sigemptyset(&sact1.sa_mask);
162  sigaction(i, &sact1, 0);
163  }
164  }
165  }
166  memcpy(&sigwait_set, set, sizeof(*set));
167  pthread_sigmask(SIG_BLOCK,(sigset_t*) set,(sigset_t*) 0);
168  pthread_sigmask(SIG_UNBLOCK,&unblock_mask,(sigset_t*) 0);
169 }
170 
171 
172 int sigwait(sigset_t *setp, int *sigp)
173 {
174  if (memcmp(setp,&sigwait_set,sizeof(sigwait_set)))
175  sigwait_setup(setp); /* Init or change of set */
176 
177  for (;;)
178  {
179  /*
180  This is a fast, not 100% portable implementation to find the signal.
181  Because the handler is blocked there should be at most 1 bit set, but
182  the specification on this is somewhat shady so we use a set instead a
183  single variable.
184  */
185 
186  ulong *ptr= (ulong*) &px_recd;
187  ulong *end=ptr+sizeof(px_recd)/sizeof(ulong);
188 
189  for ( ; ptr != end ; ptr++)
190  {
191  if (*ptr)
192  {
193  ulong set= *ptr;
194  int found= (int) ((char*) ptr - (char*) &px_recd)*8+1;
195  while (!(set & 1))
196  {
197  found++;
198  set>>=1;
199  }
200  *sigp=found;
201  sigdelset(&px_recd,found);
202  return 0;
203  }
204  }
205  sigsuspend(&rev_sigwait_set);
206  }
207  return 0;
208 }
209 #else /* !DONT_USE_SIGSUSPEND */
210 
211 /****************************************************************************
212 ** Replacement of sigwait if the system doesn't have one (like BSDI 3.0)
213 **
214 ** Note:
215 ** This version of sigwait() is assumed to called in a loop so the signalmask
216 ** is permanently modified to reflect the signal set. This is done to get
217 ** a much faster implementation.
218 **
219 ** This implementation uses a extra thread to handle the signals and one
220 ** must always call sigwait() with the same signal mask!
221 **
222 ** BSDI 3.0 NOTE:
223 **
224 ** pthread_kill() doesn't work on a thread in a select() or sleep() loop?
225 ** After adding the sleep to sigwait_thread, all signals are checked and
226 ** delivered every second. This isn't that terrible performance vice, but
227 ** someone should report this to BSDI and ask for a fix!
228 ** Another problem is that when the sleep() ends, every select() in other
229 ** threads are interrupted!
230 ****************************************************************************/
231 
232 static sigset_t pending_set;
233 static bool inited=0;
234 static pthread_cond_t COND_sigwait;
235 static pthread_mutex_t LOCK_sigwait;
236 
237 
238 void sigwait_handle_sig(int sig)
239 {
240  pthread_mutex_lock(&LOCK_sigwait);
241  sigaddset(&pending_set, sig);
242  pthread_cond_signal(&COND_sigwait); /* inform sigwait() about signal */
243  pthread_mutex_unlock(&LOCK_sigwait);
244 }
245 
246 void *sigwait_thread(void *set_arg)
247 {
248  sigset_t *set=(sigset_t*) set_arg;
249 
250  int i;
251  struct sigaction sact;
252  sact.sa_flags = 0;
253  sact.sa_handler = sigwait_handle_sig;
254  memcpy(&sact.sa_mask, set, sizeof(*set)); /* handler isn't thread_safe */
255  sigemptyset(&pending_set);
256 
257  for (i = 1; i <= sizeof(pending_set)*8; i++)
258  {
259  if (sigismember(set,i))
260  {
261  sigaction(i, &sact, (struct sigaction*) 0);
262  }
263  }
264  /* Ensure that init_thr_alarm() is called */
265  DBUG_ASSERT(thr_client_alarm);
266  sigaddset(set, thr_client_alarm);
267  pthread_sigmask(SIG_UNBLOCK,(sigset_t*) set,(sigset_t*) 0);
268  alarm_thread=pthread_self(); /* For thr_alarm */
269 
270  for (;;)
271  { /* Wait for signals */
272 #ifdef HAVE_NOT_BROKEN_SELECT
273  fd_set fd;
274  FD_ZERO(&fd);
275  select(0,&fd,0,0,0);
276 #else
277  sleep(1); /* Because of broken BSDI */
278 #endif
279  }
280 }
281 
282 
283 int sigwait(sigset_t *setp, int *sigp)
284 {
285  if (!inited)
286  {
287  pthread_attr_t thr_attr;
288  pthread_t sigwait_thread_id;
289  inited=1;
290  sigemptyset(&pending_set);
291  pthread_mutex_init(&LOCK_sigwait, MY_MUTEX_INIT_FAST);
292  pthread_cond_init(&COND_sigwait, NULL);
293 
294  pthread_attr_init(&thr_attr);
295  pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
296  pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
297  pthread_attr_setstacksize(&thr_attr,8196);
298  pthread_create(&sigwait_thread_id, &thr_attr, sigwait_thread, setp);
299  pthread_attr_destroy(&thr_attr);
300  }
301 
302  pthread_mutex_lock(&LOCK_sigwait);
303  for (;;)
304  {
305  ulong *ptr= (ulong*) &pending_set;
306  ulong *end=ptr+sizeof(pending_set)/sizeof(ulong);
307 
308  for ( ; ptr != end ; ptr++)
309  {
310  if (*ptr)
311  {
312  ulong set= *ptr;
313  int found= (int) ((char*) ptr - (char*) &pending_set)*8+1;
314  while (!(set & 1))
315  {
316  found++;
317  set>>=1;
318  }
319  *sigp=found;
320  sigdelset(&pending_set,found);
321  pthread_mutex_unlock(&LOCK_sigwait);
322  return 0;
323  }
324  }
325  pthread_cond_wait(&COND_sigwait, &LOCK_sigwait);
326  }
327  return 0;
328 }
329 
330 #endif /* DONT_USE_SIGSUSPEND */
331 #endif /* HAVE_SIGWAIT */
332 
333 
334 /****************************************************************************
335  The following functions fixes that all pthread functions should work
336  according to latest posix standard
337 ****************************************************************************/
338 
339 /* Undefined wrappers set my_pthread.h so that we call os functions */
340 #undef pthread_mutex_init
341 #undef pthread_mutex_lock
342 #undef pthread_mutex_unlock
343 #undef pthread_mutex_destroy
344 #undef pthread_mutex_wait
345 #undef pthread_mutex_timedwait
346 #undef pthread_mutex_trylock
347 #undef pthread_mutex_t
348 #undef pthread_cond_init
349 #undef pthread_cond_wait
350 #undef pthread_cond_timedwait
351 #undef pthread_cond_t
352 #undef pthread_attr_getstacksize
353 
354 /*****************************************************************************
355 ** Patches for AIX and DEC OSF/1 3.2
356 *****************************************************************************/
357 
358 #if defined(HAVE_NONPOSIX_PTHREAD_MUTEX_INIT)
359 
360 #include <netdb.h>
361 
362 int my_pthread_mutex_init(pthread_mutex_t *mp, const pthread_mutexattr_t *attr)
363 {
364  int error;
365  if (!attr)
366  error=pthread_mutex_init(mp,pthread_mutexattr_default);
367  else
368  error=pthread_mutex_init(mp,*attr);
369  return error;
370 }
371 
372 int my_pthread_cond_init(pthread_cond_t *mp, const pthread_condattr_t *attr)
373 {
374  int error;
375  if (!attr)
376  error=pthread_cond_init(mp,pthread_condattr_default);
377  else
378  error=pthread_cond_init(mp,*attr);
379  return error;
380 }
381 
382 #endif
383 
384 
385 /*****************************************************************************
386  Patches for HPUX
387  We need these because the pthread_mutex.. code returns -1 on error,
388  instead of the error code.
389 
390  Note that currently we only remap pthread_ functions used by MySQL.
391  If we are depending on the value for some other pthread_xxx functions,
392  this has to be added here.
393 ****************************************************************************/
394 
395 #if defined(HPUX10) || defined(HAVE_BROKEN_PTHREAD_COND_TIMEDWAIT)
396 
397 int my_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
398  struct timespec *abstime)
399 {
400  int error=pthread_cond_timedwait(cond, mutex, abstime);
401  if (error == -1) /* Safety if the lib is fixed */
402  {
403  if (!(error=errno))
404  error= ETIMEDOUT; /* Can happen on HPUX */
405  }
406  if (error == EAGAIN) /* Correct errno to Posix */
407  error= ETIMEDOUT;
408  return error;
409 }
410 #endif
411 
412 #if defined(HPUX10)
413 
414 void my_pthread_attr_getstacksize(pthread_attr_t *connection_attrib,
415  size_t *stack_size)
416 {
417  *stack_size= pthread_attr_getstacksize(*connection_attrib);
418 }
419 #endif
420 
421 
422 #ifdef HAVE_POSIX1003_4a_MUTEX
423 /*
424  In HP-UX-10.20 and other old Posix 1003.4a Draft 4 implementations
425  pthread_mutex_trylock returns 1 on success, not 0 like
426  pthread_mutex_lock
427 
428  From the HP-UX-10.20 man page:
429  RETURN VALUES
430  If the function fails, errno may be set to one of the following
431  values:
432  Return | Error | Description
433  _______|__________|_________________________________________
434  1 | | Successful completion.
435  0 | | The mutex is locked; therefore, it was
436  | | not acquired.
437  -1 | [EINVAL] | The value specified by mutex is invalid.
438 
439 */
440 
441 /*
442  Convert pthread_mutex_trylock to return values according to latest POSIX
443 
444  RETURN VALUES
445  0 If we are able successfully lock the mutex.
446  EBUSY Mutex was locked by another thread
447  # Other error number returned by pthread_mutex_trylock()
448  (Not likely)
449 */
450 
451 int my_pthread_mutex_trylock(pthread_mutex_t *mutex)
452 {
453  int error= pthread_mutex_trylock(mutex);
454  if (error == 1)
455  return 0; /* Got lock on mutex */
456  if (error == 0) /* Someon else is locking mutex */
457  return EBUSY;
458  if (error == -1) /* Safety if the lib is fixed */
459  error= errno; /* Probably invalid parameter */
460  return error;
461 }
462 #endif /* HAVE_POSIX1003_4a_MUTEX */
463 
464 /* Some help functions */
465 
466 int pthread_dummy(int ret)
467 {
468  return ret;
469 }