Commit | Line | Data |
---|---|---|
2a84b02d | 1 | /* POSIX compatible signal blocking for threads. |
caf8a9b2 | 2 | Copyright (C) 2011-2012 Free Software Foundation, Inc. |
2a84b02d PE |
3 | |
4 | This program is free software: you can redistribute it and/or modify | |
5 | it under the terms of the GNU General Public License as published by | |
6 | the Free Software Foundation; either version 3 of the License, or | |
7 | (at your option) any later version. | |
8 | ||
9 | This program is distributed in the hope that it will be useful, | |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | GNU General Public License for more details. | |
13 | ||
14 | You should have received a copy of the GNU General Public License | |
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
16 | ||
17 | #include <config.h> | |
18 | ||
19 | /* Specification. */ | |
20 | #include <signal.h> | |
21 | ||
22 | #include <errno.h> | |
24e0f6b1 PE |
23 | #include <stddef.h> |
24 | ||
b6e9e0ff PE |
25 | #if PTHREAD_SIGMASK_INEFFECTIVE |
26 | # include <string.h> | |
27 | #endif | |
28 | ||
24e0f6b1 PE |
29 | #if PTHREAD_SIGMASK_UNBLOCK_BUG |
30 | # include <unistd.h> | |
31 | #endif | |
2a84b02d PE |
32 | |
33 | int | |
34 | pthread_sigmask (int how, const sigset_t *new_mask, sigset_t *old_mask) | |
24e0f6b1 | 35 | #undef pthread_sigmask |
2a84b02d | 36 | { |
24e0f6b1 | 37 | #if HAVE_PTHREAD_SIGMASK |
b6e9e0ff PE |
38 | int ret; |
39 | ||
40 | # if PTHREAD_SIGMASK_INEFFECTIVE | |
41 | sigset_t omask, omask_copy; | |
42 | sigset_t *old_mask_ptr = &omask; | |
43 | sigemptyset (&omask); | |
44 | /* Add a signal unlikely to be blocked, so that OMASK_COPY | |
45 | is unlikely to match the actual mask. */ | |
46 | sigaddset (&omask, SIGILL); | |
47 | memcpy (&omask_copy, &omask, sizeof omask); | |
48 | # else | |
49 | sigset_t *old_mask_ptr = old_mask; | |
50 | # endif | |
51 | ||
52 | ret = pthread_sigmask (how, new_mask, old_mask_ptr); | |
53 | ||
24e0f6b1 PE |
54 | # if PTHREAD_SIGMASK_INEFFECTIVE |
55 | if (ret == 0) | |
56 | { | |
57 | /* Detect whether pthread_sigmask is currently ineffective. | |
58 | Don't cache the information: libpthread.so could be dynamically | |
59 | loaded after the program started and after pthread_sigmask was | |
60 | called for the first time. */ | |
b6e9e0ff PE |
61 | if (memcmp (&omask_copy, &omask, sizeof omask) == 0 |
62 | && pthread_sigmask (1729, &omask_copy, NULL) == 0) | |
24e0f6b1 PE |
63 | { |
64 | /* pthread_sigmask is currently ineffective. The program is not | |
65 | linked to -lpthread. So use sigprocmask instead. */ | |
66 | return (sigprocmask (how, new_mask, old_mask) < 0 ? errno : 0); | |
67 | } | |
b6e9e0ff PE |
68 | |
69 | if (old_mask) | |
70 | memcpy (old_mask, &omask, sizeof omask); | |
24e0f6b1 PE |
71 | } |
72 | # endif | |
73 | # if PTHREAD_SIGMASK_FAILS_WITH_ERRNO | |
74 | if (ret == -1) | |
75 | return errno; | |
76 | # endif | |
77 | # if PTHREAD_SIGMASK_UNBLOCK_BUG | |
78 | if (ret == 0 | |
79 | && new_mask != NULL | |
80 | && (how == SIG_UNBLOCK || how == SIG_SETMASK)) | |
81 | { | |
82 | /* Give the OS the opportunity to raise signals that were pending before | |
83 | the pthread_sigmask call and have now been unblocked. */ | |
84 | usleep (1); | |
85 | } | |
86 | # endif | |
87 | return ret; | |
88 | #else | |
2a84b02d PE |
89 | int ret = sigprocmask (how, new_mask, old_mask); |
90 | return (ret < 0 ? errno : 0); | |
24e0f6b1 | 91 | #endif |
2a84b02d | 92 | } |