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 | |