]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/testsuite/gdb.threads/interrupted-hand-call.c
c1b0d02e19e4170e49c1c1bc84dde56cf2a8ee73
[thirdparty/binutils-gdb.git] / gdb / testsuite / gdb.threads / interrupted-hand-call.c
1 /* Test case for hand function calls interrupted by a signal in another thread.
2
3 Copyright 2008-2017 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20 #include <pthread.h>
21 #include <signal.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <time.h>
25 #include <unistd.h>
26
27 #ifndef NR_THREADS
28 #define NR_THREADS 4
29 #endif
30
31 pthread_t threads[NR_THREADS];
32
33 /* Number of threads currently running. */
34 int thread_count;
35
36 pthread_mutex_t thread_count_mutex;
37
38 pthread_cond_t thread_count_condvar;
39
40 sig_atomic_t sigabrt_received;
41
42 void
43 incr_thread_count (void)
44 {
45 pthread_mutex_lock (&thread_count_mutex);
46 ++thread_count;
47 if (thread_count == NR_THREADS)
48 pthread_cond_signal (&thread_count_condvar);
49 pthread_mutex_unlock (&thread_count_mutex);
50 }
51
52 void
53 cond_wait (pthread_cond_t *cond, pthread_mutex_t *mut)
54 {
55 pthread_mutex_lock (mut);
56 pthread_cond_wait (cond, mut);
57 pthread_mutex_unlock (mut);
58 }
59
60 void
61 noreturn (void)
62 {
63 pthread_mutex_t mut;
64 pthread_cond_t cond;
65
66 pthread_mutex_init (&mut, NULL);
67 pthread_cond_init (&cond, NULL);
68
69 /* Wait for a condition that will never be signaled, so we effectively
70 block the thread here. */
71 cond_wait (&cond, &mut);
72 }
73
74 void *
75 thread_entry (void *unused)
76 {
77 incr_thread_count ();
78 noreturn ();
79 }
80
81 void
82 sigabrt_handler (int signo)
83 {
84 sigabrt_received = 1;
85 }
86
87 /* Helper to test a hand-call being "interrupted" by a signal on another
88 thread. */
89
90 void
91 hand_call_with_signal (void)
92 {
93 const struct timespec ts = { 0, 10000000 }; /* 0.01 sec */
94
95 sigabrt_received = 0;
96 pthread_kill (threads[0], SIGABRT);
97 while (! sigabrt_received)
98 nanosleep (&ts, NULL);
99 }
100
101 /* Wait until all threads are running. */
102
103 void
104 wait_all_threads_running (void)
105 {
106 pthread_mutex_lock (&thread_count_mutex);
107 if (thread_count == NR_THREADS)
108 {
109 pthread_mutex_unlock (&thread_count_mutex);
110 return;
111 }
112 pthread_cond_wait (&thread_count_condvar, &thread_count_mutex);
113 if (thread_count == NR_THREADS)
114 {
115 pthread_mutex_unlock (&thread_count_mutex);
116 return;
117 }
118 pthread_mutex_unlock (&thread_count_mutex);
119 printf ("failed waiting for all threads to start\n");
120 abort ();
121 }
122
123 /* Called when all threads are running.
124 Easy place for a breakpoint. */
125
126 void
127 all_threads_running (void)
128 {
129 }
130
131 int
132 main (void)
133 {
134 int i;
135
136 signal (SIGABRT, sigabrt_handler);
137
138 pthread_mutex_init (&thread_count_mutex, NULL);
139 pthread_cond_init (&thread_count_condvar, NULL);
140
141 for (i = 0; i < NR_THREADS; ++i)
142 pthread_create (&threads[i], NULL, thread_entry, NULL);
143
144 wait_all_threads_running ();
145 all_threads_running ();
146
147 return 0;
148 }
149