1 | /* Copyright (C) 2002-2022 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. |
3 | |
4 | The GNU C Library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2.1 of the License, or (at your option) any later version. |
8 | |
9 | The GNU C Library 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 GNU |
12 | Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with the GNU C Library; if not, see |
16 | <https://www.gnu.org/licenses/>. */ |
17 | |
18 | #include <errno.h> |
19 | #include <pthread.h> |
20 | #include <semaphore.h> |
21 | #include <signal.h> |
22 | #include <stdio.h> |
23 | #include <stdlib.h> |
24 | #include <unistd.h> |
25 | |
26 | |
27 | #ifdef SIGRTMIN |
28 | |
29 | /* Number of different signals to use. Also is the number of threads. */ |
30 | # define N 10 |
31 | /* Maximum number of threads in flight at any one time. */ |
32 | # define INFLIGHT 5 |
33 | /* Number of signals sent in total. */ |
34 | # define ROUNDS 10000 |
35 | |
36 | |
37 | static int received[N][N]; |
38 | static int nsig[N]; |
39 | static pthread_t th[N]; |
40 | static sem_t sem; |
41 | static pthread_mutex_t lock[N]; |
42 | static pthread_t th_main; |
43 | static int sig0; |
44 | |
45 | static void |
46 | handler (int sig) |
47 | { |
48 | int i; |
49 | for (i = 0; i < N; ++i) |
50 | if (pthread_equal (thread1: pthread_self (), thread2: th[i])) |
51 | break; |
52 | |
53 | if (i == N) |
54 | { |
55 | if (pthread_equal (thread1: pthread_self (), thread2: th_main)) |
56 | puts (s: "signal received by main thread" ); |
57 | else |
58 | printf (format: "signal received by unknown thread (%lx)\n" , |
59 | (unsigned long int) pthread_self ()); |
60 | exit (1); |
61 | } |
62 | |
63 | ++received[i][sig - sig0]; |
64 | |
65 | sem_post (sem: &sem); |
66 | } |
67 | |
68 | |
69 | static void * |
70 | tf (void *arg) |
71 | { |
72 | int idx = (long int) arg; |
73 | |
74 | sigset_t ss; |
75 | sigemptyset (&ss); |
76 | |
77 | int i; |
78 | for (i = 0; i <= idx; ++i) |
79 | sigaddset (&ss, sig0 + i); |
80 | |
81 | if (pthread_sigmask (SIG_UNBLOCK, newmask: &ss, NULL) != 0) |
82 | { |
83 | printf (format: "thread %d: pthread_sigmask failed\n" , i); |
84 | exit (1); |
85 | } |
86 | |
87 | pthread_mutex_lock (mutex: &lock[idx]); |
88 | |
89 | return NULL; |
90 | } |
91 | |
92 | |
93 | static int |
94 | do_test (void) |
95 | { |
96 | /* Block all signals. */ |
97 | sigset_t ss; |
98 | sigfillset (&ss); |
99 | |
100 | th_main = pthread_self (); |
101 | |
102 | sig0 = SIGRTMIN; |
103 | |
104 | if (pthread_sigmask (SIG_SETMASK, newmask: &ss, NULL) != 0) |
105 | { |
106 | puts (s: "1st pthread_sigmask failed" ); |
107 | exit (1); |
108 | } |
109 | |
110 | /* Install the handler. */ |
111 | int i; |
112 | for (i = 0; i < N; ++i) |
113 | { |
114 | struct sigaction sa = |
115 | { |
116 | .sa_handler = handler, |
117 | .sa_flags = 0 |
118 | }; |
119 | sigfillset (&sa.sa_mask); |
120 | |
121 | if (sigaction (sig: sig0 + i, act: &sa, NULL) != 0) |
122 | { |
123 | printf (format: "sigaction for signal %d failed\n" , i); |
124 | exit (1); |
125 | } |
126 | } |
127 | |
128 | if (sem_init (sem: &sem, pshared: 0, INFLIGHT) != 0) |
129 | { |
130 | puts (s: "sem_init failed" ); |
131 | exit (1); |
132 | } |
133 | |
134 | pthread_attr_t a; |
135 | |
136 | if (pthread_attr_init (attr: &a) != 0) |
137 | { |
138 | puts (s: "attr_init failed" ); |
139 | exit (1); |
140 | } |
141 | |
142 | if (pthread_attr_setstacksize (attr: &a, stacksize: 1 * 1024 * 1024) != 0) |
143 | { |
144 | puts (s: "attr_setstacksize failed" ); |
145 | return 1; |
146 | } |
147 | |
148 | for (i = 0; i < N; ++i) |
149 | { |
150 | if (pthread_mutex_init (mutex: &lock[i], NULL) != 0) |
151 | { |
152 | printf (format: "mutex_init[%d] failed\n" , i); |
153 | } |
154 | |
155 | if (pthread_mutex_lock (mutex: &lock[i]) != 0) |
156 | { |
157 | printf (format: "mutex_lock[%d] failed\n" , i); |
158 | } |
159 | |
160 | if (pthread_create (newthread: &th[i], attr: &a, start_routine: tf, arg: (void *) (long int) i) != 0) |
161 | { |
162 | printf (format: "create of thread %d failed\n" , i); |
163 | exit (1); |
164 | } |
165 | } |
166 | |
167 | if (pthread_attr_destroy (attr: &a) != 0) |
168 | { |
169 | puts (s: "attr_destroy failed" ); |
170 | exit (1); |
171 | } |
172 | |
173 | int result = 0; |
174 | unsigned int r = 42; |
175 | pid_t pid = getpid (); |
176 | |
177 | for (i = 0; i < ROUNDS; ++i) |
178 | { |
179 | if (TEMP_FAILURE_RETRY (sem_wait (&sem)) != 0) |
180 | { |
181 | printf (format: "sem_wait round %d failed: %m\n" , i); |
182 | exit (1); |
183 | } |
184 | |
185 | int s = rand_r (seed: &r) % N; |
186 | |
187 | kill (pid: pid, sig: sig0 + s); |
188 | } |
189 | |
190 | void *status; |
191 | for (i = 0; i < N; ++i) |
192 | { |
193 | if (pthread_mutex_unlock (mutex: &lock[i]) != 0) |
194 | { |
195 | printf (format: "unlock %d failed\n" , i); |
196 | exit (1); |
197 | } |
198 | |
199 | if (pthread_join (th: th[i], thread_return: &status) != 0) |
200 | { |
201 | printf (format: "join %d failed\n" , i); |
202 | result = 1; |
203 | } |
204 | else if (status != NULL) |
205 | { |
206 | printf (format: "%d: result != NULL\n" , i); |
207 | result = 1; |
208 | } |
209 | } |
210 | |
211 | int total = 0; |
212 | for (i = 0; i < N; ++i) |
213 | { |
214 | int j; |
215 | |
216 | for (j = 0; j <= i; ++j) |
217 | total += received[i][j]; |
218 | |
219 | for (j = i + 1; j < N; ++j) |
220 | if (received[i][j] != 0) |
221 | { |
222 | printf (format: "thread %d received signal SIGRTMIN+%d\n" , i, j); |
223 | result = 1; |
224 | } |
225 | } |
226 | |
227 | if (total != ROUNDS) |
228 | { |
229 | printf (format: "total number of handled signals is %d, expected %d\n" , |
230 | total, ROUNDS); |
231 | result = 1; |
232 | } |
233 | |
234 | printf (format: "A total of %d signals sent and received\n" , total); |
235 | for (i = 0; i < N; ++i) |
236 | { |
237 | printf (format: "thread %2d:" , i); |
238 | |
239 | int j; |
240 | for (j = 0; j <= i; ++j) |
241 | { |
242 | printf (format: " %5d" , received[i][j]); |
243 | nsig[j] += received[i][j]; |
244 | } |
245 | |
246 | putchar (c: '\n'); |
247 | |
248 | } |
249 | |
250 | printf (format: "\nTotal :" ); |
251 | for (i = 0; i < N; ++i) |
252 | printf (format: " %5d" , nsig[i]); |
253 | putchar (c: '\n'); |
254 | |
255 | return result; |
256 | } |
257 | |
258 | # define TEST_FUNCTION do_test () |
259 | |
260 | #else |
261 | # define TEST_FUNCTION 0 |
262 | #endif |
263 | |
264 | #include "../test-skeleton.c" |
265 | |