1 /* Test that pthread_kill succeeds during thread exit.
2    Copyright (C) 2021 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 /* This test verifies that pthread_kill for a thread that is exiting
20    succeeds (with or without actually delivering the signal).  */
21 
22 #include <array_length.h>
23 #include <stdbool.h>
24 #include <stddef.h>
25 #include <support/xsignal.h>
26 #include <support/xthread.h>
27 #include <unistd.h>
28 
29 /* Set to true by timeout_thread_function when the test should
30    terminate.  */
31 static bool timeout;
32 
33 static void *
timeout_thread_function(void * unused)34 timeout_thread_function (void *unused)
35 {
36   usleep (1000 * 1000);
37   __atomic_store_n (&timeout, true, __ATOMIC_RELAXED);
38   return NULL;
39 }
40 
41 /* Used to synchronize the sending threads with the target thread and
42    main thread.  */
43 static pthread_barrier_t barrier_1;
44 static pthread_barrier_t barrier_2;
45 
46 /* The target thread to which signals are to be sent.  */
47 static pthread_t target_thread;
48 
49 /* Set by the main thread to true after timeout has been set to
50    true.  */
51 static bool exiting;
52 
53 static void *
sender_thread_function(void * unused)54 sender_thread_function (void *unused)
55 {
56   while (true)
57     {
58       /* Wait until target_thread has been initialized.  The target
59          thread and main thread participate in this barrier.  */
60       xpthread_barrier_wait (&barrier_1);
61 
62       if (exiting)
63         break;
64 
65       xpthread_kill (target_thread, SIGUSR1);
66 
67       /* Communicate that the signal has been sent.  The main thread
68          participates in this barrier.  */
69       xpthread_barrier_wait (&barrier_2);
70     }
71   return NULL;
72 }
73 
74 static void *
target_thread_function(void * unused)75 target_thread_function (void *unused)
76 {
77   target_thread = pthread_self ();
78   xpthread_barrier_wait (&barrier_1);
79   return NULL;
80 }
81 
82 static int
do_test(void)83 do_test (void)
84 {
85   xsignal (SIGUSR1, SIG_IGN);
86 
87   pthread_t thr_timeout = xpthread_create (NULL, timeout_thread_function, NULL);
88 
89   pthread_t threads[4];
90   xpthread_barrier_init (&barrier_1, NULL, array_length (threads) + 2);
91   xpthread_barrier_init (&barrier_2, NULL, array_length (threads) + 1);
92 
93   for (int i = 0; i < array_length (threads); ++i)
94     threads[i] = xpthread_create (NULL, sender_thread_function, NULL);
95 
96   while (!__atomic_load_n (&timeout, __ATOMIC_RELAXED))
97     {
98       xpthread_create (NULL, target_thread_function, NULL);
99 
100       /* Wait for the target thread to be set up and signal sending to
101          start.  */
102       xpthread_barrier_wait (&barrier_1);
103 
104       /* Wait for signal sending to complete.  */
105       xpthread_barrier_wait (&barrier_2);
106 
107       xpthread_join (target_thread);
108     }
109 
110   exiting = true;
111 
112   /* Signal the sending threads to exit.  */
113   xpthread_create (NULL, target_thread_function, NULL);
114   xpthread_barrier_wait (&barrier_1);
115 
116   for (int i = 0; i < array_length (threads); ++i)
117     xpthread_join (threads[i]);
118   xpthread_join (thr_timeout);
119 
120   return 0;
121 }
122 
123 #include <support/test-driver.c>
124