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